19(终). 系统启动

来源:互联网 发布:淘宝卖毛衣好的店铺 编辑:程序博客网 时间:2024/05/17 21:58

 启动指把一部分OS装入主存并让CPU执行,也表示内核数据结构的初始化等。启动很大程度上依赖于体系结构,以下以80x86为例。

1.       史前时代
加电后,RAM中数据是随机的,首先,复位电路开动,在CPU某脚上产生RESET。它会将cs、eip等Regs设置成固定值,随后,它开始从物理地址0xfffffff0处执行代码,此物理地址被硬件映射到某ROM,其中放的程序集在80x86体系中叫BIOS。所有OS启动都要用BIOS程序初始化硬件。一些OS如MS—DOS甚至依赖于BIOS实现大部分系统调用。BIOS使用实模式地址,BIOS启动过程执行4个操作:a.POST(power-on self-test,上电自检),ACPI兼容的BIOS中,会建立几个表描述当前系统中的硬件设备,这些表可被OS获取。b.初始化硬件设备,在PCI体系结构中它很重要,它保证IRQ线与I/O端口不冲突,它完事后会在屏幕上显示PCI设备一个列表。c.找一个OS,按BIOS的设置,它会按顺序访问如软盘、磁盘、光盘的第一扇区。d.只要找到一个,就把该第一扇区的内容拷到RAM的物理地址0x00007c00处。拷完后跳到这里执行拷进来的代码。
2.       远古时代
从磁盘启动Linux要一个两步的引导装入程序(boot loader),80x86下有名的是LILO(Linux LOader)及可识别多个文件系统的GRUB(Grand unified Bootloader)。以硬盘来说,它的第一个扇区称为主引导记录(Master Boot Recorder,MBR),该扇区中包含记录着磁盘分区情况的分区表及如BIOS中所述的一个小程序,其实这个小程序就是LILO的一部分,因为LILO太大装不进MBR,如前所述,这段LILO的片段被拷到物理地址0x00007c00处的RAM处开始执行,它执行时会将自己搬到0x00096a00处并建立实模式栈。接着它把LILO的第二部分拷到0x00096a00+512=0x00096c00处并执行。第二部分从磁盘读取可用OS的映射表,让用户选择一个OS,再将相应分区的引导扇区拷进来执行,或者是直接就拷内核映像。拷贝过程大致如下:1.调用BIOS相关例程显示Loading。2.调用BIOS过程从磁盘装入内核映像的第一个512字节到RAM0x00090000,再拷贝内核映像中512字节开始的叫setup()的函数代码到0x00090200。3.调用一个BIOS例程从磁盘中装载其余内核映像:若内核映像是make zImage编译的小映像则放入低的0x00010000,若由make bzImage编译的大内核映像则放到高的0x00100000,分别称为高装载、低装载。4.此时,内核映像已经全部拷入主存,回顾下:从一开始到512字节开始处的setup()函数被拷到0x00090000处,而setup()函数之后的映像被高或低装载到其它地方,这部分映像的开头是一个start_up32()函数(后面会用)。这时跳到第二步拷进来的0x00090200处的setup()函数。
3.       中世纪:setup()函数
BIOS虽已初始化硬件,但Linux为了增加可移植性而重新初始化它们。它除了初始化硬件外还将原先若低装载的其余内核映像移动到0x00001000处,之后建立临时的中断描述符表IDT和临时全局描述符表GDT、重写PIC以屏蔽中断,设置cr0的PE位进入保护模式,跳到0x1000(对于低装载的情况)或0x00100000处(高装载)的叫start_up32()的函数处。
4.       文艺复兴:start_up32()函数
它先初始化段寄存器与临时栈,清eflags,再调用一函数来解压缩内核。若内核映像被低装载,则直接解压到0x00100000处;若是高装载(0x00100000),则解压在压缩的映像后面的地址上,解压完成后再将解压出的内核拷贝回0x00100000处以覆盖原先在此处的压缩的内核映像。之后跳到解压后的0x00100000处执行另一个start_up32()函数,它为进程0建立执行环境、开启分页、再跳到一个start_kernel()函数。
5.       现代:start_kernel()

它完成内核的初始化,初始化各个内核部件。最后调用kernel_thread()创建进程1内核线程,之后内核线程会创建其它内核线程并执行sbin/init程序,init完成最终的OS其它初始化。

原创粉丝点击