為了啟動 Arch Linux,必須配置一個與 Linux 兼容的引導加載程序。引導加載程序負責在初始化啟動進程之前,加載好內核和 initial ramdisk。具體過程因 BIOS 和 UEFI 系統而異,詳細描述在本文和關聯頁面中給出。
固件類型
固件是開機時最先執行的程序。
UEFI
統一可擴展固件接口(Unified Extensible Firmware Interface,UEFI)支持讀取分區表和文件系統。UEFI 不從主引導記錄(MBR)中啟動任何引導代碼(無論其是否存在),相反,UEFI 的啟動過程依賴非易失性隨機訪問存儲器(NVRAM)中的引導條目。
UEFI 規範要求支持 FAT12、FAT16 和 FAT32 文件系統(參見 UEFI 規範 2.10 版 13.3.1.1 小節),但每個符合規範的廠商可以選擇添加對其它文件系統的支持;比如,蘋果的固件支持 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 引導代碼啟動。
BIOS
BIOS,又稱基本輸入輸出系統(Basic Input-Output System),大多數情況下儲存在主板自身的一塊快閃記憶體內,獨立於其它系統存儲。其最早是為 IBM PC 開發,用於處理硬體初始化和啟動過程。從 2010 年起已逐漸被技術上沒有類似限制的 UEFI 替換。
系統初始化
系統上電時,會執行加電自檢(Power-on self-test,POST)。詳細信息可參考 Hugo Landau 的 Modern CPUs have a backstage cast 一文。
在 UEFI 下的情況
- 加電自檢後,UEFI 初始化引導所需的硬體(硬碟、鍵盤控制器等等)。
- 固件讀取 NVRAM 中的引導項,以決定要啟動哪一個 EFI 應用程式,以及從哪啟動(比如從哪一個硬碟和分區)。
- 一個引導項可能對應的只是一塊硬碟。在這種情況下,固件會尋找硬碟上的 EFI 系統分區,並嘗試在後備引導路徑
\EFI\BOOT\BOOTx64.EFI
處(在 IA32(32 位)UEFI 的系統上為BOOTIA32.EFI
)查找 EFI 應用程式。這就是UEFI 可引導可移除介質的工作原理。
- 一個引導項可能對應的只是一塊硬碟。在這種情況下,固件會尋找硬碟上的 EFI 系統分區,並嘗試在後備引導路徑
- 固件啟動 EFI 應用程式。
- 這可以是一個#引導加載程序,或者是使用 EFISTUB 的 Arch 內核本體。
- 還可以是一些其他的 EFI 應用程式,比如 UEFI shell 或#引導加載程序(例如 systemd-boot 或 rEFInd)。
如果啟用了安全啟動,啟動過程將會通過簽名驗證 EFI 二進制文件的真實性。
多重引導
由於每個作業系統或廠商都可以維護自己在 EFI 系統分區中的文件,同時不影響其他系統,所以 UEFI 的多重引導的原理就是啟動不同的、與特定作業系統引導加載程序所對應的 EFI 應用程式。這避免了依賴一個#引導加載程序去加載另一個作業系統的鏈式加載機制。
另請參閱 Arch + Windows 雙系統。
在 BIOS 下的情況
- 上電自檢後,BIOS 初始化引導所需的硬體(硬碟、鍵盤控制器等等)。
- BIOS 啟動在「BIOS 硬碟順序」中第一塊硬碟上的前 440 字節代碼(即主引導記錄引導代碼區域)。
- 引導加載程序在 MBR 引導代碼的第一階段,之後會從下列任意一處啟動第二階段代碼(如果有的話):
- 真正的#引導加載程序啟動。
- 隨後,引導加載程序通過鏈式加載或直接加載作業系統內核的方式加載作業系統。
引導加載程序
引導加載程序(Boot Loader,又稱引導加載器、啟動加載器或啟動引導器)是由計算機固件(BIOS 或 UEFI)啟動的軟體。它負責用想要的內核參數加載內核和其它外置 initramfs 映像。
在 UEFI 的情況下,內核本身可以由 UEFI 使用 EFI boot stub 直接啟動。要在引導前編輯內核參數,仍可以使用單獨的引導加載程序或引導管理器。使用 32 位 IA32 UEFI 固件的系統需要使用支持混合啟動模式的引導加載程序。
/boot
目錄下的內核和 initramfs 映像,否則 Arch 系統將無法引導。也就是說,引導加載器必須支持從塊設備、堆疊塊設備(LVM、RAID、dm-crypt、LUKS 等)開始,到內核和 initramfs 映像所在文件系統為止的一切功能。
Since almost no boot loader supports such stacked block devices and since file systems can introduce new features which may not yet be supported by any boot loader (e.g. archlinux/packaging/packages/grub#7 , FS#79857, FS#59047, FS#58137, FS#51879, FS#46856, FS#38750, FS#21733 and fscrypt encrypted directories), using a separate /boot partition with a universally supported file system, such as FAT32, is oftentimes more feasible.
功能比較
- 由於 GPT 是 UEFI 規範的一部分,因此所有的 UEFI 引導加載程序都支持 GPT 磁碟。在 BIOS 上使用 GPT 磁碟是可行的,可以使用 Hybrid MBR 的「混合引導(hybrid booting)」,或者使用新的純 GPT 協議。但是這個協議可能在某些 BIOS 實現上會出問題,詳情請參考 Rodsbooks。
- 作為 UEFI 規範的一部分,所有 UEFI 引導加載程序都支持安全啟動,但有可能會存在一些限制。
名稱 | 固件 | 分區表 | 多重引導 | 文件系統 | 注意 | |||
---|---|---|---|---|---|---|---|---|
BIOS | UEFI | MBR | GPT | |||||
Clover | 是 | 是 | 否 | 是 | 是 | 可擴展2,5 | 可以在過時 BIOS 系統上模擬 UEFI。 | |
EFI boot stub | – | 是1 | 是 | 是 | – | 繼承自固件2 | 內核是有效的 EFI 可執行文件,可直接從 UEFI 或其它 UEFI 引導加載器啟動。 | |
GRUB | 是 | 是3 | 是 | 是 | 是 | 內置 | 支持 RAID,LUKS(Argon2 PBKDFs 除外)和 LVM(但是不支持精簡配置卷)。平台相關限制請參考 GRUB。 | |
Limine | 是 | 是3 | 是 | 是 | 是 | 有限 | ||
rEFInd | 否 | 是 | 是 | 是 | 是4 | 可擴展2,5 | 支持自動檢測內核和參數,無需明確配置,並支持快速啟動[2]。 | |
Syslinux | 是 | 部分1 | 是 | 是 | 部分 | 有限 | 不支持某些文件系統功能。 只能訪問自身所處的文件系統。 |
|
systemd-boot | 否 | 是3 | 手動 | 是 | 是4 | 可擴展2,5 | 無法從 ESP 或擴展引導加載程序分區(XBOOTLDR)以外的分區啟動二進制文件。 支持自動檢測放入 esp/EFI/Linux/ 的統一內核映像。
|
|
統一內核映像 | – | 是3 | 是 | 是 | – | 繼承自固件2 | systemd-stub(7)、內核、initramfs、內核命令行打包而成的 EFI 可執行文件,可直接從 UEFI 固件或另一個引導加載程序加載。 | |
GRUB Legacy | 是 | 否 | 是 | 否 | 是 | 有限 | 停止開發,轉為 GRUB。 | |
LILO | 是 | 否 | 是 | 部分 | 是 | 有限 | 因為局限性(如與 Btrfs、GPT 和 RAID 搭配使用時)已停止開發。 |
- 雖然二進制文件可以被簽名用於安全啟動,但它不會進行後續驗證,從而破壞了信任鏈。
- 文件系統支持是從固件繼承的。UEFI 規範要求支持 FAT12,FAT16 和 FAT32 文件系統,但廠商可選擇添加對其他文件系統的支持。比如說,蘋果 Mac 中的固件支持 HFS+ 文件系統。如果固件提供在啟動時加載 UEFI 驅動程序的接口,則可以通過加載文件系統驅動程序(需單獨獲取)的方式添加對其他文件系統的支持。
- 支持混合模式啟動,即可以在 32 位 IA32 UEFI 固件上啟動 64 位 x86_64 Linux 內核
- 一種啟動管理器。它只能啟動其他的 EFI 應用程式,例如,使用
CONFIG_EFI_STUB=y
參數編譯的 Linux 內核映像和 Windows Boot Managerbootmgfw.efi
。 - 支持加載 UEFI 文件系統驅動。
另請參見維基百科:引導加載程序比較。
內核
引導加載器會啟動包含內核的 vmlinux 映像。
內核是作業系統的核心。它運行於一個叫內核空間的底層上,負責機器硬體和應用程式之間的交流。在繼續進入用戶空間前,內核會首先執行硬體枚舉和初始化。具體細節請參考zhwp:內核和zhwp:Linux內核。
initramfs
initramfs(初始內存文件系統,initial RAM file system)映像是一個 cpio 存檔文件。Initramfs 映像可通過 mkinitcpio,dracut 或 booster 生成,並是 Arch 推薦的設置早期用戶空間的工具。
在#引導加載程序加載內核和可能存在的 initramfs(初始 RAM 文件系統)文件、並啟動內核之後,內核將 initramfs 檔案展開到(當時為空的)rootfs(初始根文件系統,比如 ramfs 或 tmpfs)。在內核構建過程中嵌入內核二進制文件的 initramfs 被首先提取,然後提取可能存在的外部 initramfs 文件。因此,外部 initramfs 中的文件會覆蓋嵌入式 initramfs 中具有相同名稱的文件。然後,內核執行 /init
(在 rootfs 中)作為第一個進程。早期用戶空間(early userspace)啟動。
/
下的根文件系統原本是一個空的 rootfs,是一個特殊的 tmpfs 或 ramfs 實例。這裡就是 initramfs 會解壓到的臨時根文件系統。
initramfs 的功能是為早期用戶空間提供必要文件,以啟動晚期用戶空間。它不需要包括所有可能會用到的內核模塊,而只需要包括根設備需要的模塊,例如 NVMe,SATA,SAS,eMMC 或 USB(從外接硬碟啟動需要)和加密模塊。在根切換到根文件系統後,大部分模塊將在後續通過 udev 在 init 階段加載好。
- 首先,內核會將其內置 initramfs 解壓到臨時根分區下。Arch Linux 官方支持的內核使用空白存檔作為內置 initramfs,即構建內核時的默認行為。
- 然後,內核會按照引導加載器傳遞的命令行參數指定的順序解壓外置 initramfs 映像,覆蓋掉之前內置 initramfs 或其它解壓出來的文件。注意,可以將多個 initramfs 映像合併為一個文件,內核會按照文件內的順序加載映像。
- 如果首個 initramfs 映像未經壓縮,那麼內核在解壓後會在
/kernel/x86/microcode/
目錄查找 CPU 微碼更新,並在/kernel/firmware/acpi/
目錄查找 ACPI 表更新。 - 在適用的情況下,在處理完 CPU 微碼和 ACPI 表更新後,內核會繼續解壓剩餘的 initramfs 映像。
- 如果首個 initramfs 映像未經壓縮,那麼內核在解壓後會在
Running without initramfs
Since 6.13.8 officially supported kernels have Btrfs and Ext4 drivers built-in [3].
This makes it possible for the kernel to use a root partition with these file systems directly and load the rest of external modules needed from there. Although, there are some quirks to keep in mind:
-
GPT partition automounting could not be used, so
root
kernel parameter is always required. -
Persistent block device naming for
root
is restricted toPARTUUID
andPARTLABEL
only [4]. -
Mount options for
rootflags
are limited, e.g.noatime
would not work [5]. To mitigate possible side effects, you could make the initial mount read-only usingrootflags=ro
. Desired options could be applied later on remount via fstab. -
systemd-gpt-auto-generator(8) is pointless without initramfs and has issues [6], disable it by setting
systemd.gpt_auto=no
.
Another thing you really need initramfs for is early microcode loading. But it is not necessary to build full image for that, Arch provides microcode in separate initramfs files, which could be used independently.
If no initramfs image is provided, the kernel always contains still an empty image to start from [7]. So there should be no issues with root partition pinning.
早期用戶空間
The early userspace stage, a.k.a. the initramfs stage, takes place in rootfs consisting of the files provided by the #initramfs. Early userspace starts by the kernel executing the /init
binary as PID 1.
The function of early userspace is configurable, but its main purpose is to bootstrap the system to the point where it can access the root file system. This includes:
- Set up the storage stack where the root file system may be lying on, e.g. through dm-crypt, dm-verity, mdadm, LVM, systemd-repart, etc.
- Resolve the persistent block device names to real device through udev.
- systemd-modules-load(8) loads kernel modules, such as any block device modules needed to mount the real root file system.
- Handle decryption of the real root file system, if applicable.
- Load the DRM module, as early KMS is enabled by default for in-tree modules.
Note that the early userspace serves more than just setting up the root file system. There are tasks that can only be performed before the root file system is mounted, such as fsck and resuming from hibernation.
At the final stage of early userspace, the real root is mounted at /sysroot/
(in case of a systemd-based initramfs) or at /new_root/
(in case of a busybox-based one), and then switched to by using systemctl switch-root
when using systemd-based initramfs or switch_root(8) when using busybox-based initramfs. The late userspace starts by executing the init program from the real root file system.
晚期用戶空間
The startup of late userspace is executed by the init process. Arch officially uses systemd which is built on the concept of units and services, but the functionality described here largely overlaps with other init systems.
getty
init 會為每個虛擬終端(通常有六個)調用一次 getty,它會初始化終端並保護其免受未授權訪問。在提供用戶名和密碼後,getty 會對照 /etc/passwd
和 /etc/shadow
檢查是否正確。如果正確,就接著調用 login(1)。
Login
login 會根據 /etc/passwd
設置環境變量並啟動用戶 shell,從而為用戶配置一個會話。在成功登錄後,執行登錄 shell 前,login 程序會顯示 /etc/motd(message of the day)的內容,你可以用它來顯示服務條款以提醒用戶你的本地策略,也可以顯示其它提示信息。
Shell
用戶的 shell 啟動後,在顯示命令行提示符前,通常會執行一個運行時配置文件(例如 bashrc)。如果用戶帳戶配置為在登錄時自動啟動 X,那麼運行時配置文件會調用 startx 或 xinit,具體內容請參考#圖形會話(Xorg)。
顯示管理器
另外,在特定虛擬終端下,init 可配置為啟動顯示管理器,而不是 getty。要達成該效果,需要手動啟用其 systemd 服務文件,之後顯示管理器就會啟動一個圖形會話。
圖形會話(Xorg)
xinit 會調用用戶的 xinitrc 運行時配置文件,後者一般會啟動一個窗口管理器或桌面環境。如果用戶退出了窗口管理器,xinit、startx、shell、login 就會依此順序中斷,返回到 getty 或顯示管理器。
參見
- Wikipedia:Booting process of Linux
- Inside the Linux boot process
- Rod Smith - Managing EFI Boot Loaders for Linux
- NeoSmart: The BIOS/MBR Boot Process
- Lennart Poettering - Linux Boot Partitions and How to Set Them Up
- Wikipedia:initrd
- Early Userspace in Arch Linux
- Kernel Newbie Corner: initrd and initramfs
- bootup(7) (mostly about the systemd initrd + userspace portion)