先看了0.11的内核启动代码,这部分代码还不算太难,主要就是bootsect.S文件。由于0.11内核比较小,所以内核镜像被加载到了0x10000内存地址处。由于启动代码是16位实地址模式,一个段最大是64k,所以每次从磁盘读取数据最多是64k,因此加载内核镜像时是以64k为单位从磁盘加载的。这种工作方式对于早期的小内核工作的很好,没有什么问题。
随着Linux内核的发展,内核镜像的数据量不断增大,已经远远超过了512k(0.11时内核镜像达不到这个数据量)。因此,要想将内核镜像加载到0x10000内存地址已经不可能了(内核镜像不能覆盖0xA0000到0x100000这段内存空间),所以,对于现在的大内核,其镜像都是加载到0x100000地址处,即内存1M开始的地址。但这么做会有问题,因为,启动代码是16位实地址模式,最大能访问的内存地址就是1M,要想访问1M以上的内存空间是不可能的。所以在2.4的内核中,我发现启动代码和0.11时有了一定的变化,增加了对大内核镜像的支持,主要是通过BIOS的0x15号中断程序访问超过1M的内存空间。代码主要是在setup.S的bootsect_helper标志处。
具体过程是这样的:
1、使用0.11时的方式从磁盘读取64k数据到0x10000地址处,这部分和0.11时基本相同。
2、调用0x15中断将0x10000地址处的64k数据拷贝到0x100000地址处,接着继续第一步操作,如此循环,直到读取所有镜像数据。当然第二步的操作在每次循环时有变化,主要是目的地址在改变。第二步的操作就是bootsect_helper标志开始的代码,要想了解这段代码,就得知道0x15 BIOS中断,这个中断的作用是通过全局描述符表在内存中拷贝数据块。要注意的是这里用到了全局描述附表,但这个时候系统还是在实地址模式,只不过就是这个中断用到了全局描述符表而已,全局描述符表也是在setup.S中定义的。
到了2.6内核,启动代码又有变化了,这个时候不存在bootsect.S和setup.S文件了,这两个文件被合并了,新的文件是header.S。而且这个文件的代码量明显少了很多,根本没有什么从磁盘读取镜像,并调用0x15中断这样的代码了。2.6把整个启动程序代码都抛弃了,想通过2.6的header.S来引导系统根本不可能的,因为2.6已经将启动程序完全交给LILO或者GRUB这样的专用引导程序了。
以下是0x15中断的说明:
功能:通过全局描述符表在内存中拷贝数据块
调用前:
ah = 87h
cx = 要拷贝的字数(最多8000h)。注意是“字数”而不是字节,意思实说是以2个字节为单位的,最大8000h就是说一次最多拷贝64k Bytes
es:si 指向全局描述符表(下面详细说明)
调用:int 15h
调用后:
cf = 0 表示拷贝成功,此时ah = 0
cf = 1 表示有错误发生,此时ah = 错误码,错误码如下:
01h--奇偶校验错
02h--中断错误
03h--A20选通错
80h--无效命令
86h--不受支持的功能
全局描述符表说明:
es:si指向的描述符表中有6个描述符,这6个描述符分别是:
伪描述符
段描述符表的描述符
源段描述符
目的段描述符
BIOS段描述符
堆栈段描述符
其中需要我们填的描述符有两个,即源段描述符和目的段描述符,其余的描述符空着就好了,在调用后,BIOS会填好。
每个描述符占八个字节,结构如下:
偏移 长度 说明
---- ------ ---------------------------------------------------
00 word 段长度(共20位,这里存bit0--bit15),以字节为单位
02 word 段基址(共32位,这里是bit0--bit15)
04 byte 段基址,这里存bit16--bit23
06 byte 段访问权限,见后面说明
07 word bit0--bit3为段长度的bit16--bit19
bit8--bit15为段基址的bit24--bit31
bit4:保留位AVL;bit5:强制为0;bit6:D/B(较繁琐不说了)
bit7:G,段界限颗粒度(Granularity),G=0颗粒度为字节
G=1段界限颗粒度为4kb
段访问权限说明:
bit7----存在(Present)位P,P=1表示段在内存中存在,P=0表示段在内存中不存在
bit5:6----描述符的特权级,0--3
bit4----说明描述符的类型S,S=0系统段描述符和门描述符,S=1数据段和代码段描述符
bit0:3----描述符特性,根据不同的描述符有不同的8种特性,请查阅相关资料
实际按照如下填写:
伪描述符全为0
段描述表的描述符全为0
源段描述符
段长度:0ffffh(也可以据实填写,但应大于2 * CX -1)
32位段基址按实际填写
段访问权限填93h
其它:AVL=0,D/B=0,G=0
目的段描述符的填写参考源段描述符
BIOS段描述符和堆栈描述符均为全0