Linux内核启动分析(上)

来源:互联网 发布:铃声助手mac版 编辑:程序博客网 时间:2024/05/16 15:38

Figure 1.1 内核启动顺序

        一切都是从你摁下电源摁钮时开始。首先是主板初始化自身的固件--芯片组还有一些附件,接着尝试让CPU工作。如果这个时候有意外发生,你的电脑恐怕只剩电扇在那独自空转了。此时主板可能会发出刺耳的鸣叫提醒你注意:嗨,伙计CPU这家伙不工作啦!

        好的到这时CPU可能已经正常工作了,如果是多核CPU,那么会随机的选择其中的一个来当做BSP(Bootstrap Processor),来运行BIOS服务和kernel初始化代码。而剩下的那些个核心知道kernel正常运转时才会被激活。你也该知道在真正的kernel运行前CPU是运行在real-mode实模式的,没有分页、没有保护、没有特权功能,地址空间就是平坦的、线性的1MB。

        一旦上电,作为现代和老式的CPU中的寄存器就会复位成默认值。这其中的EIP(指令指针)默认值为0xFFFFFFF0,这个位置也被称之为:复位向量。也就是说第一条指令在0xFFFFFFF0位置,而这个位置的值只是一个简单的jump指令,主板确保她会跳到实模式下1MB内存中的0xF0000位置,这个位置也正是BIOS映射在内存中的位置。也就是说通过硬件手段将BIOS的入口960KB到1MB内存空间映射到主板上的BIOS(flash)。你可能也听过低端内存,说的就是这1MB空间中的低640KB内存,在MS-DOS那个年代,640KB已经是海量内存了...在640KB到960KB之间还有其他一些个映射包括:显卡内存什么的...


Figure 1.2 内存分布

        BIOS已经被映射到了960KB开始的地方,EIP也指向这,接着CPU就开始执行BIOS代码了,执行一些个硬件初始化。POST就是用来确定咱们有些啥装备、都还能工作否?没有显卡的话BIOS就停在那了,发出低沉的鸣叫:嗨老兄,显卡不见了。显卡要是工作正常,就会在屏幕上打印:电脑品牌logo。POST会进行多项测试和初始化,包括罗列资源列表:中断啊,内存啊,IO端口啊等等。对于高级的BIOS有个ACPI(Advanced Configuration and Power Interface)还会构建一张设备清单以供后面的kernel使用。

         POST之后,BIOS就会按照用户配置去磁盘、光驱、软驱、U盘或者网络上寻找一个OS了。如果上述地方统统没能找着,屏幕就会打印:“Non-SystemDisk or Disk Error”。如果找着了,进行下一步。

         BIOS接着就读取硬盘的第一个扇区(sector 0),也被称为MBR(主引导记录),共计512B。MBR中包含有:系统引导程序:bootloader--440B(e.g. LILO,GRUB的stage 1)、硬盘签名--2B、分区表4x16B、MBR数字签名--2B(用于验证MBR的有效性常为0xAA55)。读取出的512B加载到0x7c00位置处,并跳转到该处结束自己的使命(但是其提供的服务会驻留在RAM中),开始执行MBR中的代码--系统引导程序。

         Windows MBR引导加载程序会搜寻各个分区,找到一个活动分区,并加载该分区的第一个区即boot sector,然后执行其中的代码。这个时候出错的话,bootloader会向屏幕打印:“InvalidPartition Table”或者“Missing OperatingSystem”。

        Linux的bootloader则有所不同,他可以处理好多不同种类的OS,可以提供命令行参数,挂载不同的文件系统。不像WMBR他不是搜寻活动分区,其过程大致如下:

        1. MBR自身包含引导的第一阶段,GRUB称之为stage 1;

        2. 由于只有440B,其功能仅限加载一个包含额外启动代码的bootsector;

        3. MBR和其在第二步中加载的代码会读取包含bootloader stage 2所需代码的文件。GRUB称之为stage 2,Windows中是c:\NTLDR。step 2失败,Windows会打印:“NTLDR ismissing”,这时可以用启动光盘修复一下启动项就OK了。stage 2代码会读取启动配置文件(GRUB会读取grub.conf,Windows 下为boot.ini)。对于对系统启动,则会显示启动项列表;否则直接进行启动系统;

        4. 走到这bootloader准备启动一个kernel了。但必须知道足够的有关文件系统的信息来从启动分区读取kernel镜像。在linux下,这是是通过读取/boot/vmlinuz-3.2.0.32-generic-pae 文件到内存并跳转到kernel启动入口。在Windows中,启动代码不在kernel中而是嵌入在NTLDR中了。经过一些列的初始化,NTLDR会加载c:\Windows\System32\ntoskrnl.exe接着和GRUB一样跳转到kernel启动入口。

        之前又说过在低端内存中任何形式的MS-DOS镜像都可以放的下(都小于640KB),但是linux内核经常大于1MB,上面提到的vmlinuz文件就有5MB,也就是说实模式下RAM中是放不下的。bootloader必须运行在实模式下加载BIOS服务,这时就可以开启unrealmode(Big real-mode),就可以访问超过1MB空间的内存了。具体是怎么做的呢?应该是这样:bootloader将CPU带入undreal mode是通过加载超过1MB限制的段描述符的GDT(Global DiscriptorTable),接着通过reset再返回到real-mode,这就形成混合模式:real-mode+ 4GB内存访问(具体参见:http://wiki.osdev.org/Unreal_Mode)。在GRUB源码中有相关的切换模式代码,当GRUB加载完kernel时就会又返回real-mode了。

        加载完成后就会跳转到早期kernel初始化代码。

 

参考:

[1] http://duartes.org/gustavo/blog/post/how-computers-boot-up