x86 MBR

看过《x86汇编语言–从实模式到保护模式》或者《操作系统–真象还原》等涉及x86系统的书,都会知道,x86计算机的启动流程会把启动盘第一个sector复制到0x7c00处,然后跳转到0x7c00处执行。

加载MBR流程如下,

  1. 检测启动盘第一个sector最后两个字节是否为0x55, 0xaa
  2. 复制第一个sector到内存0x7c00
  3. 跳转到0x7c00处执行

(这流程省了很多支线,别在意)


实例代码

例如,

mov al, 'Y'
mov ah, 0x0e
mov bx, 0x7
int 0x10
finish:
        hlt
        jmp finish

times 510-($-$$) db 0

db 0x55, 0xaa

上面的代码编译后,把bin文件复制(刻录?写入?)到虚拟机硬盘文件的第一个sector就可以在虚拟机开机后,看到虚拟机屏幕上有个Y。


真机运行

大多的书上,都会教大家用bochs运行调试自己写的MBR。大概就像上面说的那样,把bin文件复制到img文件上,然后启动bochs。(用多了就不过瘾了)

那么大家有没有想过在真机上运行一下自己写的东东呢?我敢肯定,对操作系统有兴趣的人肯定有想过,也有人试过,嘻嘻。(如果没想过,就不会看自己动手写操作系统之类的书籍,对不对?)

《30天自制操作系统》就是一个没推荐用虚拟机的“另类”。它一开始就叫读者把MBR写入软盘,然后软盘启动开机。

但是呢!软盘,好远古的东东,现在大多数人都不会用了吧。(我也没用)
那能不能用“正常”一点的方法?

现在我们多数用硬盘或者U盘开机。硬盘就不用说了,和虚机硬盘文件一样,把MBR写入到硬盘的第一个sector中,然后开机就可以了。至于U盘,今天的主角,就要慢慢细说分享了。


U盘启动

刚自己写操作系统时,我手头上就只有一部三星的笔记本,没有其他电脑。我试着把我写的MBR复制到U盘的第一个分区,然后把手提关机,并设置“U盘,硬盘”的顺序开机,然而重启了很多次,都是直接启动硬盘上的windows,并没有识别U盘上的MBR。

我确认过U盘的第一个sector最后为0x55,0xaa。我怀疑过是不是U盘启动和硬盘,软盘不一样?毕竟U盘没有磁头之类的架构。

之后,我找了另一部计算机,台式来的。试试我写的U盘引导行不行,谁知在我的笔记本上重启多次没成功加载的U盘MBR,竟然在台式成功了。那么证明了U盘启动,bios也是把U盘的第一个sector加载到0x7c00然后跳转执行。


笔记本U盘MBR

既然台式机可以识别出U盘上的MBR(我写的),为什么我的笔记本就不行呢!?
难道笔记本U盘启动有特别之处?或者说bios服务调用(int)不一样?
就上面贴出的MBR代码,

mov al, 'Y'
mov ah, 0x0e
mov bx, 0x7
int 0x10
finish:
        hlt
        jmp finish

times 510-($-$$) db 0

db 0x55, 0xaa

我在台式机,是可以用U盘启动上面代码的,在屏幕上显示‘Y’。
而我的笔记本上却说没找到可引导介质。(我把硬盘启动关了,就剩下U盘启动)

经过反汇编安装win10的U盘MBR,和多次测试后,发现我的笔记本bios检测启动盘时,会检测活动分区标志。(至于什么是活动分区标志,可以百度MBR结构)

所以上面代码要修改一下,

mov al, 'Y'
mov ah, 0x0e
mov bx, 0x7
int 0x10
finish:
        hlt
        jmp finish

times 446-($-$$) db 0

active_flag db 0x80 ;<-活动分区标志

times 510-($-$$) db 0

db 0x55, 0xaa

猜想,或许笔记本为了保护好自身硬件和成功启动系统,所以除了检测后面的0x55,0xaa,还会检测是否存在活动分区。


(我只在我自己的三星笔记本上测试过,可能其他笔记本会“正常”点。如果遇到相同问题,可以参考上面,试试加上活动分区标志)