1,当系统上电或复位时,CPU会将PC指针赋值为一个特定的地址0xFFFF0并执行该地址处的指令。在PC机中,该地址位于BIOS中,它保存在主板上的ROM或Flash中
2,BIOS运行时按照CMOS的设置定义的启动设备顺序来搜索处于活动状态并且可以引导的设备。若从硬盘启动,BIOS会将硬盘MBR(主引导记录)中的内容加载到RAM。MBR是一个512字节大小的扇区,位于磁盘上的第一个扇区中(0道0柱面1扇区)。当MBR被加载到RAM中之后,BIOS就会将控制权交给MBR
3,主引导加载程序查找并加载次引导加载程序。它在分区表中查找活动分区,当找到一个活动分区时,扫描分区表中的其他分区,以确保它们都不是活动的。当这个过程验证完成之后,就将 活动分区的引导记录从这个设备中读入RAM中并执行它
4,次引导加载程序加载Linux内核和可选的初始RAM磁盘,将控制权交给Linux内核源代码。
5,运行被加载的内核,并启动用户空间应用程序
另外,第5阶段,它完成启动内核并运行用户空间的 init进程
当内核映像被加载到RAM之后,Bootloader的控制权被释放,内核阶段就开始了。内核映像并不是完全可直接执行的目标代码,而是一个压缩的zImage(小内核)或bzImage(大内核,b表示big)
但是,并非zImage和bzImage映像中的一切都被压缩了,否则Bootloader把控制权交给菏泽哥内核映像它就傻了。实际上,映像中包含未被压缩的部分,这部分中包含解压缩程序,解压缩程序会解压映像中被压缩的部分。zImage和bzImage都是用gzip压缩的,它们不仅是一个压缩文件,而且在这两个文件的开头部分内嵌有gzip解压缩代码
当bzImage(用于i386映像)被调用时,它从/arch/i386/boot/head.S的start汇编例程开始执行。这个程序执行一些基本的硬件设置,并调用
/arch/i386/boot/compressed/head.S中的startup_32例程。startup_32程序设置一些基本的运行环境(如堆栈)后,清除BSS段,调用
/arch/i386/boot/compressed/misc.c中的decompress_kernel()C函数解压内核。内核被解压到内存之后,会调用
/arch/i386/kernel/head.S文件中的startup_32例程,这个新的startup_32例程(称为清除程序或进程0)会初始化页表,并启用内存分页机制,接着为任何可选的浮点单元(FPU)检测CPU的类型,并将其存储起来供以后使用。这些都做完之后,/init/main.c中的start_kernel()函数被调用,进入与体系结构无关的Linux内核部分
start_kernel()会调用一系列初始化函数来设置中断,执行进一步的内存配置。之后,/arch/i386/kernel/process.c中kernel_thread()被调度以启动第一个核心线程,该线程执行init()函数,而原执行序列会调用cpu_idle()等待调度
作为核心线程init()函数完成外设及驱动程序的加载和初始化,挂接根文件系统。
init()打开/dev/console设备,重定向stdin、stdout和stderr到控制台。之后,它搜索文件系统中的init程序(也可以由“init=”命令行参数指定init程序),并使用execve()系统调用执行init程序。搜索init程序的顺序为:/sbin/init、/etc/init、/bin/init和/bin/sh。在嵌入式系统中,多数情况下,可以传给内核一个简单的shell脚本来启动必需的嵌入式应用程序
至此,漫长的Linux内核引导和启动过程就此结束,而init()对应的这个由start_kernel()创建的第一个线程也进入用户模式