计算机的启动是一个非常复杂的过程,从打开电源到桌面的显示,需要经过一系列不可或缺的过程,了解这些过程有助于我们更好地理解操作系统,也有助于我们修复系统可能出现的问题。
##0. 启动流程一览
我们先给出 Linux 启动流程的总览图,然后再每一个模块展开说明。
1. BIOS
当我们按下电源按键后,计算机硬件会自动读取主板上的BIOS(Basic Input/Output System)来加载硬件信息以及硬件系统的自我测试。BIOS也是一套程序,它知道如何与硬件进行交互。BIOS首先会对硬件进行检查,判断计算机硬件是否能满足运行的基本条件,这叫做“硬件自检”(Power-On Self-Test,简称 POST)。
硬件自检后,BIOS 会将控制权交给下一段启动程序。这时,BIOS需要知道,”下一阶段的启动程序”具体存放在哪一个设备。也就是说,BIOS需要有一个外部存储设备的排序,排在前面的设备就是优先转交控制权的设备。这种排序叫做”启动顺序”(Boot Sequence)。
因此,BIOS按照”启动顺序”,把控制权转交给排在第一位的存储设备。
2. MBR
系统读取位列第一的可启动存储设备。计算机先读取该设备的第一个扇区,也就是读取最前面的512个字节。这最前面的512个字节,就叫做”主引导记录”(Master boot record,缩写为MBR)。MBR 只有512字节,放不了太多东西,它主要告诉计算机从该设备的哪一个分区(partition)来装载引导加载程序(boot loader)。Boot Loader 储存有操作系统(OS)的相关信息,比如操作系统名称,操作系统内核(kernel)所在位置等。它的主要功能就是加载内核到内存中去执行。常用的 boot loader 有 GRUB 和 LILO 。
那我们经常说到的多操作系统是怎么回事呢?其实每个文件系统(或分区)的最前面会保留一个引导扇区(boot selector),这个引导扇区可以安装 boot loader。这样我们在每个 boot loader 中对应不同的操作系统,在读取 MBR 的时候选择我们需要启动的 boot loader 即可。
3. kernel
随后,boot loader 会帮助我们加载内核,内核就会开始检测硬件与加载驱动程序。没错,内核会以自己的功能重新检测一遍硬件,而不一定会使用 BIOS 检测到的硬件信息。也就是说,内核此时才开始接管 BIOS 后的工作。
Kernel 实际上是一个用来操作计算机的程序,它是计算机操作系统的内核,主要的任务是管理计算机的硬件资源,充当软件和硬件的接口。操作系统上的任何操作都要通过 kernel 传达给硬件。
4. init process
在内核加载完毕以后,此时内核会主动调用第一个进程,那就是 /sbin/init
,它的作用就是初始化系统环境。使用pstree
命令会发现init的进程编号(PID)是1,也就是说init是第一个运行的程序,其他所有进程都从它衍生,都是它的子进程。
许多程序需要开机启动。它们在Windows叫做”服务”(service),在 Linux 就叫做”守护进程”(daemon)。
init 进程的一大任务,就是去运行这些开机启动的程序。但是,不同的场合需要启动不同的程序,比如用作服务器时,需要启动 Apache,用作桌面就不需要。Linux 允许为不同的场合,分配不同的开机启动程序,这就叫做”运行级别”(run level)。也就是说,启动时根据”运行级别”,确定要运行哪些程序。
基本上,依据有无网络与有无 X Window ,Linux 将 run level 划分为7个等级(0-6)。其中0是关机,1是单用户模式,6是重启。而 2-5,一般来说都是多用户模式。
Linux 在启动各个服务前会先执行一系列的初始脚本(rc.sysinit)。这些脚本执行如下功能:设置计算机名称,时区,检测文件系统,挂载硬盘,清空临时文件,设置网络……
之后会根据运行级别的不同,系统会运行 rc0.d 到 rc6.d 目录中的相应的脚本程序,来完成相应的初始化工作和启动相应的服务。rc*.d目录中存放的是该运行级别中需要执行的服务脚本的软链接文件(即快捷方式)。
除此之外,Linux 还会运行一些其他的初始脚本。运行完后,操作系统已经完全准备好了,只是,还没有人可以登录!!!init 会给出登录(login)对话框,或者是图形化的登录界面。
5. login
输入用户名密码登录成功后,系统会为用户分配一个用户 ID(UID),和一个组 ID(GID)。这两个 ID 就好像身份证一样会一直伴随用户,用于检测用户执行程序时的身份验证。
当用户登录成功后,一个完整的操作系统就展现在用户的面前了。哈哈!
总结
结合一开始给出的流程图,Linux 的启动流程可以概括为以下几个主要步骤:
- 加载 BIOS 的硬件信息与硬件自检,并依据设置取得第一个可启动的设备;
- 读取并执行第一个启动设备内的MBR的 boot loader;
- 依据 boot loader 的设置加载内核,内核会开始检测硬件与加载驱动程序;
- 在内核 Kernel 加载完毕后,Kernel 会主动调用 init 进程,而 init 会取得 run-level 信息;
- init 执行 rc.sysinit 初始化系统的操作环境(网络、时区等);
- init 启动 run-level 的各个服务;
- 用户登录
要注意在一开始的流程图中 init 虽然只用了一个模块展现出来,但其实在启动过程中 init 占了很大的比重。