Linux如何被启动(二)

Linux如何被启动(一)
引导程序(bootsect)利用int 0x13中断(对应磁盘服务程序中断服务程序)加载从第6个扇区开始的240个扇区的system模块到内存指定位置,在Linux 0.11中,这个位置就是0x10000.至此,bootsect引导程序已把操作系统的代码都加入内存了,bootsect引导程序接着会去确定根设备号,最后它就会设置CS:IP,使其指向0x90200,这正是setup程序,意味着setup将要被执行:

  1. setup程序执行后做的第一件事是利用BIOS提供的中断服务程序从设备上提取将来内核运行时要用到的机器系统数据:光标位置、显示页面数等等,如从BIOS提供的0x41和0x46中断向量所指内存位置获取硬盘参数表1、硬盘参数表2,并将它们放到新的内存位置(0x9000:0x0080和0x9000:0x0090,在linux 0.11中),bootsect程序所在的位置是0x90000,因为bootsect的使命已结束,因此从BIOS提取的机器系统数据将覆盖bootsect引导程序所在部分区域。
  2. 接着setup会关闭掉中断,即setup程序将CPU的标志寄存器的中断允许标志(IF)设置为0,程序在接下来执行过程中,无论是否发生中断,系统都不响任何中断,直到中断重新被打开。之所以要关闭中断,是因为setup将要完成打开32位寻址空间、打开保护模式、新的中断响应机制、建立内存的分布机制等工作,这些工作没有完成的话,都不应该去处理任何在这期间发生的中断。
  3. setup关闭中断后,做的第一件事是将内核(system模块)从它加入内存之初所处的0x10000位置,复制到内存开始的地方0x00000,这个地方可是BIOS的中断向量、中断参数、中断服务程序放置的地方,现在它们都没有用了,所占的内存就会被重新利用,即用于放置内核代码。
  4. setup程序接着要做的就是用自身提供的数据初始化中断描述符表寄存器和全局描述表寄存器。这样以后就可以通过这些寄存器快速找到对应的描述表。全局描述符表是系统中唯一存放段寄存器内容(段描述符)的数组,它用于配合程序进行保护模式下的段寻址,在进程切换时就会用到它。而中断描述表则是保存保护模式下所有中断服务程序的入口地址。这些描述表在内存中的位置是不固定的,可以由操作系统来决定,然后用中断描述符表寄存器和全局描述表寄存器来存放它们在内存中的地址。在当前这个阶段内核尚未真正运行起来,还没有进程,所以现在全局描述表中第一项是空的,第二项是内核代码段描述符,第三项是内核数据段描述符,其余都是空的。目前中断描述符表是一张空表,因为当前的中断是关闭着的,无需要用到中断服务程序,先让其空着,也很合理。
  5. setup程序接着会打开第21(A20)根到第32根地址线的选通控制,意味着在保护模式下,它的线性寻址空间有4GB大小。在这之前的实模式下,CPU的寻址范围是0~0xFFFFF,只有1M的寻址空间,只需要第0~第19根地址线,当程序寻址超过0xFFFFF时,CPU就会回滚到内存地址起始处寻址,即0xFFFFF+1=0x00000,最高位溢出。
  6. 在Linux 0.11的代码中, setup程序会接着对8259A中断控制器进行编程,这块芯片是专门为了对8086和8088进行中断控制而设计的,是可以用程序控制的中断控制器。之所以要重新编程的原因是因为CPU在保护模式下,int 0x00~int 0x1F是Intel CPU内部不可屏蔽的中断和异常中断用的。不对8259A重新编程的话,这些中断就会被覆盖。所以编程的目的就是为了即保留CPU内部的中断号,又可满足在保护模式下的中断需求
  7. setup完成8259A的重新编程的工作后,会将CR0寄存器第0位(PE ,Protected Mode Enable )设置为1,即将CPU的工作模式设置为保护模式(设置0,就是实模式)。当CPU的工作模式从实模式变为保护模式后,CPU需要根据GDT全局描述符表来决定后续执行哪里的程序。CR0寄存器用于存放系统控制标志。
  8. 设置好CR0后,从此CPU要执行的程序只能根据GDT全局描述符表来决定执行哪个程序,setup程序(它是个汇编程序)它执行了这样一句全集jmpi 0,8,这里的8要从二进制按位来理解它的意思,8对应二进制1000,这里的4个位都有特殊意义:最后两位(00)表示内核特权级,如果最后两位是11,表示用户特权级;第三位0表示GDT全局描述符表,如果是1则表示LDT局位描述符表(这张表是用来存放程序的信息,每个任务都有一张LDT和TSS任务状态段,这些表的地址都会存放到GDT上,用来完成进程中各段的寻址、现场保护与现场恢复。);第四位的1,表示根据所选的表的第2项来确定代码段的段基址和段限长等信息,根据setup在初始化GDT表时填入的信息可知,这正是内核代码的地址,head程序就处于内核代码最开始的地方,就意味着开始执行head程序。
  9. 接下来head程序还要在执行操作系统的main之间再做些准备工作。这个我们一下章来讲。

Linux OS在执行由main函数开始的用C语言编写的操作系统内核程序之前用三个由汇编代码生成的程序,即bootsect、setup和马上要执行的head程序。Linux内核的加载策略:
第一步:先将第0磁盘0磁道第1扇区中的bootsect引导程序加载到内存0x07C00,再复制到0x90000;
第二步:再将第0磁盘0磁道第1扇区后面的四个扇区的setup程序加载到内存0x90200
第三步:加载第5个扇区后共240个扇区的内核程序,最开始部分是head程序,其后是内核程序。head.s 汇编成目标代码,再将用C语言编写的内核程序编译成的目标代码,然后将它们链接成system模块。

你可能感兴趣的:(linux,运维,服务器)