Linux内核——3个汇编程序bootsect、setup以及system(head.s)

加电的一瞬间,计算机内存中,准确的说是RAM中,中空空如也,什么程序也没有。软盘里虽然有操作系统程序,但CPU的逻辑电路被设计为只能运行内存中的程序,没有能力直接从软盘运行操作系统。


这就需要硬件主动加载0xffff0处的BIOS程序,由BIOS准备好中断向量表、中断服务程序,接着通过中断“int 0x19”将引导程序bootsect加载至内存,以及后续的一系列操作,最终操作系统自身代码才能位于内存中,被CPU执行。


通过BIOS的“int 0x13”中断,找到bootsect自身的中断服务程序,将setup加载至SETUPSEG(0x90200)处。同样手法,将system加载至SYSSEG(0x10000)处。bootsect程序任务都已经完成。


然后,通过“jmpi 0, SETUPSEG”跳转至setup程序的加载位置,此时CS:IP指向setup程序的第一条指令。


setup通过BIOS提供的中断服务程序提取了系统数据,存储在原来的bootsect位置只保留最后2字节未被覆盖(0x901fc,根设备号)。接着,将IF至0,完成关中断操作。


然后,将system移动到0x00000位置,此时head已经占据了0x00000处,同时BIOS中断向量表彻底被覆盖。为此,setup开始为保护模式做准备,设置GDT、IDT并用CPU中专用寄存器IDTR、GDTR看住。


接着,打开A20,也就是32位寻址模式,再对可编程中断控制器8259A进行重新编程,并置PE位为1,即设定处理器工作方式为保护模式,以后根据GDT决定执行哪里的程序。


最后,通过“jmpi 0,8”跳转到head。“0”表示段内偏移,“8(1000)”是保护模式下的段选择符,最后两位“00”表示内核态,第二位“0”表示GDT,第一位“1”表示GDT表中GDT[1]项(内核代码段),从该项中得知段基址为0x00000000。结合上述偏移0,可知最终跳转至0x0000000处,执行head程序。


Reference:

  1. 新设计团队. Linux内核设计的艺术[M]. 北京:机械工业出版社, 2014.

@qingdujun
2017-11-25 北京 怀柔

你可能感兴趣的:(Linux内核——3个汇编程序bootsect、setup以及system(head.s))