【完整代码已经归档到 https://github.com/linzhanglong/mini_bootloader 】
引导内核调试了很久,终于调通了,这里主要关键点在于长跳转或者CPU模式切换时候段寄存器的初始化好,否则会跳不过去。现在看一下如何引导Linux内核。
首先我们看一下我们的内核编译的产物(摘自 https://www.slideshare.net/shimosawa/linux-kernel-booting-process-1-for-nlkb):
bzImage就是我们要引导的内核,我们需要了解一下bzImage构成和如何启动的。
bzImage有三部分组成:bootsector, setup.bin, vmlinux.bin。其中bootsector大小512字节,相当于前面的MBR,这个代码会加载到内存地址0x7c00。改代码会把自己移动到0x90000内存位置,并且加载了setup code代码到0x90200,把压缩的内核(vmlinix.bin头部自带解压戴安)代码vmlinu,bin加载到0x100000内存地址,最后跳掉setup code代码部分开始执行。目前bootsector的功能已经被bootloader替换了,我们需要他通过我们的bootloader把bzImage代码里面的bootsector + setup code代码到0x90000内存地址。把vmlinux,bin代码加载到0x100000内存地址。然后跳转到setup code就可以了。setup code代码要求CPU处于实模式下,代码会初始化硬件,进入保护模式,然后调转到0x100000地址去执行vmlinux.bin代码(vmlinux.bin头部自带解压后面的压缩代码)。这里具体setup code的代码实现那些功能可以查一下资料,这里没有详细研究。
现在我们要如何引导我们的内核?
首先我们简单理解就是把bootsector+ setup code加载到0x90000,并且把vmlinux.bin加载到0x10000,最后跳转到0x90200的setup code代码就可以引导内核了。但是这里需要处理两个问题:
1.把vmlinux.bin加载到0x10000,需要CPU处于保护模式,要不访问不了超过1M的内存地址空间;
2.我们需要知道setup code和vmlinux.bin的大小,其实这个存在的地方就在bootsector扇区,里面包含了内核头部信息的一部分,另一部分在setup code的: