系统的启动过程其实很复杂。(下面是一位高人画的图,原图点这里)
简单来说,系统启动的过程如下:
1、加载BIOS的硬件信息与自检,并取得第一个启动设备
2、取得执行第一个启动设备内的MBR的boot loader(grub,spfdisk等程序)
3、根据boot loader的设置加载Kernel,Kernel会检测硬件,加载驱动程序
4、Kernel调用init进程,读取/etc/inittab文件,取得runlevel信息
5、init执行/etc/rc.d/rc.sysinit,初始化系统环境
6、init执行runlevel的各项服务的启动
7、init执行/etc/rc.d/rc.local(用户的自定义程序)
8、init执行mingetty(终端虚拟程序)来启动login进程,等待用户登入
下面是详细的启动过程
一、POST(加电自检)
BIOS自检,枚举本地设备和初始化,找出CMOS设置中第一个“active”状态的设备(可能是硬盘,也可能是U盘,看BIOS怎么设置的)读入其MBR
二、第一阶段引导加载程序
1、MBR 实际上是由3个部分组成 :主引导加载程序(master bootloader code,446 字节)、主分区表 (ppt)、magic nubmer (0xAA55)组成 主分区表有4个记录,对应主分区1-主分区4,共64 字节。最后的 magic number 是 2 字节
2、主引导加载程序搜索主分区表,扫描全部4个分区记录,确保只有1个是被标为”active“ 的(用 fdisk 可以设置某个分区为 active 分区)。然后读入该分区的引导扇区(前512 字节)。active 分区一般是 C 盘或者 linux 的第一个分区
3、主引导加载程序的作用就是读入第2阶段的引导加载程序
三、第二阶段引导加载程序
1、第2阶段引导加载程序的目的是加载内核和initrd 。
2、 如果Boot-Loader安装在MBR中,启动过程将不会涉及到Active分区的第一个扇区,也就是说MBR的引导程序(stage1)会直接加载stage2(或是stage1.5,grub有此阶段),而stage2是存放在某个分区中的文件,lilo应该是boot.b, grub是stage1.5和stage2,在安装boot-loader的时候,这些文件的位置会被记录在stage1中。在这种情况下,即使没有一个分区是Active的,系统也可以引导。
3、如果Boot-loader安装在Active分区的第一个扇区,MBR仍然会有一小段引导程序,用于加载被安装在Active分区第一个扇区的Boot-loader Stage1. 通过Stage1会启动stage1.5的boot loader来理解linux内核镜像中的特殊的文件系统格式,例如,reiserfs_stage1-5(用于从reiserf日志文件系统中进行加载)或e2fs+stage1_5(用于从wxt2或ext3文件系统进行加载)。当stage1.5的boot loader被加载并运行时,stage2 的boot loader才能被加载。当stage2被加载时,GRUB能根据请求的情况显示一个可选内核的清单(在 /etc/grub.conf 中进行定义,同时还有几个软符号链接 /etc/grub/menu.lst 和 /etc/grub.conf)。你可以选择一个内核,修改其附加的内核参数。同时,你可以选择使用命令行的shell来对启动过程进行更深层次的手工控制。在第二阶段boot loader存在与内存中后,就可以对文件系统进行查询了,同时,默认的内核镜像以及初始化内存盘镜像也被加载到内存中。一切准备完毕之后,第二阶段的boot loader就会调用内核镜像。
四、内核
1、内核自解压
2、按照 bootloader 向它提供的 initrd 在内存中的地址,把 /dev/initrd 的内容拷贝到 /dev/ram ,并释放 /dev/initrd 所占用的内存
3、把 /dev/ram 按 rw 的模式挂载为虚拟文件系统,在内存中仿真一个根目录系统,提供一个可执行程序
4、该程序执行其上面的 /linuxrc 或者 /init 脚本,目的是加载驱动模块
5、在 /linuxrc 和 /init 脚本中,会有 pivot_root ()或者 switchroot 把 /sysroot 下的真正根文件系统设备挂载到 / ,把初始根文件系统挂载到 /initrd 下
6、/linuxrc 和 /init 脚本的后面会 umount /initrd 下的初始根文件系统(即使没有完全卸载,也会在 /etc/rc.d/rc.sysinit 中把它们全部卸载)
7、接下来是启动 init 进程。在 2.4 内核中,这个步骤是由内核完成的。但在 2.6 内核中,这个步骤是由 /init 脚本完成的。
简而言之:Boot Loader加载kernel和initrd后,在内存中让initrd解压缩为一个虚根,kernel就能借此通过linuxrc加载适当的驱动程序,最终释放那个虚拟文件系统,并挂载实际的根目录文件系统,就能够开始后续的正常启动流程了。
五、INIT
此时内核主动调用第一个进程/sbin/init。其主要功能是准备软件执行的环境,包括系统主机名,网络设置,语系处理,文件系统格式及其他服务的启动等。
init会读取/etc/inittab的配置文件。inittab定义了init的处理流程,其流程是:
1、取得runlevel即默认执行等级的相关等级
2、使用/etc/rc.d/rc.sysinit进行系统初始化,其主要工作是设置好整个系统的环境。
3、确认启动进入级别,通过/etc/rc.d/rc根据启动的级别来决定启动的服务选项,
4、执行用户自定义开机启动程序/etc/rc.d/rc.local
5、执行终端机模拟程序mingetty来启动login进程,等待用户登入
参考文献:
《鸟哥的私房菜基础篇第三版》第20章
深入理解linux启动流程
本文出自 “临渊羡渔” 博客,谢绝转载!