1.什么是MBR

  说实话,我一直都不喜欢在一大堆内容一开始就抛出一长条概念,这很劝退,但现在记录一下是很有必要的,否则后续忘记就难理解了。

  简单来讲,MBR记录着硬盘各个分区的大小和位置信息,就像人口普查一样,对整个硬盘的分布了熟于心。它是开机后访问硬盘时要读取的第一个扇区,不难理解,毕竟要知道自己去哪得先看地图。噢,对了,它的全称是主引导记录(master boot record),由于os需要一步步进行权限的完善,有程序进行接力和指引是必须的事情。

2. 0x7c00?why?

  好吧,这个问题我也一直都很好奇,在进行6.s081实验时,取断点并跳转总是从0x7c00开始,搜了很多操作系统有关的文章都没有给我一个满意的答案,现在算是知道了:

  早期的CPU要求物理地址 0x0~0x3FF 存放中断向量表(我还不知道这是什么意思),所以只能找其他地方放MBR了,在那时DOS(古老的系统)要求最小内存是32KB,但是MBR自然不可能覆盖在前面或中间(不然其他功能去哪开始加载,无序会导致混乱和时间变长),所以它必须预留空间,所以就得在32KB的末尾。

  写程序的大家都知道,程序必须要用到栈,MBR虽说是汇编语言但也是一段程序,它在内存里由于要给栈分配空间实际上总空间要大于512字节,最大估计也就1KB了(毕竟功能就那点),所以选32KB中最后1KB最合适,而那个地方就是0x7c00。

3.启动MBR的坎坷风雪路

  首先是简单的MBR代码:

 1 ;主引导程序 2 ;--------------------- 3  4 SECTION MBR vstart=0x7c00 ;程序开始的地址 5     mov ax, cs            ;使用cs初始化其他的寄存器 6     mov ds, ax            ;因为是通过jmp 0:0x7c00到的MBR开始地址 7     mov es, ax            ;所以此时的cs为0,也就是用0初始化其他寄存器 8     mov ss, ax            ;此类的寄存器不同通过立即数赋值,采用ax中转 9     mov fs, ax10     mov sp, 0x7c00  ;初始化栈指针11 12 ;清屏利用0x10中断的0x6号功能13 ;------------------------14     mov ax, 0x60015     mov bx, 0x70016     mov cx, 017     mov dx, 0x184f18 19     int 0x1020     ;获取光标位置21 ;---------------------22     mov ah, 3   ; 3号子功能获取光标位置23     mov bh, 1   ; bh寄存器存储带获取光标位置的页号,从0开始,此处填1可以看成将光标移动到最开始24     int 0x1025 26 ;打印字符串27 ;------------------28     mov ax, message29     mov bp, ax30 31     mov cx, 6    ;字符串长度,不包括'\0'32     mov ax, 0x130133     mov bx, 0x234 35     int 0x1036 37     jmp $38 39     message db "My MBR"40     times 510-($-$$) db 0 41     db 0x55, 0xaa

注释都说的很清楚,显示器相关就不提了,主要写写第24行0x10中断和37、40、41行。

0x10中断在这里负责有关打印的例程。调用方法是将功能号送入ah寄存器,其他参数按照中断要求放在适当寄存器,然后执行int 0x10,具体了解在这贴个链接:(3条消息) BIOS INT 10中断功能详解_bios显示模式 int10_rhxznp的博客-CSDN博客

37行是一个死循环,$是本行指令的地址,jmp是近跳转,那么jmp $就是跳到自己的地址再执行自己,再跳到自己的地址再跳转,这样是为了让程序悬停在此处,等待下一步。

40行的$$是本section的起始地址,和上面$区别还是很大的,section起始地址和行起始地址并不是一个东西。$-$$是本行到本section的偏移量,MBR的最后两个字节必须是固定的内容,也就是BIOS认为可执行的程序MBR啦!如果不是,OK,BIOS不认识,无法启动。

那么一串times 和 – 号、db是什么意思?因为要预留出0x55,0xaa,所以得要计算填满扇区用的字节数,MBR共有512字节,那么510个字节就得填充,但是扇区里还有其他东西加载,所以用510-($-$$)得到剩余量,然后用0填充,这样预留的两字节就能确保了。

也就是说,到这里程序加载的顺序是BIOS -> 跳转0x7c00 -> 跳转0x55,0xaa.

接下来是最艰难的启动之路!

  利用dd和nasm分别写入和编译MBR,这个没问题,注意路径就行,主要是启动bochs时,错误主要有三个(反反复复!):

  1. 这个每次启动都会弹出,真的很鸡肋!通过查阅发现img.lock删除后重启就行,还是不行命令加个sudo也可以。

  2. sector size of 0 is in error. 措施:中文意思是扇区大小0出错,我怀疑是我硬盘没有建立,或者建立了系统没反应,所以重新又建立了一次,解决了问题。
  3. NO bootable device. 措施:一开始我很困惑,明明我dd也nasm了怎么不认呢?原来是第二个错误的连锁反应,建立硬盘后再dd nasm一次就能识别MBR了。

  虽说就三个错误,折腾了我大半天时间,一些文章也没有我的错误,反反复复重启删除,最后终于出现在bochs的图让我成就感满满,附个胜利图:

呃,别问我为什么和上面的程序显示不一样,为了解释重点的MBR结构,我搜索了这个比较简单的程序,但图中的这个是《操作系统真象还原》里的完整代码运行出的结果,所以不一样。

  OK!总算是写完初认识啦!我只是个小菜鸡,一些认识肯定是浅显或有些不准确的,后面会随着OS的完善逐步深入,感谢浏览!