您有没有想过操作系统为什么可以运行应用程序?那么这篇文章将揭开操作系统引导和启动的面纱。- David Both
正文导航-引导过程.07%
-步骤1.25%
-步骤1.5.31%
-步骤2.36%
-BIOS开机自检(post).09%
-grub 2.15%
-内核.42%
-启动过程.46%
-systemd.47%
-失败讨论.84%
-结论.88%
-额外资源.91%
编译源:作者:David Both
译者:彭赫斯特
您有没有想过操作系统为什么可以运行应用程序?那么这篇文章将揭开操作系统引导和启动的面纱。
了解操作系统引导和引导过程对配置操作系统和解决相关引导问题至关重要。本句说明GRUB2启动载入器[1]启动启动启动挂载核心和系统初始化系统[2]启动启动作业系统的执行程序。
实际上,操作系统引导分为两个阶段:引导引导和引导启动。启动阶段以打开电源开关开始,内核初始化完成和systemd进程成功运行结束。引导阶段将接管剩馀的任务,直到操作系统进入可操作状态为止。
通常,Linux的引导引导引导和启动过程很容易理解。以下部分详细介绍了不同的步骤。
BIOS开机自检(POST)
引导加载程序(GRUB2)
内核初始化
启动所有进程的父级systemd。
本文以GRUB2和systemd为载体,介绍操作系统的引导和引导过程。这是因为这是当前主要Linux发行版使用的引导加载程序和初始化软件。当然,过去使用的其他相关软件仍在某些Linux发行版中使用。
引导过程
引导过程可以通过两种方法之一初始化。首先,如果系统关闭,打开电源按钮将打开系统引导过程。第二,如果操作系统已经在一个本地用户(root或其他没有权限的用户)上运行,则可以通过图形界面或命令行界面以编程方式启动重新启动操作,从而触发系统启动过程。重新启动包括关闭和重新启动操作。
BIOS开机自检(POST)
Linux在开机自检过程中没有做任何事情。post主要由所有操作系统的相同硬件部分执行。计算机打开后,计算机将启动基本输入输出系统基本I/O系统(BIOS)开机自检(POST)过程。
在1981年IBM设计的第一台PC上,BIOS旨在初始化硬件组件。POST是BIOS的一部分,用于检查计算机硬件的基本功能是否正常。开机自检失败将导致此计算机不可用,引导过程也将中断。
BIOS post检查硬件的基本功能是否正常,然后生成指向连接的可引导设备的引导扇区的BIOS中断[3] INT 13H。包含有效引导记录的第一个引导扇区将装入内存,控制将从引导扇区传输到此段代码。
引导扇区是引导加载程序实际的第一步。大多数Linux发行版使用三种引导加载程序:GRUB、GRUB2和LILO。GRUB2是最新的,与其他旧的类似程序相比使用最广泛。
GRUB2
GRUB2的全称是GRand Unified BootLoader,Version 2(第二版大型集成引导加载程序)。这是目前广泛使用的大多数Linux发行版的主引导加载程序。GRUB2是计算机查找操作系统内核并将其加载到内存中的智能程序。GRUB这个词比GRUB2更容易写和读,因此,除了下面特别的指示外,GRUB还指GRUB2。
GRUB旨在与更多操作系统兼容
重引导规范[4],它能够用来引导不同版本的 Linux 和其他的开源操作系统;它还能链式加载专有操作系统的引导记录。GRUB 允许用户从任何给定的 Linux 发行版本的几个不同内核中选择一个进行引导。这个特性使得操作系统,在因为关键软件不兼容或其它某些原因升级失败时,具备引导到先前版本的内核的能力。GRUB 能够通过文件 /boot/grub 进行配置。(LCTT 译注:此处指 GRUB1)
GRUB1 现在已经逐步被弃用,在大多数现代发行版上它已经被 GRUB2 所替换,GRUB2 是在 GRUB1 的基础上重写完成。基于 Red Hat 的发行版大约是在 Fedora 15 和 CentOS/RHEL 7 时升级到 GRUB2 的。GRUB2 提供了与 GRUB1 同样的引导功能,但是 GRUB2 也是一个类似主框架(mainframe)系统上的基于命令行的前置操作系统(Pre-OS)环境,使得在预引导阶段配置更为方便和易操作。GRUB2 通过 /boot/grub2 进行配置。
两个 GRUB 的最主要作用都是将内核加载到内存并运行。两个版本的 GRUB 的基本工作方式一致,其主要阶段也保持相同,都可分为 3 个阶段。在本文将以 GRUB2 为例进行讨论其工作过程。GRUB 或 GRUB2 的配置,以及 GRUB2 的命令使用均超过本文范围,不会在文中进行介绍。
虽然 GRUB2 并未在其三个引导阶段中正式使用这些阶段stage名词,但是为了讨论方便,我们在本文中使用它们。
阶段 1
如上文 POST(上电自检)阶段提到的,在 POST 阶段结束时,BIOS 将查找在接入的磁盘中查找引导记录,其通常位于 MBR(主引导记录Master Boot Record),它加载它找到的第一个引导记录中到内存中,并开始执行此代码。引导代码(及阶段 1 代码)必须非常小,因为它必须连同分区表放到硬盘的第一个 512 字节的扇区中。 在传统的常规 MBR[5] 中,引导代码实际所占用的空间大小为 446 字节。这个阶段 1 的 446 字节的文件通常被叫做引导镜像(boot.img),其中不包含设备的分区信息,分区是一般单独添加到引导记录中。
由于引导记录必须非常的小,它不可能非常智能,且不能理解文件系统结构。因此阶段 1 的唯一功能就是定位并加载阶段 1.5 的代码。为了完成此任务,阶段 1.5 的代码必须位于引导记录与设备第一个分区之间的位置。在加载阶段 1.5 代码进入内存后,控制权将由阶段 1 转移到阶段 1.5。
阶段 1.5
如上所述,阶段 1.5 的代码必须位于引导记录与设备第一个分区之间的位置。该空间由于历史上的技术原因而空闲。第一个分区的开始位置在扇区 63 和 MBR(扇区 0)之间遗留下 62 个 512 字节的扇区(共 31744 字节),该区域用于存储阶段 1.5 的代码镜像 core.img 文件。该文件大小为 25389 字节,故此区域有足够大小的空间用来存储 core.img。
因为有更大的存储空间用于阶段 1.5,且该空间足够容纳一些通用的文件系统驱动程序,如标准的 EXT 和其它的 Linux 文件系统,如 FAT 和 NTFS 等。GRUB2 的 core.img 远比更老的 GRUB1 阶段 1.5 更复杂且更强大。这意味着 GRUB2 的阶段 2 能够放在标准的 EXT 文件系统内,但是不能放在逻辑卷内。故阶段 2 的文件可以存放于 /boot 文件系统中,一般在 /boot/grub2 目录下。
注意 /boot 目录必须放在一个 GRUB 所支持的文件系统(并不是所有的文件系统均可)。阶段 1.5 的功能是开始执行存放阶段 2 文件的 /boot 文件系统的驱动程序,并加载相关的驱动程序。
阶段 2
GRUB 阶段 2 所有的文件都已存放于 /boot/grub2 目录及其几个子目录之下。该阶段没有一个类似于阶段 1 与阶段 1.5 的镜像文件。相应地,该阶段主要需要从 /boot/grub2/i386-pc 目录下加载一些内核运行时模块。
GRUB 阶段 2 的主要功能是定位和加载 Linux 内核到内存中,并转移控制权到内核。内核的相关文件位于 /boot 目录下,这些内核文件可以通过其文件名进行识别,其文件名均带有前缀 vmlinuz。你可以列出 /boot 目录中的内容来查看操作系统中当前已经安装的内核。
GRUB2 跟 GRUB1 类似,支持从 Linux 内核选择之一引导启动。Red Hat 包管理器(DNF)支持保留多个内核版本,以防最新版本内核发生问题而无法启动时,可以恢复老版本的内核。默认情况下,GRUB 提供了一个已安装内核的预引导菜单,其中包括问题诊断菜单(recuse)以及恢复菜单(如果配置已经设置恢复镜像)。
阶段 2 加载选定的内核到内存中,并转移控制权到内核代码。
内核
内核文件都是以一种自解压的压缩格式存储以节省空间,它与一个初始化的内存映像和存储设备映射表都存储于 /boot 目录之下。
在选定的内核加载到内存中并开始执行后,在其进行任何工作之前,内核文件首先必须从压缩格式解压自身。一旦内核自解压完成,则加载 systemd[6] 进程(其是老式 System V 系统的 init[7] 程序的替代品),并转移控制权到 systemd。
这就是引导过程的结束。此刻,Linux 内核和 systemd 处于运行状态,但是由于没有其他任何程序在执行,故其不能执行任何有关用户的功能性任务。
启动过程
启动过程紧随引导过程之后,启动过程使 Linux 系统进入可操作状态,并能够执行用户功能性任务。
systemd
systemd 是所有进程的父进程。它负责将 Linux 主机带到一个用户可操作状态(可以执行功能任务)。systemd 的一些功能远较旧式 init 程序更丰富,可以管理运行中的 Linux 主机的许多方面,包括挂载文件系统,以及开启和管理 Linux 主机的系统服务等。但是 systemd 的任何与系统启动过程无关的功能均不在此文的讨论范围。
首先,systemd 挂载在 /etc/fstab 中配置的文件系统,包括内存交换文件或分区。据此,systemd 必须能够访问位于 /etc 目录下的配置文件,包括它自己的。systemd 借助其配置文件 /etc/systemd/system 决定 Linux 系统应该启动达到哪个状态(或目标态target)。de 是一个真实的 target 文件的符号链接。对于桌面系统,其链接到 gra,该文件相当于旧式 systemV init 方式的 runlevel 5。对于一个服务器操作系统来说,de 更多是默认链接到 mul, 相当于 systemV 系统的 runlevel 3。 emergency.target 相当于单用户模式。
(LCTT 译注:“target” 是 systemd 新引入的概念,目前尚未发现有官方的准确译名,考虑到其作用和使用的上下文环境,我们认为翻译为“目标态”比较贴切。以及,“unit” 是指 systemd 中服务和目标态等各个对象/文件,在此依照语境译作“单元”。)
注意,所有的目标态target和服务service均是 systemd 的单元unit。
如下表 1 是 systemd 启动的目标态target和老版 systemV init 启动运行级别runlevel的对比。这个 systemd 目标态别名 是为了 systemd 向前兼容 systemV 而提供。这个目标态别名允许系统管理员(包括我自己)用 systemV 命令(例如 init 3)改变运行级别。当然,该 systemV 命令是被转发到 systemd 进行解释和执行的。
SystemV 运行级别 | systemd 目标态 | systemd 目标态别名 | 描述 |
---|---|---|---|
停止系统运行但不切断电源。 | |||
0 | runlevel0.target | 停止系统运行并切断电源. | |
S | emergency.target | 单用户模式,没有服务进程运行,文件系统也没挂载。这是一个最基本的运行级别,仅在主控制台上提供一个 shell 用于用户与系统进行交互。 | |
1 | re | runlevel1.target | 挂载了文件系统,仅运行了最基本的服务进程的基本系统,并在主控制台启动了一个 shell 访问入口用于诊断。 |
2 | runlevel2.target | 多用户,没有挂载 NFS 文件系统,但是所有的非图形界面的服务进程已经运行。 | |
3 | mul | runlevel3.target | 所有服务都已运行,但只支持命令行接口访问。 |
4 | runlevel4.target | 未使用。 | |
5 | gra | runlevel5.target | 多用户,且支持图形界面接口。 |
6 | reboot.target | runlevel6.target | 重启。 |
de | 这个目标态target是总是 mul 或 gra 的一个符号链接的别名。systemd 总是通过 de 启动系统。de 绝不应该指向 、 或 reboot.target。 |
表 1 老版本 systemV 的 运行级别与 systemd 与目标态target或目标态别名的比较
每个目标态target有一个在其配置文件中描述的依赖集,systemd 需要首先启动其所需依赖,这些依赖服务是 Linux 主机运行在特定的功能级别所要求的服务。当配置文件中所有的依赖服务都加载并运行后,即说明系统运行于该目标级别。
systemd 也会查看老式的 systemV init 目录中是否存在相关启动文件,若存在,则 systemd 根据这些配置文件的内容启动对应的服务。在 Fedora 系统中,过时的网络服务就是通过该方式启动的一个实例。
如下图 1 是直接从 bootup 的 man 页面拷贝而来。它展示了在 systemd 启动过程中一般的事件序列和确保成功的启动的基本的顺序要求。
和 ba 目标态可以被视作启动过程中的状态检查点。尽管 systemd 的设计初衷是并行启动系统服务,但是部分服务或功能目标态是其它服务或目标态的启动的前提。系统将暂停于检查点直到其所要求的服务和目标态都满足为止。
状态的到达是以其所依赖的所有资源模块都正常启动为前提的,所有其它的单元,如文件系统挂载、交换文件设置、设备管理器的启动、随机数生成器种子设置、低级别系统服务初始化、加解密服务启动(如果一个或者多个文件系统加密的话)等都必须完成,但是在 中这些服务与模块是可以并行启动的。
启动所有的低级别服务和系统初具功能所需的单元,这些都是进入下一阶段 ba 的必要前提。
图 1:systemd 的启动流程
在 的条件满足以后,systemd 接下来启动 ba,启动其所要求的所有单元。 ba 通过启动下一目标态所需的单元而提供了更多的功能,这包括各种可执行文件的目录路径、通信 sockets,以及定时器等。
最后,用户级目标态(mul 或 gra) 可以初始化了,应该注意的是 mul 必须在满足图形化目标态 gra 的依赖项之前先达成。
图 1 中,以 * 开头的目标态是通用的启动状态。当到达其中的某一目标态,则说明系统已经启动完成了。如果 mul 是默认的目标态,则成功启动的系统将以命令行登录界面呈现于用户。如果 gra 是默认的目标态,则成功启动的系统将以图形登录界面呈现于用户,界面的具体样式将根据系统所配置的显示管理器[8]而定。
故障讨论
最近我需要改变一台使用 GRUB2 的 Linux 电脑的默认引导内核。我发现一些 GRUB2 的命令在我的系统上不能用,也可能是我使用方法不正确。至今,我仍然不知道是何原因导致,此问题需要进一步探究。
grub2-set-default 命令没能在配置文件 /etc/default/grub 中成功地设置默认内核索引,以至于期望的替代内核并没有被引导启动。故在该配置文件中我手动更改 GRUB_DEFAULT=saved 为 GRUB_DEFAULT=2,2 是我需要引导的安装好的内核文件的索引。然后我执行命令 grub2-mkconfig > /boot/grub2 创建了新的 GRUB 配置文件,该方法如预期的规避了问题,并成功引导了替代的内核。
结论
GRUB2、systemd 初始化系统是大多数现代 Linux 发行版引导和启动的关键组件。尽管在实际中,systemd 的使用还存在一些争议,但是 GRUB2 与 systemd 可以密切地配合先加载内核,然后启动一个业务系统所需要的系统服务。
尽管 GRUB2 和 systemd 都比其前任要更加复杂,但是它们更加容易学习和管理。在 man 页面有大量关于 systemd 的帮助说明, 也在线收录了完整的此帮助说明[9]。下面有更多相关信息链接。
附加资源
GNU GRUB[10] (Wikipedia)
GNU GRUB Manual[11] )
Master Boot Record[12] (Wikipedia)
Multiboot specification[13] (Wikipedia)
systemd[14] (Wikipedia)
systemd bootup process[15] )
systemd index of man pages[16] )
作者简介:
David Both 居住在美国北卡罗纳州的首府罗利,是一个 Linux 开源贡献者。他已经从事 IT 行业 40 余年,在 IBM 教授 OS/2 20余年。1981 年,他在 IBM 开发了第一个关于最初的 IBM 个人电脑的培训课程。他也曾在 Red Hat 教授 RHCE 课程,也曾供职于 MCI worldcom,Cico 以及北卡罗纳州等。他已经为 Linux 开源社区工作近 20 年。
via:
作者:David Both[17] 译者: penghuster 校对:wxy
本文由 LCTT 原创编译,Linux中国 荣誉推出
[1]: GRUB2 引导装载程序 -
[2]: systemd 初始化系统 -
[3]: 中断 -
[4]: 多重引导规范 -
[5]: 传统的常规 MBR -
[6]: systemd -
[7]: init -
[8]: 显示管理器 -
[9]: 帮助说明 - https://www./software/systemd/man/index.html
[10]: GNU GRUB -
[11]: GNU GRUB Manual -
[12]: Master Boot Record -
[13]: Multiboot specification -
[14]: systemd -
[15]: systemd bootup process - https://www./software/systemd/man/bootup.html
[16]: systemd index of man pages - https://www./software/systemd/man/index.html
[17]: David Both -