转载时请注明出处和作者联系方式作者联系方式:diablo_work at 126 dot com
最近看了看grub2的源码,现总结一下,方便其他人学习。
1.开机,bios读取MBR(硬盘中的0号扇区),放置MBR的内容到内存0:0x 7c 00处,然后将控制权转到内存0:0x 7c 00处。MBR中对应的代码为/boot/i386/pc/boot.S。boot.S的主要任务调入硬盘中的1号扇区(由变量kernel_sector指定)到内存0x7000:0处,然后调用copy_buffer,将内存0x7000:0的内容拷贝到内存0:0x8000处,copy的大小为一个扇区的大小(512字节),然后将控制权转到0: 0x8000处。以上的执行流程都是在实模式下进行的。
其中读取扇区的方法为:
判断硬盘是chs模式还是lba模式,通过调用Int 13/AH=41h;
如果是chs模式,则调用Int 13/AH=42h读取1号扇区的内容;
如果是lba模式,则调用Int 13/AH=2h读取1号扇区的内容;
关于bios调用,可以参考网站http://www.ctyme.com/rbrown.htm。内容很全,不过我一直都希望有一本类似的电子书(用起来方便),可惜没有找到。如果谁有,能否提供?
boot.S编译后生成boot.img,boot.img的大小为512字节,刚好是一个扇区的大小。boot.img将被放置在0号扇区。
一般的资料上说(最典型的莫过于Tanenbaum 写的<<Operating Systems Design and Implementation, Third Edition>>),MBR后面的64字节为硬盘分区表,但从boot.S的代码上看,似乎是没有硬盘分区表的,当然也不存在处理硬盘分区表的代码了。
2.此时,cpu执行1号扇区中的指令。1号扇区的内容对应/boot/i386/pc/diskboot.S。其主要功能是调入grub的kernel。Grub的Kernel(kernel.imag)应该是位于从2号扇区开始的、连续的几个扇区中的内容。由于diskboot.S中的代码不具备识别文件系统的功能(也不可能具备,因为太小了,才512个字节),因此kernel.imag是不能以文件的方式进行保存的,必须“原模原样”写到连续的几个扇区中。
在网上查了一些资料,0道0面的全部扇区都为隐含扇区,是不进入任何一个磁盘分区的。因此多系统引导程序就把自己的程序放在隐含扇区中。从grub的实现来看,也确实是这样的。0扇区放置boot.img,1扇区放置diskboot.img,从2扇区开始的连续的几个扇区放置kernel.img。但关于0道0面的全部扇区都为隐含扇区,我没有找到权威的资料,不知道谁能给出一些权威的参考资料?
程序的执行流程很简单,首先将2号扇区(由变量blocklist_default_start指定)开始的内容拷贝到内存0x7000:0处,因为Phoenix EDD上一次最多只能读0x 7f 个扇区,因此diskboot.S使用了循环读取得方法,一次最多读0x 7f 个扇区。但在我机器上,kernel.img的大小为30K左右,而且是压缩后才放到2号扇区开始的若干个扇区。我想,一般情况下,一次读操作应该足够了。
然后调用copy_buffer,将内存0x7000:0的内容拷贝到内存0:0x8200处。大小由压缩后的grub内核的大小决定。
然后将控制权转到0: 0x8200处。从此时开始,正式转入grub的内核。
另外diskboot.S编译后生成diskboot.img,diskboot.img的大小为512字节,也刚好是一个扇区的大小。diskboot.img的内容将被放置在1号扇区。
待续。。。