Arch 启动过程
为了引导 Arch Linux,必须设置一个支持 Linux 的引导加载程序。引导加载程序负责在启动过程开始前加载内核和初始内存盘。对于BIOS和UEFI系统,其过程差异很大。
固件类型
打开系统电源后,最先执行的程序是固件。
- BIOS 和 UEFI 这两个词经常被用来代替 固件。
- 请不要与Linux 固件混淆。
UEFI
通用可扩展固件接口(UEFI)支持读取分区表和文件系统。UEFI 不会从主引导记录(MBR)中启动任何引导代码,无论 MBR 是否存在;相反,引导依赖于NVRAM中的引导项。
UEFI 规范要求支持FAT12、FAT16 和 FAT32文件系统(参见UEFI 规范 2.11 版,第 13.3.1.1 节),但任何符合规范的供应商都可以选择添加对其他文件系统的支持;例如,某些苹果固件支持HFS+或APFS。UEFI 实现也支持ISO 9660用于光盘。
UEFI 启动 EFI 应用程序,例如引导加载程序、引导管理器、UEFI Shell 等。这些应用程序通常存储在EFI 系统分区的文件中。每个供应商都可以将自己的文件存储在 EFI 系统分区下的 /EFI/vendor_name 目录中。可以通过向 NVRAM 添加引导项或从 UEFI Shell 启动应用程序。
UEFI 规范通过其兼容支持模块 (CSM)支持传统的BIOS引导。如果 CSM 在 UEFI 中启用,UEFI 将为所有驱动器生成 CSM 引导项。如果选择一个 CSM 引导项进行引导,UEFI 的 CSM 将尝试从驱动器的 MBR 引导代码进行引导。
BIOS
大多数情况下,BIOS或基本输入输出系统存储在主板本身的闪存中,与系统存储无关。它最初是为IBM PC创建的,用于处理硬件初始化和启动过程,自 2010 年以来,它逐渐被 UEFI 取代,后者不存在同样的技术限制。
系统初始化
系统通电后,会执行上电自检(POST)。另请参阅 Hugo Landau 的《现代 CPU 的后台彩排》。
UEFI
- POST 之后,UEFI 会初始化引导所需的硬件(磁盘、键盘控制器等)。
- 固件读取 NVRAM 中的引导项,以确定要启动的 EFI 应用程序以及从何处启动(例如,从哪个磁盘和分区)。
- 引导项可以只是一个磁盘。在这种情况下,固件会在该磁盘上查找EFI 系统分区,并尝试在备用引导路径
\EFI\BOOT\BOOTx64.EFI中查找 EFI 应用程序(在具有 IA32(32 位)UEFI 的系统上为BOOTIA32.EFI)。这就是 UEFI 可引导移动媒体的工作方式。
- 引导项可以只是一个磁盘。在这种情况下,固件会在该磁盘上查找EFI 系统分区,并尝试在备用引导路径
- 固件启动 EFI 应用程序。
- 这可能是一个引导加载程序,或者 Arch内核本身通过EFI 引导存根。
- 这可能是一些其他的 EFI 应用程序,例如UEFI Shell或像systemd-boot或rEFInd这样的引导管理器。
如果启用了安全启动,启动过程将通过签名验证 EFI 二进制文件的真实性。
多重引导
由于每个操作系统或供应商都可以维护其在EFI 系统分区内的文件而不影响其他文件,因此使用 UEFI 进行多重引导只是启动对应于特定操作系统引导加载程序的不同 EFI 应用程序的问题。这消除了依赖一个引导加载程序的链式加载机制来加载另一个操作系统的需要。
BIOS
- POST 之后,BIOS 会初始化引导所需的硬件(磁盘、键盘控制器等)。
- BIOS 启动 BIOS 磁盘顺序中的第一个磁盘的最后 440 字节(主引导记录引导代码区域)。
- MBR 中的引导加载程序的第一个阶段代码随后从以下位置之一启动其第二个阶段代码(如果存在):
- MBR 之后的磁盘扇区,即所谓的 post-MBR 间隙(仅在 MBR 分区表上),
- 分区或无分区的磁盘卷引导记录(VBR),
- 对于 GPT 分区磁盘上的GRUB,使用特定于 GRUB 的 BIOS 引导分区(它取代了 GPT 中不存在的 post-MBR 间隙)。
- 实际的引导加载程序被启动。
- 引导加载程序随后通过链式加载或直接加载操作系统内核来加载操作系统。
引导加载程序
引导加载程序是由固件(UEFI 或BIOS)启动的一段软件。它负责加载具有所需内核参数和任何外部initramfs映像的内核。
引导管理器会显示一个引导选项菜单,或者提供其他方式来控制引导过程——即,它只是运行其他 EFI 可执行文件。
在 UEFI 的情况下,内核本身可以使用EFI 引导存根直接由 UEFI 启动。仍然可以使用单独的引导加载程序或引导管理器来编辑内核参数。
具有32 位 IA32 UEFI的系统需要支持混合模式引导的引导加载程序。
/boot 目录中。这意味着引导加载程序必须支持从块设备、堆叠块设备(LVM、RAID、dm-crypt、LUKS 等)一直到内核和 initramfs 映像所在的*.文件系统的所有内容。由于几乎没有引导加载程序支持此类堆叠块设备,并且文件系统可能会引入引导加载程序尚未支持的新功能(例如 archlinux/packaging/packages/grub#7、FS#79857、FS#59047、FS#58137、FS#51879、FS#46856、FS#38750、FS#21733 以及 fscrypt 加密目录),通常使用一个独立的 /boot 分区,并使用通用支持的文件系统,如 FAT32,更为可行。
特性对比
| 名称 | 固件 | 分区表 | 多重引导 | 文件系统 | 备注 | ||
|---|---|---|---|---|---|---|---|
| BIOS | UEFI | MBR | GPT | ||||
| Clover | 是 | 是 | 否 | 是 | 是 | 可扩展2,5 | 可在旧版 BIOS 系统上模拟 UEFI。 |
| EFI 引导存根 | – | 是1 | 是 | 是 | – | 从固件继承2 | 内核是一个有效的 EFI 可执行文件,可以直接从 UEFI 或其他 UEFI 引导加载程序启动。 |
| GRUB | 是 | 是3 | 是 | 是 | 是 | 内置 | 支持 RAID、LUKS(但不支持 Argon2 PBKDFs)和 LVM(但不支持精简卷)。有关设置特定的限制,请参见GRUB。 |
| Limine | 是 | 是3 | 是 | 是 | 是 | 有限 | |
| rEFInd | 否 | 是 | 是 | 是 | 是4 | 可扩展2,5 | 支持自动检测内核和参数,无需显式配置,并支持 fastboot [2]。 |
| Syslinux | 是 | 部分1 | 是 | 是 | 部分 | 有限 | 不支持某些文件系统功能。 只能访问被安装到的文件系统。 |
| systemd-boot | 否 | 是3 | 手动 | 是 | 是4 | 可扩展2,5 | 只能从其安装到的 ESP 或同一磁盘上的扩展引导加载程序分区 (XBOOTLDR partition) 启动二进制文件。 自动检测放在 esp/EFI/Linux/ 中的统一内核映像。 |
| 统一内核镜像 (Unified kernel image) | – | 是3 | 是 | 是 | – | 从固件继承2 | systemd-stub(7),一个打包成 EFI 可执行文件的内核、initramfs 和内核命令行,可直接从 UEFI 固件或另一个引导加载程序加载。 |
| GRUB Legacy | 是 | 否 | 是 | 否 | 是 | 有限 | 已停止支持,转而支持GRUB。 |
| LILO | 是 | 否 | 是 | 部分 | 是 | 有限 | 已停止支持,原因在于其局限性(例如,对 Btrfs、GPT、RAID、加密等)。 |
- 虽然二进制文件可以为安全启动签名,但它不执行后续验证,从而破坏了信任链。
- 文件系统支持继承自固件。UEFI 规范要求支持 FAT12、FAT16 和 FAT32 文件系统[3],但供应商可以自行添加对其他文件系统的支持;例如,苹果Mac上的固件支持 HFS+ 文件系统。如果固件提供了在启动时加载UEFI 驱动程序的接口,则可以通过加载(独立获取的)文件系统驱动程序来添加对其他文件系统的支持。
- 支持混合模式引导。即,可以在32 位 IA32 UEFI上引导 64 位 x86_64 Linux 内核。
- 一个引导管理器。它只能启动其他 EFI 应用程序,例如,使用
CONFIG_EFI_STUB=y构建的 Linux 内核映像和Windows 引导管理器 (bootmgfw.efi)。 - 支持加载UEFI 文件系统驱动程序。
内核
引导加载程序引导包含内核的vmlinux 映像。
内核在低级别(内核空间)运行,在硬件和程序之间进行交互。内核首先执行硬件枚举和初始化,然后继续到用户空间。有关详细说明,请参阅Wikipedia:内核(操作系统)和Wikipedia:Linux 内核。
initramfs
initramfs(initial RAM file system,初始内存文件系统)映像是一个cpio存档,它提供了早期用户空间(见下文)成功启动后期用户空间所需的文件。这主要包括所有内核模块、用户空间工具、相关库、支持文件(如 udev 规则)等,这些都是定位、访问和挂载根文件系统所必需的。通过 initramfs 的概念,可以处理更复杂的设置,例如从外部驱动器引导、堆叠设备(逻辑卷、软件 RAID、压缩、加密)或在早期用户空间运行一个微小的 SSH 服务器,用于远程解锁或维护根文件系统。
大多数模块将在 init 过程的后期由udev在切换到根文件系统后加载。
过程如下
- 根文件系统
/最初是一个空的rootfs,它是 tmpfs 或 ramfs 的特殊实例。这是 initramfs 映像将被解压到的临时根文件系统。 - 内核会将内置的 initramfs 解压到临时根目录。Arch Linux 的官方支持的内核使用一个空的存档作为内置 initramfs,这是构建 Linux 时的默认设置。
- 内核按引导加载程序传递的命令行中指定的顺序解压外部 initramfs 映像,覆盖内置 initramfs 或先前解压的文件。请注意,可以将多个 initramfs 映像合并到一个文件中,内核将按文件中的顺序处理它们。
- 如果第一个 initramfs 映像是未压缩的,在解压后,内核将在
/kernel/x86/microcode/和/kernel/firmware/acpi/中分别查找 CPU微码更新和 ACPI 表更新。 - 处理完 CPU 微码和 ACPI 表更新后,内核将继续解压其余的 initramfs 映像(如果有)。
- 如果第一个 initramfs 映像是未压缩的,在解压后,内核将在
Initramfs 映像是 Arch Linux 设置早期用户空间的首选方法,可以使用 mkinitcpio、dracut 或 booster 生成。
不使用 initramfs 引导
自 6.13.8 版本以来,官方支持的内核内置了Btrfs和Ext4驱动程序[4]。
这使得内核可以直接使用这些文件系统的根分区,并从那里加载其余的外部模块。尽管如此,有一些需要注意的怪癖:
- 无法使用GPT 分区自动挂载,因此
root内核参数始终是必需的。 root的持久块设备命名仅限于PARTUUID和PARTLABEL[5]。rootflags的挂载选项有限,例如noatime将不起作用[6]。为了缓解可能的副作用,可以使用rootflags=ro使初始挂载成为只读。所需的选项可以在之后通过 fstab 重新挂载时应用。- systemd-gpt-auto-generator(8) 在没有 initramfs 的情况下没有意义,并且存在问题[7],通过设置
systemd.gpt_auto=no禁用它。
您真正需要 initramfs 的另一件事是早期微码加载。但不需要为此构建完整的映像,Arch 提供了独立 initramfs 文件中的微码,可以单独使用。
如果没有提供 initramfs 映像,内核始终包含一个空的映像以供启动[8]。因此,根分区固定应该没有问题。
早期用户空间
早期用户空间阶段,也称为initramfs 阶段,在 rootfs 中进行,该 rootfs 由#initramfs提供的文件组成。早期用户空间由内核执行 PID 1 的 /init 二进制文件启动。
早期用户空间的功能是可配置的,但其主要目的是引导系统到能够访问根文件系统的程度。这包括:
- 设置根文件系统可能所在的存储堆栈,例如通过dm-crypt、dm-verity、mdadm、LVM、systemd-repart等。
- 通过udev将持久块设备名称解析为真实设备。
- systemd-modules-load(8) 加载内核模块,例如挂载真实根文件系统所需的任何块设备模块。
- 处理真实根文件系统的解密(如果适用)。
- 加载 DRM 模块,因为早期 KMS默认对树内模块启用。
请注意,早期用户空间的作用不仅限于设置根文件系统。有些任务只能在挂载根文件系统之前执行,例如fsck和从休眠恢复。
在早期用户空间的最后阶段,真实根会被挂载到 /sysroot/(对于基于systemd的 initramfs)或 /new_root/(对于基于 busybox 的 initramfs),然后通过使用 systemd 基于 initramfs 使用 systemctl switch-root 或使用 busybox 基于 initramfs 使用switch_root(8)进行切换。后期用户空间通过执行真实根文件系统中的init程序来启动。
后期用户空间
后期用户空间的启动由init进程执行。Arch 官方使用systemd,它基于单元和服务的概念构建,但此处描述的功能很大程度上与其他 init 系统重叠。
getty
init 进程为每个虚拟终端(通常是六个)调用一次getty。getty 初始化每个终端并保护其免受未经授权的访问。当提供用户名和密码后,getty 会对照 /etc/passwd 和 /etc/shadow 进行检查,然后调用login(1)。
登录
login 程序通过设置环境变量并根据 /etc/passwd 启动用户的 shell 来为用户开始一个会话。login 程序在成功登录后,在执行登录 shell 之前,会显示 /etc/motd(message of the day,当日消息)的内容。这是一个很好的地方,可以显示您的服务条款,提醒用户您的本地策略或任何您想告诉他们的信息。
Shell
一旦用户的Shell启动,它通常会在显示提示符之前运行一个运行时配置文件,例如 bashrc。如果账户被配置为登录时启动 X,则运行时配置文件将调用 startx 或 xinit。跳转到#图形化会话 (Xorg)查看结尾。
显示管理器
此外,init可以配置为在特定的虚拟终端上启动显示管理器而不是 getty。这需要手动启用其systemd 服务文件。然后,显示管理器会启动一个图形化会话。
图形化会话 (Xorg)
xinit 运行用户的 xinitrc 运行时配置文件,该文件通常启动一个窗口管理器或一个桌面环境。当用户完成并退出时,xinit、startx、shell 和 login 将按此顺序终止,返回到 getty 或显示管理器。