30天自制操作系统-day01

30天自制操作系统-day01

二月 08, 2022

前言

旧坑未填,又开新坑

好久没更新blog了,想开一个新坑,《30天自制操作系统》,相信不少人都听说过这本书,今天翻看了一下,发现挺有趣的,于是开始动手。

这一系列的文章并不会详细介绍相关知识,例如汇编、makefile等,只是介绍如何实现书中的操作过程

由于书是图书馆借的,没有光盘中的资料,于是一顿搜索,发现GitHub的这个仓库里有全套的源代码+中文注释。非常感谢这位老哥的帮助!

一翻书,发现作者使用的汇编器是自己写的(据说是认为nasm太慢),而且使用的操作系统和硬件(使用的是软盘)太古老了。

因此这里我使用的是:

编辑器:VSCode

汇编器:nasm

虚拟机:qemu

这些软件的安装我就不做说明了(记得都加入环境变量),注意VSCode里安装这些插件:Hex Editorx86 and x86_64 Assembly

手动打机器码

按照书里的步骤,我们先体验一下二进制打印一个Hello world

使用VSCode新建一个文件,命名boot.bin,使用Hex Editor打开(按快捷键Ctrl + Shift + P,输入hex就会出现使用十六进制打开)

除了下面几段外其他全是00,慢慢敲吧,如果想偷懒,可以去我的仓库下载这个文件(如果没有这个仓库说明我还在鸽,咕咕咕~~~)

国内经常打不开GitHub点击这里下载😀

第一段:

第一段

第二段

第二段

第三段

第三段

一直填充00到0x00167FF0那一行填满

然后我们就得到了一个可以成功引导的镜像文件啦

下面我们运行它

运行镜像

打开命令行,进入目录,简简单单,一行命令

1
qemu-system-i386 -drive format=raw,file=day1.bin

你因该能看到:

运行演示

可以看到,打开了一个窗口,运行了我们的Hello, world

完成这一步,我们到底做了什么呢?

我们用手动敲机器码的方式实现了一个小程序,实际中估计没有多少人这么做,毕竟及时是本书的作者也不太可能用手动写机器码的方式为我们提供了这段代码(考虑到这本书的作者写过汇编器,我还是加个“太”字吧。。。)

一般情况下,我们真正要做的事是写汇编代码,然后使用汇编器帮我们将汇编代码翻译成机器码,注意是“翻译”,不是“编译”,因为写汇编本质上还是在写机器指令,只包括稍微可读了一些。

使用汇编器

由于这本书第一天并没有介绍太多汇编指令,这里我们还是手写机器码,只不过不用按那么多00了,这一步由汇编器帮我们完成。

与上面的手动打机器码等效的汇编代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
; hello-os
; TAB=4

; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code

DB 0xeb, 0x4e, 0x90
DB "HELLOIPL" ; 启动扇区名称(8字节)
DW 512 ; 每个扇区(sector)大小(必须512字节)
DB 1 ; 簇(cluster)大小(必须为1个扇区)
DW 1 ; FAT起始位置(一般为第一个扇区)
DB 2 ; FAT个数(必须为2)
DW 224 ; 根目录大小(一般为224项)
DW 2880 ; 该磁盘大小(必须为2880扇区1440*1024/512)
DB 0xf0 ; 磁盘类型(必须为0xf0)
DW 9 ; FAT的长度(必须是9扇区)
DW 18 ; 一个磁道(track)有几个扇区(必须为18)
DW 2 ; 磁头数(必须是2)
DD 0 ; 不使用分区,必须是0
DD 2880 ; 重写一次磁盘大小
DB 0, 0, 0x29
DD 0xffffffff

DB "HELLO-OS " ; 磁盘的名称(必须为11字节,不足填空格)
DB "FAT12 " ; 磁盘格式名称(必须是8字节,不足填空格)
TIMES 18 DB 0 ; 先空出18字节

; 程序主体,这里依然是机器码

DB 0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c
DB 0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a
DB 0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09
DB 0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb
DB 0xee, 0xf4, 0xeb, 0xfd

; 信息显示部分

DB 0x0a, 0x0a ; 换行两次
DB "hello, world"
DB 0x0a ; 换行
DB 0

TIMES 0x1fe-($-$$) DB 0x00 ; 填写0x00直到0x001fe

DB 0x55, 0xaa

; 启动扇区以外部分输出

DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
TIMES 4600 DB 0
DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
TIMES 1469432 DB 0

注意,书中作者使用的是自己写的汇编器nask,由于找不到64位的程序,我使用的是nasm汇编器,所以语法有些变化,参照这篇文章

将文件复制并命名为boot.asm,不过我还是建议自己打一遍

使用如下命令汇编:

1
nasm -f bin boot.asm -o day1.bin

同样,使用qemu运行

1
qemu-system-i386 -drive format=raw,file=day1.bin

运行的结果应该是一样的,这里就不放图了,你可以用SHA1验证,生成的文件与之前手打的一模一样

1
certunit -hashfile SHA1 day1.bin

第一天结束

【完】