机器启动到linux初始化是一个比较复杂并且细节性较强的过程,大部分的实现都是由于历史遗留问题以及各种协议约定而来的,衔接性比较强,而且比较难跟踪,毕竟不是C语言那么简单,一个函数调用一个函数,整个脉络比较清晰明了。
这里主要是以linux-3.2.55版本内核为基础,将整个系统的初始化流程梳理了一下。
进入正文:
A、 自摁下电源开关后,是由主板自动初始化处理器信息的,将CS、DS、ES、SS置为0xffff,而PC置为0x0000,由于初始化时,处理器处于实模式,那么也就是计算机执行的第一条指令在0xffff0这个位置。计算机执行的第一条指令是来自BIOS的,存储在ROM里面,通过ROM芯片译码以读取出来执行,该指令通常都是一条跳转指令,这是由于0xffff0距离可访问的内存结尾已经不远了,该指令可以用来跳转到具体的BIOS操作代码中;
B、 BIOS开始执行后,做了不少事情,比如Power On Self Test(POST,开机自检),检查CPU寄存器、周边芯片的状态,以及针对动态内存、主板芯片组、显卡以及相关外围的寄存器做初始化设置,并检查能够正常工作,同时记录系统的设置值,最重要的就是将常驻程序库(可以理解为BIOS的库)放置在某段内存中,提供给操作系统或者应用程序调用,比如int 0x13等;
C、 BIOS毕竟不是系统,完成了分内工作后,执行int 0x19(前面提到的BIOS的常驻程序库)将存储在磁盘0头0道0扇区的MBR读入到内存0x7c00中,然后BIOS通过跳转指令去到0x7c00去执行引导程序代码;
D、 MBR的引导程序对不同的linux版本而言各有不同,最初0.11版本中,linux的/boot/bootsect.s自己实现了这个MBR引导程序,而如今3.2.55的linux内核版本自身已经不再实现MBR引导程序了,都是由GRUB的/stage1/stage1.S实现的,具体的引导程序历史可以参考linux内核中的/Documentation/x86/boot.txt;
E、 Linux 0.11的引导过程就不谈了,关于这块的资料数不胜数,那么GRUB实现的引导,主要是给用户提供了系统引导选择和引导编辑等功能,核心的是它通过调用BIOS的常驻程序库去将linux内核映像加载到内存当中;
F、 GRUB加载完了内核映像,将会跳转到内核的/ arch/x86/boot/header.S里面的_start开始执行,其实_start也没什么好执行的,就跳转到start_of_setup去设置准备给实模式下main函数运行的环境;
G、 开始进入main函数执行,该函数的实现在/arch/x86/boot/main.c文件里面,具体可以进入去分析里面的代码,其主要的莫过于一些参数的准备、堆的初始化、CPU的检测、BIOS的设置以及内存检测等工作,然后开始转入保护模式;
H、 进入保护模式后,将会跳转去执行arch/x86/boot/compressed/head_32.S里面的startup_32,其主要设置一个基本的环境,如堆栈等;
I、 再往下就是调用/arch/x86/boot/compressed/misc.c里面的decompress_kernel,用来解压内核,当内核被解压到内存中之后,就可以调用它了;
J、 解压完内核,还要调用一个startup_32,这个不同于前面的那个,这个是位于/arch/x86/kernel/head_32.S里面的,主要工作是对页表进行初始化,并启动内存分页功能,初始化0号进程;
K、 startup_32执行完了之后,最后进入内核的主题函数start_kernel,该函数位于/init/main.c,自此完成linux的最后初始化。
以上就是机器启动linux的整个过程,主要是梳理了初始化实现的一个线索,暂时不深入分析。