EFISTUB - Arch Linux 中文维基

跳转到内容

# EFISTUB

来自 Arch Linux 中文维基
翻译状态：

- 本文（或部分内容）译自 EFI_boot_stub，最近一次同步于 2026-07-22，若英文版本有所更改，则您可以帮助同步与翻译更改的内容。
- 您可以在 ArchWiki 的对应页面找到本文翻译的原始修订历史。
- 本文可能与英文原文存在出入。

相关文章

- Arch 的启动流程
- UEFI
- 统一内核映像

EFI boot stub (也称为 EFI stub)是本身就为 EFI 可执行程序的内核，也就是说，它可以直接被 UEFI 引导启动。

此前，本文和 Debian Wiki 曾将该术语拼写为单个单词 (EFISTUB 或 EFIStub).

默认情况下，Arch Linux提供的内核都是 EFI boot stubs。如果自行编译内核，需将 `CONFIG_EFI_STUB` 配置为 `y` 以启用它，详见The EFI Boot Stub。

在继续之前，需要一个 EFI 系统分区（ESP），并且选择其挂载方式。

提示：

- 如果将ESP分区挂载到`/boot`，pacman 更新的内核就能直接使 UEFI 读取。
- EFI boot stub也可以使用引导加载程序间接启动:
  - 一些 UEFI 启动管理器可以为 UEFI 引导提供额外选项或简化过程
  - 这对于测试内核参数或有多个内核/操作系统且主板 UEFI 启动菜单不易使用的情况尤为有用
  - 如果启动管理器拥有内核和 initramfs 所在分区的文件系统的驱动（例如rEFInd），则无需将他们保存在 ESP 中。

## 另选方案：统一内核镜像

统一内核镜像 (UKI) 本身就是一个 EFI stub 内核,同时含有 initramfs 和启动选项在单一文件中。下表列出了在它们被 UEFI 引导时，UKI 与非 UKI 的 EFI stub 的特性对比。

| UKI | 非 UKI 的 EFI stub
--- | --- | ---
initramfs | 包含在内 | 在单一文件中，存储在 ESP 中
启动选项 | 自身包包含在内含 | 存储在 UEFI 变量中

当没有问题时，UKI 更简单，因为它只需要一个文件，并容纳了所有启动内核所必需的一切。然而，非 UKI 内核可以在不同的 initramfs 文件之间切换和尝试不同的启动选项。对于 UKI 来说，每次变动都会导致生成一个单独的 UKI。

## 引导 EFI boot stub

注意：传递给内核 EFI boot stub 的 initramfs 路径应当相对于 ESP 的根目录，并使用反斜杠分隔路径（遵循 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 有新的修复了问题的版本，可以考虑使用主板厂商推荐的工具刷入。
- 此项可能已过时：一些固件 (尤其是 Lenovo 和 Dell 笔记本电脑) 不会将 NVRAM 中的引导项命令行参数传给 EFI 可执行程序(详见 Arch BBS 2014年的帖子)这种情况下，可以使用 UKI。

#### efibootmgr

使用 efibootmgr 添加加载内核的引导项

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

其中，`block_device_name` 是块设备名，`X` 是分区编号， `root=` 后的 `block_device_identifier` 是实际的 Linux 根目录分区标识符。

注意：

- 有关支持的设备名称格式，请参见内核参数。
- 有关如何获取对应的值，请参见块设备持久化命名。
- 有关具体示例，请参见块设备持久化命名#内核参数。

注意：`-u`/`--unicode` 后的字符串是内核参数，可能还需要根据实际情况添加其它参数（如用于休眠到磁盘的参数）。

基于 LTS Linux 内核、NVMe 存储、带有特定子卷的 BTRFS 文件系统以及 Swap 分区休眠的示例：

    # 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。

提示：

- kesboot-gitAUR 包可以简易且自动地实现此过程，同时他还含有 pacman hook 可在执行软件包操作时添加和移除 EFI 变量。
- https://github.com/de-arl/auto-UEFI-entry 是一个生成上述指令的 bash 辅助工具。
- 将创建引导项的命令保存到 Shell 脚本将非常方便，能让后续修改（例如更改内核参数时）。在这个过程中，可以考虑将删除旧启动项自动化, 因为 efibootmgr 当前 不支持编辑现有引导项.
- 题为 The Linux kernel with built-in boot loader 的论坛帖子或许具有参考价值

#### 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 Shell本身就是一个普通的 UEFI 应用程序。

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

在这种情况下，内核参数将会被作为普通参数传递给 EFI 启动脚本内核。

为了避免每次都需要记住所有的内核参数，你可以将可执行命令保存到一个 shell 脚本中，例如保存在 EFI 系统分区中的`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 分区的根目录下。（对于其他设备，sd"X"代表的ESP分区设备或者编号都可能不同）

## 一些小提示和技巧

### 带有启动内存盘（ramdisk）的后备启动项

如果没有引导管理器，那么内核命令行在启动时是无法被修改的。为了至少提供一些后备方案，例如可以使用`initramfs-linux-fallback.img` 或者在不使用英特尔微码的情况下启动系统，只需使用 efibootmgr 创建一个额外的引导条目即可。这个引导条目的标签可以命名例如“Arch Linux Fallback”，并设置所需的备用选项。

### 在ESP分区上的Archiso

可以将 Arch Linux 的 ISO 镜像放置在 ESP 分区中，从而拥有一个恢复系统。截至 2026 年 7 月 1 日的版本发布时，镜像的文件大小为 1.5G。

首先，下载 archlinux-YYYY.MM.DD-x86_64.iso。

接下来，在你的 ESP 目录下创建一个用于 archiso 的目录：

    # mkdir -p esp/EFI/archiso

提取 arch 目录中的所有内容：

    # bsdtar -v -x --no-same-permissions --strip-components 1 -f archlinux-YYYY.MM.DD-x86_64.iso -C esp/EFI/archiso arch

在最后一步中，使用 `efibootmgr` 创建一个启动项。请替换以下内容：

diskpath 是设备的路径（例如：/dev/sda)）

`diskpart` 是分区编号

    # efibootmgr --create --disk diskpath \
    --part diskpart \
    --label "Arch (rescue system)" \
    --loader '\EFI\archiso\boot\x86_64\vmlinuz-linux' \
    --unicode 'archisobasedir=/EFI/archiso archisosearchfilename=/EFI/archiso/boot/x86_64/vmlinuz-linux initrd=\EFI\archiso\boot\x86_64\initramfs-linux.img'

现在你可以从 UEFI 启动加载程序中选择恢复系统了。

## 故障排除

一些主板，比如 Haswell 架构时代的华硕（ASUS）主板 (如在法国论坛上遇到的那样), 在系统启动时不会注意到引导条目发生的变化，除非是以另一个已存在的引导条目来启动系统。

## 参见

- Linux 内核文档——EFI 启动脚本（The EFI Boot Stub）
- Linux 内核提交代码 - x86 架构，efi：支持 EFI 启动脚本功能（EFI Boot Stub支持）
- Rod·Smith的做法——使用内核的 EFI 加载器

分类：​

- 启动加载程序
- 简体中文

EFISTUB
添加话题