前言
一直想着要多了解一下操作系统但是由于各种原因一直拖, 来英国这段时间发生了很多事, 眨眼半年过去了, 博客也没更新几篇, 之前看现在也没什么心思看了. 这几天一直在看操作系统, 想想看操作系统这一块一直都是自己比较好奇但又不是很了解的一块, 想着这里概念也挺多的, 就准备搞出这一系列, 也算是做做笔记, 方便以后复习整理.
计算机的启动过程
关于这个部分我个人也是参考了这个这篇文章, 然后结合一些书籍谈一下个人理解吧. 这一块首先是写在ROM芯片里面的程序BIOS(Basic Input/Output System), 正常情况下按下电源键之后, BIOS程序启动, 他的任务按照执行顺序主要是下面几个 :
- POST (Power-On Self-Test) : 主要是检查各种计算机硬件, 此时如果一切正常屏幕上打印CPU, 硬盘, 内存等各种硬件信息, 否则计算机蜂鸣并停止启动.
- 接下来BIOS会主动寻找下一阶段的启动程序, 该启动程序可能存在于CD/DVD等存储设备, BIOS会依次检查, 具体设备检查的先后可以在BIOS中进行设置. 判断方式也比较简单, 如果该设备的第一个扇区(512bytes)的最后两个字节是0x55和0xAA, 表明这个设备可以用于启动, 这也就是我们通常所说的引导扇区, 否则继续检查下一个设备.
- 然后被找到的引导扇区将被加载到内存中的0000:7c00处(现在还是实模式).
然后控制权限交给了被加载的引导扇区中的代码, 这512字节也被称之为MBR(master boot record). MBR也分三部分 :
- 第1-446字节:调用操作系统的机器码 .
- 第447-510字节:分区表(Partition table) .
- 第511-512字节:主引导记录签名(0x55和0xAA) .
分区表什么的这里不提, 具体可以看上面提到的那篇文章. 这一部分暂时只需要提这么多就足够了. 那么如果要编写操作系统, 就必须从引导扇区开始写, 这一块当时是用汇编代码, 市面上大多数将编写操作系统的书籍都无一例外地使用的汇编器nasm, 它所支持的汇编格式是Intel格式的汇编, 和AT&T汇编(gcc那一套)有一定的区别, 具体可以看我之前写过的文章, 另外这里还需要掌握一些nasm的基本语法, 这个我主要是参考这篇文章, 讲的还是比较详细的.
下面我从书中截取了一个引导扇区的源代码, 可以感受一下 :
org 07c00h ; 告诉编译器程序加载到7c00处 ;@接下来的三行用来初始化段寄存器 mov ax, cs mov ds, ax mov es, ax call DispStr ; 调用显示字符串例程 jmp $ ; 无限循环 ;@该函数主要用于负责打印, 当前阶段看不懂可以忽略.DispStr: mov ax, BootMessage mov bp, ax ; ES:BP = 串地址 mov cx, 16 ; CX = 串长度 mov ax, 01301h ; AH = 13, AL = 01h mov bx, 000ch ; 页号为0(BH = 0) 黑底红字(BL = 0Ch,高亮) mov dl, 0 int 10h ; 10h 号中断 retBootMessage: db "Hello, OS world!" ;@这里我感觉应该是 510 - ($ - $$ + 1) 才对times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为512字节dw 0xaa55 ; 结束标志
所有前面加过@的注释都是我写的.
那么来讲一下如何把这段代码运行起来 :
工具很简单 :
- nasm 汇编器, 主要用于把汇编语言编译成elf格式的可执行文件.
- linux指令dd, 主要用于将编译完成的可执行文件转移到虚拟软盘中.
- qemu 虚拟机, 主要用于模拟计算机的运行, 可以执行我们制作的软盘镜像.
这里只需要即可, 需要注意的是第二行中制作出来的img格式的虚拟光盘之中并没有文件系统, 所以不能直接被mount到linux上. 所以想使用mount挂载到linux上在进行复制是行不通的.
nasm xxx.asm -o bootdd if=boot of=fred.img bs=512 count=1qemu fred.img
一些疑问
从上述过程中了解到, MBR被加载到07C00位置是作为一种BIOS的默认行为, 既然这样的话为什么我们需要显示地声明org 07c00h
呢? 我尝试着做了如下工作 :
- 修改上述代码, 只留下最后两行, 也就是只是指定最后两个字节为0xAA55, 这样事实上仍然能够被操作系统识别为引导扇区.
- 修改上述代码, 除掉/更改 第一行, 能够别识别为引导扇区但是输出异常.
- 除去所有代码, 无法识别.
这里可以肯定的是, 决定是否是引导扇区完全了07C00无关, 只要扇区末尾是0Xaa55即可. 那么为什么不加org 07coo
就不行呢? 最终看完这篇文章我才算理解, 就是说这一行的作用在于表明所有数据的偏移量, 因为正常的操作系统中, 由于虚拟内存的存在(而不是物理内存), 每个程序看到的其实内存地址都是0, 所以编译器并不需要为代码中每个地址添加偏移量. 而这里是BIOS强行将这段代码添加到了物理内存的07C00, 这时候如果不添加第一行, 编译器并不知道这一点, 所以会出现输出异常, 为了验证我的理解, 我将07C00改成了07C01, 输出果然变成了ello, OS world! "
.