Linux系统引导过程

2019-04-13 16:20发布

主要分为五个阶段:
1、系统加电到阶段1:
主要任务:系统加电后由BIOS进行加电自检POST(POST上电自检:是微机接通电源后,系统进行的一个自我检查的例行程序。这个过程通常称为POST上电自检(Power On Self Test),对系统的几乎所有的硬件进行检测。)检查系统必备的引导设备是否存在,如内存、磁盘等关键硬件设备;然后读取CMOS中的引导设备信息,从引导设备中读取第一个扇区,该扇区包含着引导程序。
2、引导过程详解:
引导包含两个阶段,当找到第一个引导设备后,第一阶段的引导程序就会被装载入RAM并执行,该引导程序大小一般小于一个扇区,其作用是加载第二阶段的引导加载程序,MBR就是熟知的第一阶段引导加载器。通常,Linux都是从硬盘上引导的,其中主引导目录(MBR)中包含主引导加载程序。MBR是一个 512 字节大小的扇区,位于磁盘上的第一个扇区中(0 道 0 柱面1 扇区)。当 MBR 被加载到RAM中之后,BIOS 就会将控制权交给 MBR。
当第二阶段的引导加载程序(grub)被装入RAM后并执行时,通常会显示一个动画屏幕,并将Linux内核镜像和一个可选的初始RAM磁盘(临时根文件系统initrd)加载到内存中。在加载映像时,第二阶段的引导加载程序就会将控制权交给内核映像,然后内核就可以进行解压和初始化了。
详细过程如下:
在BIOS(即BIOS有将文件从外设拷贝到内存的能力)将引导设备的第一个扇区的引导程序(在磁盘上或其他存储设备上)装入内存(具体的物理地址是0x7c00)以后,由引导程序把操作系统的核心装载到内存中。其中引导程序可以很简单,只占用一个扇区512字节,也可以很复杂如grub.在引导程序grub被装到内存并获得控制权之后,grub会读取相应的磁盘上已经存在的真实文件系统中(即在安装linux操作系统时,内核是和根文件系统完全分开的,且根文件系统必须先于内核存在于磁盘上,原因是在还未加内核之前grub就会读取存在于磁盘上的根文件系统下的grub.conf文件,从该文件中才知道要加载的内核在根文件系统的哪,同时也说明了,文件系统必须已经存在于磁盘之上,对于后面的加载是内核去加载存在于磁盘之上的文件系统,从而内核可以通过加载后的文件系统对整个磁盘进行管理)的/boot/grub.conf中的引导列表选择默认的要启动的内核镜像bzImage.根据bzImage中前512字节的bootsect.S中的setup、vmLinux.bib所占扇区的大小,以及内核是否为大内核镜像,将bootsect.S放置到物理地址0x00090000(576Kb),setup.S放置到物理地址0x00090020(576.5Kb),如果是大内核将vmLinux.bin(经过压缩的系统镜像,由piggy.o、misc.c、head.S组成,其中只有piggy.o是被压缩过的,其他两个并未被压缩)放置到0x000100000(1Mb),否则小内核的话,放置到0x000010000(64Kb),将内核搬到相应的地址之后,引导程序跳到物理地址0x00090020,即setup.S所在的物理地址,并开始执行setup.S代码。
3、阶段1~阶段2
该阶段由文件setup.S生成的代码块进行系统设备的探测,将探测到的相关信息保存到内存地址中(应该是在1MB以内的空间中),在系统最终初始化时由系统使用。按顺序探测完设备后,跳转到物理地址0x000100000(1Mb)(即vmLinux.bin的所在位置),开始执行由/compressed/head.S(该段代码位于vmLinux.bin中,但并未压缩,所以可以直接执行,同时/compressed/misc.c也位于vmLinux.bin的头部,也没有被压缩,这两个联合起来完成对内核镜像压缩文件piggy.o的解压,其中misc.c包含zlib算法的解压缩代码的c语言的实现,head.S中包含的汇编代码用于为调用解压缩程序设置调用参数和解压缩过程使用的堆、栈。)生成的代码块。
4、阶段2~阶段3
该阶段执行由/compressed/head.S生成的代码块,该汇编代码为调用C语言函数设置相应的参数及栈指针后调用decompress_kernel对压缩的内核进行解压缩,该函数按需要将解压的内核片段放置到两个不同的物理内存区域中(将解压缩后的内核放置到两块不同的物理内存的原因是:要放解压后代码的地址1Mb处被vmLinux.bin占着,只有解压完了,那部分空间才能被释放),然后将head.S中名为move、负责搬移的代码(该代码负责将两部分分开的内核代码移动到一起的功能)移动到物理地址0x00010000(64Kb)。然后跳转到物理地址0x00010000,执行该段代码。
5、阶段3~阶段4
该阶段执行复制到物理地址0x00010000的搬移代码,该部分的搬移代码将位于两个物理区域的解压缩内核代码片段移动到物理地址0x00100000,此时物理地址0x00100000处包含解压后的内核镜像。
6、阶段4~阶段5
该阶段搬移代码执行完毕后,执行紧随其后的跳转指令,跳转到物理地址0x00100000。执行位于文件src/arch/i386/kernel/head.S中的startup_32代码段,开始进行系统核心的初始化过程。
7、阶段5~系统完全启动
该阶段进行系统的初始化,初始化过程由系统初始化进程init_task完成(也叫0号进程)。该进程完成了系统内存管理子系统、进程管理子系统、中断异常子系统、时间度量子系统的初始化工作。最后该进程通过函数kernel_thread()创建一个名为init的内核线程,然后0号进程调用调度器schedule(),释放了处理器的使用权,成为系统的空闲(idle)进程。在内核线程init获得处理器后,首先完成对称多处理器系统中应用处理器的初始化();然后挂在系统的跟文件系统,完成系统总线、网络协议栈等的初始化;最后通过调用execve()开始执行用户态程序/sbin/init,此时内核线程init转换成了用户进程。
该用户态进程是系统中所有进程(除了0号进程)的祖先,它首先读取系统配置文件/etc/inittab,根据该配置文件完成系统的最终环境的初始化。在RHEL5系统下,这些初始化包括:执行脚本文件/etc/rc.d/rc.sysinit完成系统环境的初始化,包括获取网络参数,挂载进程文化系统proc,内核2.6新引入的用于描述系统设备层次结构的文件系统sys,挂载每一个具体设备的驱动程序,设置系统时间和主机名,在需要对根文件系统进行检测时调用fcsk检测文件系统的一致性;根据文件/etc/inittab中指定的运行级别运行相应级别的启动脚本,这些脚本通常负责控制一个后台服务进程运行,每个运行级别的启动脚本位于/etc/rc.d/rc<运行级别号>.d目录中;最后为系统中的终端启动一个getty进程、等待用户登录。