EFI 启动存根

出自 ArchWiki

一个 EFI 启动存根 (又名 EFI 存根) 是一个内核,它是一个 EFI 可执行文件,即可以直接从 UEFI 启动。

从历史上看,本文和 Debian Wiki 使用术语时将它们作为一个词 (EFISTUB 或 EFIStub)。

默认情况下,Arch Linux 内核是 EFI 启动存根。如果编译内核,通过设置 CONFIG_EFI_STUB=y 来激活它。有关更多信息,请参阅 EFI 启动存根

在继续之前,你需要一个 EFI 系统分区选择如何挂载它

提示
  • 如果你将 ESP 挂载到 /bootpacman 将直接更新 UEFI 将读取的内核。
  • EFI 启动存根也可以使用引导加载程序间接启动
    • 有几个 UEFI 启动管理器可以提供额外的选项或简化 UEFI 启动过程
    • 如果你正在试验内核参数,或者你有多个内核/操作系统,并且你的主板 UEFI 启动菜单不易使用,这将特别有用。
    • 具有内核和 initramfs 所在分区的rEFInd等文件系统驱动程序的启动管理器允许将它们放在 ESP 之外。

启动 EFI 启动存根

注意: 传递给内核 EFI 启动存根的 initramfs 路径应相对于 EFI 系统分区的根目录,并使用反斜杠(符合 EFI 标准)。例如,如果 initramfs 位于 esp/EFI/arch/initramfs-linux.img 中,则相应的 UEFI 格式化行应为 initrd=\EFI\arch\initramfs-linux.img。在以下示例中,我们将假设所有内容都在 esp/ 下。

直接使用 UEFI

UEFI 旨在消除对 GRUB 等中间引导加载程序的需求。如果你的主板具有良好的 UEFI 实现,则可以将内核参数嵌入到 UEFI 启动项中,并让主板直接启动 Arch。你可以使用 efibootmgr 或 UEFI Shell v2 来修改主板的启动项。

注意
  • 过时的 UEFI 实现可能与 Linux 内核存在兼容性问题。如果有较新版本的 UEFI 带有错误修复,请考虑使用制造商推荐的工具刷新它。
  • 一些固件(尤其是 LenovoDell 笔记本电脑)不会将 NVRAM 中启动项的命令行参数传递给 EFI 二进制文件。[1] 在这种情况下,可以将内核和参数组合成统一内核镜像,然后使用生成的 .efi 文件创建启动项。

efibootmgr

要使用 efibootmgr 创建将加载内核的启动项

# efibootmgr --create --disk /dev/sdX --part Y --label "Arch Linux" --loader /vmlinuz-linux --unicode 'root=block_device_identifier rw initrd=\initramfs-linux.img'

其中 /dev/sdXY 是 ESP 所在驱动器和分区号,root= 参数是你的 Linux 根分区。

注意: 有关支持的设备名称格式,请参阅内核参数,有关如何获取相应的值,请参阅持久块设备命名,有关示例,请参阅持久块设备命名#内核参数

如果省略,则 /dev/sda 上的第一个分区将用作 ESP。

请注意,引号中的 -u/--unicode 参数只是内核参数的列表,因此你可能需要添加其他参数(例如用于挂起到磁盘)。

带有 LTS Linux 内核、NVME 存储、具有特定子卷的 BTRFS 文件系统以及在交换分区上休眠的示例

# efibootmgr --create \
 --disk /dev/nvme0n1 --part 1 \
 --label "EFISTUB Arch" \
 --loader /vmlinuz-linux-lts \
 --unicode 'root=UUID=01a40dd8-28f0-4636-be1e-aeed60c98095 resume=UUID=2d877d5d-4ca1-4d46-a3d6-b6ee94cbbd78 rw rootflags=subvol=@ loglevel=3 quiet initrd=\initramfs-linux-lts.img'

有关获取启动项列表、设置启动顺序或删除它们的更多信息,请参阅efibootmgr

提示

bcfg

某些 UEFI 实现使得使用 efibootmgr 成功修改 NVRAM 变得困难。如果 efibootmgr 无法成功创建条目,你可以在 UEFI Shell v2 中使用 bcfg 命令(即来自 Arch Linux live iso)。

首先,使用以下命令找出你的 ESP 所在的设备号

Shell> map

在此示例中,1 用作设备号。要列出 ESP 的内容

Shell> ls FS1:

要查看当前的启动项

Shell> bcfg boot dump

要为你的内核添加条目,请使用

Shell> bcfg boot add N FS1:\vmlinuz-linux "Arch Linux"

其中 N 是条目将添加到启动菜单中的位置。0 是第一个菜单项。已经存在的菜单项将在菜单中移动,而不会被丢弃。

你可以直接添加内核选项

Shell> bcfg boot -opt N "root=/dev/sda2 initrd=\initramfs-linux.img"

或者通过在你的 ESP 上创建一个文件

Shell> edit FS1:\options.txt

在该文件中,添加引导行。例如

root=/dev/sda2 rw initrd=\initramfs-linux.img
注意: 在文件中的行首添加额外的空格。行首有一个字节顺序标记,它将压缩其旁边的任何字符,这将在启动时导致错误。

F2 保存,然后按 F3 退出。

将这些选项添加到你之前的条目

Shell> bcfg boot -opt N FS1:\options.txt

对任何其他条目重复此过程。

要删除以前添加的项目,请执行

Shell> bcfg boot rm N

使用 UEFI Shell

如果你不想创建永久启动项,可以从 UEFI Shell 启动内核,因为它是一个普通的 UEFI 应用程序

> FS0:
> \vmlinuz-linux root=PARTUUID=3518bb68-d01e-45c9-b973-0b5d918aae96 rw initrd=\initramfs-linux.img

在这种情况下,内核参数作为普通参数传递给 EFI 启动存根内核。

为了避免每次都记住所有内核参数,你可以将可执行命令保存到 EFI 系统分区上的 shell 脚本中,例如 archlinux.nsh,然后使用以下命令运行它

> FS0:
> archlinux

使用 startup.nsh 脚本

某些 UEFI 实现不会在冷启动之间保留 EFI 变量(例如 6.1 版本之前的 VirtualBox),并且通过 UEFI 设置的任何内容都会在关机时丢失。

UEFI Shell 规范 2.0 规定,ESP 分区根目录中名为 startup.nsh 的脚本将始终被解释,并且可以包含任意指令;其中你可以设置引导加载行。确保将 ESP 分区挂载到 /boot 并创建一个包含内核引导加载行的 startup.nsh 脚本。例如

vmlinuz-linux rw root=/dev/sdX [rootfs=myfs] [rootflags=myrootflags] \
 [kernel.flag=foo] [mymodule.flag=bar] \
 initrd=\initramfs-linux.img

此方法几乎适用于你可能在真实硬件中遇到的所有 UEFI 版本,你可以将其用作最后的手段。脚本必须是单行长行。方括号中的部分是可选的,仅作为指南提供。Shell 样式的换行符仅用于视觉清晰度。FAT 文件系统使用反斜杠作为路径分隔符,在这种情况下,反斜杠声明 initramfs 位于 ESP 分区的根目录中。

技巧与诀窍

带有备用 ramdisk 的启动项

在没有启动管理器的情况下,内核命令行在启动时不可更改。为了至少有一些备用可能性,例如使用 initramfs-linux-fallback.img 和/或在没有 Intel 微代码的情况下启动,只需使用 efibootmgr 创建另一个启动项,例如标记为 “Arch Linux fallback” 和所需的备用选项。

故障排除

在某些 Dell 系统上无法启动的存根

几代 Dell 固件错误地将参数传递给引导加载程序,从而导致 EFISTUB 解析空命令行,这通常意味着系统无法启动(请参阅完整的 linux-efi 线程)。

自 Linux 5.10 以来,已找到一种解决方法来纠正此行为(请参阅此 commit )。对于 Linux < 5.10,你可以使用 efi-packer,如 arch-efiboot,或不同的引导加载程序。

启动项的更改未应用

某些主板,例如 Haswell 时代的 ASUS 主板(在法国论坛上遇到的情况),除非系统使用另一个预先存在的启动项启动,否则不会注意到对启动项的更改。

参见