好了,下面开始分析boot.bin了,放置在软盘的前512字节中。
如何判断一个软盘是引导软盘呢? 这个任务是交给在BIOS的。
BIOS会读取软盘的前512字节,如果第511个,512个字节的内容为0x55AA,就认定这是个引导软盘,将这512字节放置在内存0x7c00处,并跳转执行。
boot的目的我前一节说过了,就是查找KERNEL.SYS所在软盘位置,将其读到内存中,并跳转执行。
下面是详细细节:
BIOS执行时,设置好了中断向量,boot执行前,内存分布如下: ; | ROM | ; | BIOS | 0xE000:0000 ; | | ; | | ; | VGA | ; | BIOS | 0xC000:0000 ; | | ; | | ; | | ; | | ; | | ; | | ; |--------| ; |BOOT SEC| ; |ORIGIN | 07C0:0000 ; |--------| ; | | ; |--------| 0x40:0000 ; |中断向量| ; |_______ | 0x0:0000
boot会先将自己copy到内存1FE0:7c00处, 0x1FE00+0x7C00=0x27a00 = 158.5K, 即内存偏移158.5K处。
执行完后,内存分布如下:
; |--------| 2000:0000 ; |BOOT SEC| ; |RELOCATE| ; |--------| 1FE0:0000 ; | | ; | | ; |--------| ; |BOOT SEC| ; |ORIGIN | 07C0:0000 ; |--------| ; | | ; |--------| 0x40:0000 ; |中断向量| ; |_______ | 0x0:0000
然后如下操作, retf执行后CS=0x1FE0, IP=cont偏移地址,所以下面CPU就在copy过去的boot.bin中执行了
也就是说0x7C00那块的512字节内存已经没有”利用价值了”。
疑问:boot为什么要将自己挪到断地址为1FE0处?先算下0000:7C00所在的内存偏移:0+0x7C00 = 31KB, 0x7C00之前只有31K的可用内存空间。 boot的目的就是将KERNEL.SYS载入内存,而KERNEL.SYS一般比较大,这个版本的大小约为77KB, 如果从内存开始的地方就放置KERNEL,0x7C00处会被覆盖掉,那boot还怎么执行啊? 所以boot先要将自己挪到内存高处,方便加载KERNEL。 但是目的段不一定必须为1FE0,将其改为3BC0,重新编译运行,也是可以正常加载KERNEL的,可以试试。
剩下的就是读盘,因软盘系统为FAT12格式,所以要找到KERNEL.SYS文件,如前一节所述,要有一段的逻辑代码,先弄懂FAT12格式,再看汇编代码就容易了。
将KERNEL.SYS放到偏移0x60:0000处,然后来个跳转到执行KERNEL代码。
疑问:为什么要将KERNEL放到0x600处?0-0x3FF存放的是中断向量。 0x400-0x5FF 存放BIOS的数据,如当前时间等。 即前面的内容都被占用了,所以KERNEL只能放置在偏移0x600往后的空间了。 在KERNEL执行之前的内容分布如下: ; | ROM | ; | BIOS | 0xE000:0000 ; | | ; | | ; | VGA | ; | BIOS | 0xC000:0000 ; | | ; | | ; | | ; | | ; | | ; | | ; |--------| ; |KERNEL | ; |LOADED | ; |--------| 0060:0000 ; | | ; |--------| 0x40:0000 ; |中断向量| ; |_______ | 0x0:0000