Arch 的启动流程

来自 Arch Linux 中文维基
(重定向自Boot process

为了启动 Arch Linux,必须配置一个与 Linux 兼容的引导加载程序。引导加载程序负责在初始化启动进程之前,加载好内核和 initial ramdisk。具体过程因 BIOSUEFI 系统而异,详细描述在本文和关联页面中给出。

固件类型[编辑 | 编辑源代码]

固件是开机时最先执行的程序。

提示:本文时常以 BIOS 和 (U)EFI 代称固件。

BIOS[编辑 | 编辑源代码]

BIOS,又称基本输入输出系统(Basic Input-Output System),是系统开启时最先运行的程序(固件)。大多数情况下它储存在主板自身的一块闪存内,独立于其他系统存储。最早是为 IBM PC 开发,用于处理硬件初始化和启动过程。从 2010 年起已逐渐被技术上不受限的 #UEFI 替换。

UEFI[编辑 | 编辑源代码]

统一可扩展固件接口(Unified Extensible Firmware Interface,UEFI)支持读取分区表和文件系统。UEFI 不从主引导记录(MBR)中启动任何引导代码(无论其是否存在),相反,UEFI 的启动过程依赖非易失性随机访问存储器(NVRAM)中的引导条目。

UEFI 规范要求支持 FAT12、FAT16 和 FAT32 文件系统(参见 UEFI 规范 2.9 版 13.3.1.1 小节),但每个符合规范的厂商可以选择添加对其他文件系统的支持;比如,苹果公司(Apple)的 Mac 支持(并默认使用)他们自己的 HFS+APFS 文件系统。UEFI 的一些实现方案还支持光盘的 ISO-9660 文件系统。

UEFI 会启动 EFI 应用程序。例如引导加载程序、引导管理器和 UEFI Shell 等等。这些应用程序通常以文件形式存储在 EFI 系统分区中。厂商可以将其特定文件存储在 EFI 系统分区中的 /EFI/vendor_name 文件夹下。应用程序可以通过在 NVRAM 中添加引导项或从 UEFI shell 中启动。

UEFI 规范通过兼容性支持模块(Compatibility Support Module,CSM)来支持传统 #BIOS 引导。如果在 UEFI 中启用了 CSM, UEFI 会为所有驱动器生成 CSM 引导项。如果选择从某一个 CSM 引导项启动,UEFI 的 CSM 会尝试从这个磁盘的 MBR 引导代码启动。

注意: 英特尔正逐渐取消对 CSM 的支持。以后也许不能再依赖此特性。

系统初始化[编辑 | 编辑源代码]

系统开启,执行加电自检(Power-on self-test,POST)之后:

在 BIOS 下的情况[编辑 | 编辑源代码]

  1. 上电自检后,BIOS 初始化引导所需的硬件(硬盘、键盘控制器等等)。
  2. BIOS 启动在“BIOS 硬盘顺序”中第一块硬盘上的前 440 字节代码(即主引导记录引导代码区域)。
  3. 引导加载程序在 MBR 引导代码的第一阶段,之后会从下列任意一处启动第二阶段代码(如果有的话):
    • MBR 之后的下一个磁盘扇区,即所谓 MBR 后间隙(post-MBR gap,仅在 MBR 分区表上有)。
    • 分区或者无分区磁盘的卷引导记录(Volume Boot Record,VBR)。
    • BIOS 引导分区(仅限 BIOS/GPT 上的 GRUB)。
  4. 真正的#引导加载程序启动。
  5. 随后,引导加载程序通过链式加载或直接加载操作系统内核的方式加载操作系统。

在 UEFI 下的情况[编辑 | 编辑源代码]

  1. 加电自检后,UEFI 初始化引导所需的硬件(硬盘、键盘控制器等等)。
  2. 固件读取 NVRAM 中的引导项,以决定要启动哪一个 EFI 应用程序,以及从哪启动(比如从哪一个硬盘和分区)。
    • 一个引导项可能对应的只是一块硬盘。在这种情况下,固件会寻找硬盘上的 EFI 系统分区,并尝试在后备引导路径 \EFI\BOOT\BOOTx64.EFI 处(在 IA32(32 位)UEFI 的系统上为 BOOTIA32.EFI)查找 EFI 应用程序。这就是可引导 UEFI 可移动媒体的工作原理。
  3. 固件启动 EFI 应用程序。

如果启用了安全启动,启动过程将会通过签名验证 EFI 二进制文件的真实性。

注意: 一些 UEFI 系统只能从后备引导路径引导。

UEFI 中的多重引导[编辑 | 编辑源代码]

因为每个操作系统或厂商都可以维护自己在 EFI 系统分区中的文件,同时不影响其他系统,所以 UEFI 的多重引导的原理就是启动不同的、与特定操作系统引导加载程序所对应的 EFI 应用程序。这避免了依赖一个#引导加载程序去加载另一个操作系统的链式加载机制。

另请参阅与 Windows 系统双引导

引导加载程序[编辑 | 编辑源代码]

引导加载程序(Boot Loader,又称引导加载器、启动加载器或启动引导器)是由计算机固件(BIOSUEFI)启动的软件。它负责用想要的内核参数加载内核,并根据配置文件初始化 RAM 磁盘。在 UEFI 的情况下,内核本身可以由 UEFI 使用 EFISTUB英语EFISTUB 直接启动。要在引导前编辑内核参数,仍可以使用单独的引导加载程序或引导管理器。

警告: 引导加载程序必须能够访问内核和 initramfs 映像,否则系统将无法引导。因此,在典型配置中,它必须支持访问 /boot 路径。这意味着它必须要支持从块设备、堆叠块设备(LVM、RAID、dm-crypt、LUKS 等)开始,到内核和 initramfs 映像所在文件系统为止的一切功能。
注意: 加载处理器微码更新需要调整引导加载程序的配置。[1]

功能比较[编辑 | 编辑源代码]

注意:
  • 由于 GPT 是 UEFI 规范的一部分,因此所有的 UEFI 引导加载程序都支持 GPT 磁盘。在 BIOS 上使用 GPT 磁盘是可行的,可以使用 Hybrid MBR 的“混合引导(hybrid booting)”,或者使用新的纯 GPT 协议。但是这个协议可能在某些 BIOS 实现上会出问题,详情请参考 Rodsbooks
  • 在文件系统支持中提到的“加密”指的是文件系统级加密,和块级别加密没有任何关系。
名称 固件 分区表 多重启动 文件系统 注意
BIOS UEFI MBR GPT Btrfs ext4 ReiserFS VFAT XFS
EFISTUB英语EFISTUB 继承自固件1 内核是合法的 EFI 可执行文件,可从 UEFI 固件中的 efibootmgr 或者其他引导加载程序加载。
统一内核镜像 继承自固件1 systemd-stub(7)、内核、initramfs、内核命令行打包而成的 EFI 可执行文件,可直接从 UEFI 固件或另一个引导加载程序加载。
Clover 模拟 UEFI 2 不支持加密 继承自固件1 修改版的 rEFIt 分支,用来运行黑苹果(运行在非苹果硬件上的 macOS)
GRUB 在 BIOS/GPT 配置下需要一个 BIOS 引导分区
支持 RAID、LUKS1 和 LVM(但是不支持精简配置卷)。
Limine英语Limine 不支持加密
rEFInd 2 不支持加密 不支持加密 不支持尾部压缩(tail-packing)功能 继承自固件1 支持自动检测内核和参数,无需明确配置,并支持快速启动(fastboot)[2]
Syslinux 部分支持 部分支持 不支持:多设备卷、压缩和加密 不支持加密 仅限 MBR;不支持稀疏索引节点(sparse inodes) 不支持某些文件系统功能。[3]
没有文件系统驱动[4],只能够访问自身所处的文件系统。
systemd-boot 仅限手动安装 2 通过侧载/旁加载3 通过侧载/旁加载3 通过侧载/旁加载3 继承自固件1 通过侧载/旁加载3 无法从 EFI 系统分区 或扩展引导加载程序分区 (XBOOTLDR) 以外的分区启动二进制文件。支持在将 统一内核镜像 放入esp/EFI/Linux时自动检测。
GRUB Legacy 仅 XFS v4 停止开发,转为 GRUB
LILO英语LILO 不支持加密 因为局限性(如与 Btrfs、GPT 和 RAID 搭配使用时)已停止开发
  1. 文件系统支持是从固件继承的。UEFI 规范要求支持 FAT12,FAT16 和 FAT32 文件系统,但厂商可选择添加对其他文件系统的支持。比如说,苹果公司的 Mac 中的固件支持 HFS+ 文件系统。如果固件提供在启动时加载 UEFI 驱动程序的接口,则可以通过加载文件系统驱动程序(需单独获取)的方式添加对其他文件系统的支持。
  2. 一种启动管理器。它只能启动其他的 EFI 应用程序,例如,使用 CONFIG_EFI_STUB=y 参数编译的 Linux 内核映像和 Windows 中的 bootmgfw.efi
  3. systemd-boot 支持加载 UEFI 文件系统驱动。这些驱动由 efifs 提供,需要放在 esp/EFI/systemd/drivers/ 中。

另请参见维基百科:引导加载程序比较

内核[编辑 | 编辑源代码]

内核是操作系统的核心。它运行于一个叫「内核空间」的底层上,负责机器硬件和应用程序之间的交流。为了尽可能充分地压榨 CPU 性能,内核使用调度器,通过一定的优先级算法将 CPU 按照时间动态地分配给各个程序。让我们感觉就像所有程序都在同时使用 CPU 一样。

initramfs[编辑 | 编辑源代码]

#引导加载程序加载内核和可能存在的 initramfs(初始 RAM 文件系统)文件、并启动内核之后,内核将 initramfs 档案展开到(当时为空的)rootfs(初始根文件系统,比如 ramfs 或 tmpfs)。在内核构建过程中嵌入内核二进制文件的 initramfs 被首先提取,然后提取可能存在的外部 initramfs 文件。因此,外部 initramfs 中的文件会覆盖嵌入式 initramfs 中具有相同名称的文件。然后,内核执行 /init (在 rootfs 中)作为第一个进程。早期用户空间(early userspace)启动。

Arch Linux 官方支持的内核对内置的 initramfs 使用一个空的存档(这是构建 Linux 时的默认)。外部 initramfs 映像可用 mkinitcpiodracutbooster 生成。

initramfs 之所以存在,是为了帮系统访问真正的根文件系统(参见 FHS)。也就是说,诸如 IDE、SCSI、SATA、USB/FW 一类硬件所要求的内核模块,如果并没有内置在内核里,就会被 initramfs 负责加载。一旦通过 udev 隐式加载,或由程序或脚本显式加载好模块,启动流程就会继续下去。所以,initramfs 只需包含能够让系统访问根文件系统的模块即可,不用尽可能地包含一切模块。其它需要用到的模块之后会在 init 流程中被 udev 加载好。

Init 流程[编辑 | 编辑源代码]

早期用户空间阶段发生在挂载临时 rootfs 时,对 #initramfs 提供的文件进行操作。

早期用户空间的功能是可配置的,但通常执行以下操作:

systemd-modules-load(8) 加载内核模块, 比如挂载真正根文件系统所需的任何块设备模块。 处理真实根文件系统的解密(如果适用)。 加载 DRM 模块,因为默认情况下会为树内模块启用早期 KMS。 后期用户空间的启动由 init 进程执行。Arch 正式使用 systemd,它建立在单元和服务的概念之上,但这里描述的功能在很大程度上与其他 init 系统重叠。

Getty[编辑 | 编辑源代码]

init 为每个虚拟终端(通常有六个)调用 getty,其为每个虚拟终端初始化 tty,并请求输入用户名和密码。当在某虚拟终端输入用户名和密码后,其 getty 会对照 /etc/passwd/etc/shadow 检查是否正确。如果正确,就接着调用 #login。或者,getty 可能会启动显示管理器,如果有的话。

显示管理器[编辑 | 编辑源代码]

显示管理器可以配置用于代替原来的 tty 登录提示 getty。

为了在引导后自动初始化显示管理器,必须通过 systemd 手动启用服务单元。有关启用和启动服务单元的更多信息,请参见使用单元

Login[编辑 | 编辑源代码]

通过设置环境变量、根据 /etc/passwd 的配置启动用户的 shell,login 程序会为用户启动会话。

在成功登录后,刚刚启动登录 shell 之前,login 程序显示 /etc/motdmessage of the day)。在这里,您可以显示服务条款,以提醒用户您的本地政策,或您想告诉他们的任何内容。

Shell[编辑 | 编辑源代码]

用户的 shell英语Command-line shell 启动后,在显示命令行提示符前,它会执行一个运行时配置文件,比如 .bashrc。如果用户被设定为在登录时自动启用 X,该运行时配置文件会调用 xinit

GUI、 xinit 或者 wayland[编辑 | 编辑源代码]

xinit 也会调用用户的运行时配置文件 .xinitrc,后者一般用来启动一个窗口管理器。如果用户退出了窗口管理器,xinit、startx、shell、login 就会依此顺序中断,返回到 #getty

参见[编辑 | 编辑源代码]