系统的启动其实是一个比较复杂的过程,大致包括计算机自检,加载启动内核,内核检测并加载一些适当的驱动程序,之后调用程序,准备好系统运行的环境,让用户可以顺利地使用系统。
我们了解系统启动的流程部分,可以帮助我们在系统出现一些问题时,迅速排查问题并修复,也可以帮助我们顺利地配置多重操作系统的多重引导问题。
启动步骤总览
1.加载 BIOS 的硬件信息,进行自我检测,设置取得第一个可启动设备;
2.读取并执行第一个启动设备内的 MBR 的启动引导程序(grub2,spfdisk等);
3.根据启动引导程序的设置,加载内核(kernel),内核会开始检测硬件,加载驱动程序;
4.硬件驱动成功后,内核主动调用 systemd 程序,并以default.target 流程启动。
BIOS自检与MBR
当我们按下电源键后,系统第一个步骤就是加载 BIOS(Basic Input Output System 基本的输入输出系统) , 并通过 BIOS 去加载 CMOS 中的信息,获取主机的各项硬件设置。
CMOS 是主板上的一个芯片,记录如:内置显卡,网卡以及是否启动等信息,通过额外电源来使用记录,这也是主板上为什么要有一个纽扣电池的缘故
当取得这些信息之后,BIOS 就会进行自我检测,开始执行硬件检测的初始化,设置 PnP(即插即用设备) 设备,开始读取硬盘中的软件,操作系统的内核文件。
但是由于不同操作系统的文件系统格式不同,所以我们需要一个启动引导程序,来帮助我们处理内核文件的加载(load)问题,这个程序就叫做 boot load,安装在启动设备第一个扇区内,也就是 MBR (Master Boot Record 主引导记录) 。
在总共512字节的主引导扇区中,MBR只占用了其中的446个字节,里面装的是开机管理程序,如:grub,spfdisk等,另外的64个字节是磁盘分区表,最后两个字节“55,AA”是分区的结束标志。这个整体构成了硬盘的主引导扇区。
Boot loader
我们先概括地看一下其主要功能:
1.提供选项:用户可以选择不同的启动选项,这也是多重引导的重要功能;
2.加载内核文件:直接指向可启动的程序区域来启动操作系统;
3.转交给其他 loader 将启动管理转交给其他的 loader 负责;
每个操作系统的文件系统不同,所以它们都需要单独属于自己的 boot loader,而是每个文件系统都是会保留一个启动扇区(boot sector),来提供给操作系统来安装loader ,不过通常在里面操作系统会默认安装着一份 loader。
在安装 Linux 时,我们是可以选择是否将 boot loader 安装到 MBR 中,如果选择安装的话,那么 MBR 内和我们的启动扇区内,都会保存有一份loader。但是安装 Windows 时,我们没有选择的机会,它会默认在 MBR 和启动扇区内,都安装一份 boot loader 。
所以在安装多重操作系统时,我们的 MBR 经常会被不同的 boot loader 所覆盖,在这里,建议大家在安装操作系统时,先安装 Windows ,再安装Linux ,因为 Linux 的 boot loader 具有控制权转交的功能,可以转交给其他的 boot loader 来进行开机操作,当有多个操作系统时,在开机时可以给我们提供选项,究竟启动哪个操作系统,但是Windows的 boot loader 并没有这个转交功能,而在安装它时又自动覆盖 MBR 这就导致了我们虽然安装了其他的系统,却只能进入 Windows 。
不过,也是有办法更改的,就是我们需要用 Linux 的修复模式来修复 MBR,比较麻烦了
在我们使用 Linux 的启动引导程序 grub2 时,假设里面已经有三个选项,流程如上图。最终 boot loader 的功能还是加载内核文件
加载内核检测硬件
在系统读取内核文件后,会将内核解压缩到内存中,并且利用内核的功能,开始测试和驱动周边的一些设备,如:存储设备,CPU,网卡,声卡等等。在这个时候,内核不一定会使用 COMS 中的硬件信息,而是会重新检测一次硬件,此时,内核开始接管 BIOS 后的工作。
内核可以动态加载内核模块(可以理解为驱动程序),内核模块就存放在磁盘的根目录 /lib/modules 之中。
现在 Linux 发行版一般都会将非必要的功能且可以编译称为模块的内核功能,编译成为模块,因此 USB、SATA、SCSI等磁盘设备的驱动程序通常是以模块形式存在的。
现在假设我们的 Linux 安装到了 SATA 磁盘上,系统通过 BIOS 取得了 boot loader,然后启动内核文件,内核接管系统后开始检测硬件,之后尝试挂在根目录以取得更额外的驱动程序。
乍一看,没什么问题,但是仔细想想,我们的内核要加载 SATA 磁盘的驱动程序才能挂载根目录,但是要加载的这些驱动程序又在磁盘中的 /lib/modules 里面,这就好比我们要使用箱子里的一些东西,但是箱子的钥匙在箱子里一样,就很尴尬。
要解决这个问题,就要用到虚拟文件系统,一般使用的文件名是 /boot/initrd 或 /boot/initramfs (我的电脑是前者),这个文件能够通过 boot loader 加载到内存中,然后解压缩模拟成一个根目录,且提供一个可执行程序来记载启动中所最需要的内核模块,这些内核模块一般来讲就是 USB、RAID、LVM、SCSI等文件系统与磁盘接口的驱动程序。加载完成后帮助内核调用 systemd 来延续开机的正常启动流程,而我们的虚拟文件系统也就被释放,事了拂衣去,深藏功与名。与此同时,实际的根目录文件系统将会被挂载。
systemd
当内核加载完毕,硬件检测和驱动程序加载完成后,主机硬件就已经准备完成了。此时,内核会调用第一个程序 —— systemd ,如果我们进行查看的话,会发现它的 PID 是 1。
systemd 的主要功能就是准备软件执行的环境,如主机名,网络设置,语言设置,文件格式和其他服务启动等等,所有的行为都交由 /etc/systemd/system/default.target.wants 来规划执行
大致流程:
1.systemd 执行 sysinit.target 初始化系统及 basic.target 准备操作系统;
2.systemd 启动 multi-user.target 下本机与服务器服务;
3.systemd 执行 multi-user.target 下的/etc/rc.d/rc.local 文件;
4.systemd 执行 multi-user.target 下的getty.target 及登录服务;
5.systemd 执行 graphical 需要的服务