加载BIOS
当PC的电源打开后, 80x86结构的CPU将自动进入实模式.并且CPU的 cs:ip 寄存器被强制初始化为 0xF000 : 0xFFF0.
先抛出来个问题, 为什么 cs:ip 寄存器会被初始化为0xF000 : 0xFFF0 ?
继续往后看,当主机加电后,第一个运行的软件是BIOS,但是此时由于计算机刚加电,内存里还没有数据,所以BIOS并不是放在内存中的,而是放在ROM(只读存储器).而BIOS由硬件来加载,被加载到 0xF0000~0xFFFFF处.
上面提到过,cs:ip被初始化为0xF000 : 0xFFF0,即指向0xFFFF0这个地址,也就是说,当加电后计算机执行的第一条指令的地址为0xFFFF0.但是实模式下只能访问1MB内存,此时距离1MB内存就剩下16字节, 这16字节的内容是什么呢? jmp f000: e05b 是一个跳转指令,跳转到BIOS的加载地址去执行BIOS程序.
BIOS的作用
主要是进行硬件的诊断、检测和初始化。比如检测内存、显卡等外设信息, 初始化硬件等。 然后在内存中 0x000~0x3FF出建立数据建构, 中断向量表IVT并填写中断例程。最后一项工作: 校验启动盘中位于0盘0道1扇区中的内容。
BIOS->MBR
为什么BIOS的最后一项工作是校验启动盘中位于0盘0道1扇区中的内容呢?
emmm,可以说是约定吧。其实接下来,是要开始加载MBR了,MBR在那个扇区都可以,不一定非要在第一个扇区。 但是如果没有约定,BIOS需要检查电脑中的所有存储设备,去判断它这个扇区是不是存在可执行的程序。所以有了这个约定。
那么,BIOS怎样判断这个扇区是否有可执行程序呢? —魔术0x55,0xaa。
BIOS每次只检查一个扇区的最后两个字节, 如果最后两个字节是 0x55,0xaa, 那么BIOS就认为这个扇区中存在可执行程序。(这个可执行程序就是 MBR)。
如果最后两个字节不是 0x55,0xaa, 即使这个扇区中真的有可执行程序,BIOS也不会加载它的。 如果BIOS认为这个扇区中有可执行程序, 就将这个扇区中的内容加载到 物理地址 0x7c00。然后跳转到这个地址开始执行。
所以,由于扇区的最后两个字节必须是 0x55,0xaa。 这就限制了MBR的大小必须是 512字节。
加载的地址为什么是0x7c00 ?
按 DOS 1.0 要求的最小内存 32KB 来说, MBR 希望给人家尽可能多的预留空间,这样也是保全自己的作法,免得过早被覆盖。所以 MBR 只能放在 32KB 的末尾。
MBR 本身也是程序,是程序就要用到栈,栈也是在内存中的, MBR 虽然本身只有 512 字节,但还要为其所用的栈分配点空间,所以其实际所用的内存空间要大于 512 字节,估计 1KB 内存够用了。
结合以上三点,选择 32KB中的最后 1KB最为合适,那此地址是多少呢? 32KB换算为十六进制为 0x8000,减去 1KB(0x400)的话,等于 0x7c00。这就是倍受质疑的 0x7c00 的由来,这下清楚了。
可见,加载 MBR 的位置取决于操作系统本身所占内存大小和内存布局
MBR的作用
每种操作系统的启动引导程序都是不同的, 但是大概功能都是相同的即加载操作系统的内核。
比如在我自己了解到的一个操作系统中,MBR里面就没有什么重要的功能,最重要的就是从硬盘上加载另一个程序加载器,由这个程序去执行一些初始化内核环境、加载内核的操作。
为什么要多此一举呢?为什么不能在mbr中加载内核呢?
还是开始的原因,MBR只能是512个字节, 这个空间有点小,没有办法完成初始化环境和加载内核的任务。
加载器的作用
加载器是从MBR跳转过来的, 它的主要任务就是为内核初始化环境和加载内核。在此之前的程序都是在实模式下运行的。
而内核是运行在保护模式下的。 所以加载器也算是从实模式向保护模式过渡。