【操作系统】启动篇

摘要:对于编程路上各个阶段的人来说,操作系统无疑都是神秘而富有吸引力的。我们所看到的操作系统就像一座冰山,冰山之下的秘密令人向往而畏惧。不知你是否曾经也幻想过写一个操作系统,却苦于不知如何开始,或者因为畏惧而不敢开始。而我要告诉你的是,从零开始写一个操作系统并不是一件特别难的事情,本系列文章将带你走进操作系统这个神秘的世界。

风起于青萍之末

操作系统本质上来说也只是一段程序而已,或则说,它是一堆二进制指令,也就是机器码。那么计算机开机后,操作系统是如何开始运行的呢?

这里我们要先从CPU说起,CPU是个傻蛋,它只会一条接着一条的从内存中取出指令,然后执行。至于从哪里取出指令,取决于IP寄存器的值。事实上,操作系统并不是计算机运行的第一个程序。计算机通电之后执行的第一个程序是BIOS(Basic Input Output Software),它是一段固化到计算机主板上一个ROM芯片中的程序。我们常说的开机自检,就是这段程序做的事情。

关于BIOS的全称,我在一份英文资料中看到的是Basic Input Output Software,而国内的资料大多解释为Basic Input Output System。虽然从理解不至于引起歧义,但是我认为Software更能体现它是一段程序的事实。

BIOS在做完硬件检查后,会依次读取连接到计算机的存储设备(硬盘,软盘,光盘等)的第一个扇区(512字节),注意不是读内存,后面为了叙述方便,我会把这些存储设备简述为磁盘。同时,BIOS会判断第一个扇区是不是启动扇区,如果是的话,它会把这个扇区加载到内存的0x7c000x7dff处。

我知道读完上面这段话你一定充满了疑惑,我准备了3个问题,在读完问题之后,你可以停下来思考一下,然后再继续阅读。

问题1:为什么BIOS只读第一个扇区?

其实BIOS也不知道操作系统究竟在磁盘的什么位置,既然不知道,那么最简单稳妥的方式就是放到最开头的位置。这是符合直觉和逻辑的,没什么特殊的原因,它就是这样设计和实现的。注意此时还没有文件的概念,因为文件和文件系统都是操作系统提供的抽象,不要忘了,现在还没有操作系统呢。所以,BIOS看到的磁盘就是一个个扇区。为什么不是读两个扇区呢?因为BIOS也不知道操作系统有多大。那如果操作系统不止512字节呢?这个问题需要我们自己解决,利用启动扇区的程序把真正的操作系统加载到内存,后面我们会看到如何做到这一点。

问题2:如何判断是不是启动扇区?

这个问题也很简单,我们只需要给启动扇区做一个标记就行了。如果BIOS发现启动扇区最后两个字节是0x550xaa,就会认为这是一个启动扇区。把它看作一个int16就是0xaa55,十进制是43605。不要觉得写反了,因为x86是小端序,所以0xaa55写到内存就是0x550xaa。为什么选这样一个数字也没有什么道理,也许是因为它的二进制是1和0的交替排列,也可能就是拍脑袋想出来的,这里我们就不追查它的历史原因了,总之就是这样规定的。

问题3:引导扇区为什么是加载到内存的0x7c00处?

依然是没什么道理的,因为一开始就加载到了这个地方,后来大家都遵循了这一规定,于是就流传下来了。也许有它的历史原因,这里我们就不追查了

好家伙,就是这样的没有道理,就是这样规定的,我们也只能遵守了。当然如果你能自己搞一套硬件的话这些也是完全可以改的。

当BIOS把启动盘的第一个扇区加载到内存后,会让CPU从0x7c00处开始执行指令,至此,我们就掌握了对计算机的控制权,操作系统也正是从这里开始登上舞台的。

除此之外,BIOS还提供了许多有用的中断函数,是我们在真正的操作系统启动前的编程利器。顾名思义,它提供了基本的IO功能,最基本的,或者说至少有磁盘,键盘和屏幕IO。

这就是操作系统的启动过程,接下来该动手实验了。

环境搭建

QEMU

QEMU是一个计算机模拟软件,可以模拟整个计算机,是一个免费开源的软件,大家可以自行去官网下载最新版本安装,安装过程没什么特别的地方,只需要选一些安装路径就行了。下面是官网地址:

https://www.qemu.org/

QEMU默认不会添加到path,为了使用方便,需要自己去添加。

NASM

NASM是我们将要用到的汇编工具,不用安装,直接解压就可以使用,包括它的文档,大家都可以在官网下载,官网地址如下:

https://www.nasm.us/

nasm也需要手动添加到path。

制作启动扇区

我们使用nasm来制作一个最简单的启动扇区,新建boot_sect.asm,并输入以下内容。

; 启动扇区
org 0x7c00             ; 也可以写作 [org 0x7c00]

jmp $                  ; for {}

times 510+$$-$ db 0    ; 填充0直到第510字节
dw 0xaa55              ; 启动扇区标识

如果上面的代码阅读起来有困难,那么可以参考nasm的官方文档。即使现在对它不是很理解也没有关系,在后面的章节中,我们会逐渐理解它。这里主要是看看它编译之后的内容。

使用以下指令编译它。

nasm boot_sect.asm -f bin -o boot_sect.bin -l boot_sect.lst

它会输出两个文件,一个是boot_sect.bin,另一个是boot_sect.lst。前者是编译之后的二进制机器码,是可以直接被CPU执行的指令文件;后者是汇编代码和机器码的对照文件,打开这个文件,就会看到汇编代码是如何翻译成机器码的,没必要每次都输出这个文件,好奇的时候可以看一看。

00000000  EB FE 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000010  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
........  .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
000001F0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA

..表示省略的0,512字节毕竟还是有点多的。

前两个字节EB FE就是jmp $的机器码,注意最后两个字节,最然我们写入的是0xaa55,但由于x86是小端序,所以你看到的是55 AA

接下来我们使用Qemu来启动它。

qemu-system-x86_64 -drive file=boot_sect.bin,format=raw

不出意外的话,那就是没有意外,没有意外你就会看到下面这张图,这说明Qemu成功找到了启动扇区。下图显示我们的系统是从硬盘启动的,软盘启动的命令如下:

qemu-system-x86_64 -drive file=$<,index=0,if=floppy,format=raw

我们看到,机器指令并没有什么特殊,它们一条挨着一条放在磁盘上,那么CPU怎么知道这条指令到哪里结束,下一条指令从哪里开始呢?

x86架构使用的是变长指令集,CPU通过指令码来判断指令长度;ARM架构使用的是定长指令集,按固定的长度就可以分割出每一条指令。

BIOS完成引导扇区加载后,计算机内存布局如下图所示。

这个图是比较重要的,因为我们编写操作系统时无疑是要用到内存的,这张图可以告诉你哪些地方可用,哪些地方不能使用。

我们将会用到的命令都比较长,大家可以使用make工具来构建运行,这部分大家自行领悟吧。

总结

虽然这一节的内容很简单,但是我们已经完成了一个操作系统的0.5步。看吧,它其实一点也不难,我们的学习方向总是从一个很高的抽象层次开始往底层学习,但底层其实是非常简单的,反而是经过抽象的概念没有实物的对照,加上隐藏了太多细节,反而不容易理解。如果反过来沿着技术发展的方向,从底层向上层学习,由具象走到抽象,顺势而为可能会更容易。当你从具象走向抽象时,会发现它们的原理其实特别简单。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值