UEFI

来自 Arch Linux 中文维基

统一可扩展固件接口(Unified Extensible Firmware Interface,简称 UEFI,EFI 的后继者)是操作系统和固件之间的接口。UEFI 提供了启动操作系统或运行预启动程序的标准环境。

UEFI 有别于传统 BIOS 系统所使用的“MBR 引导代码”。二者的区别和使用 UEFI 启动的过程见 Arch 的启动流程。要配置 UEFI 引导加载程序,请参见 Arch 的启动流程#引导加载程序

注意: 早期主板制造商的 UEFI 实现可能相比 BIOS 有着更多的错误。如果遇到无法解决的问题,请考虑对这类系统使用传统 BIOS 引导。

UEFI 版本[编辑 | 编辑源代码]

  • 1.x 版本的 UEFI 起始于 Intel 的 EFI。
  • 后来,一个名为 UEFI Forum 的公司组织接管了其开发工作,他们从 2.0 版本起将其更名为 Unified EFI。
  • 除非特别指明是 EFI 1.x,EFI 和 UEFI 均指代 UEFI 2.x 固件。
  • Apple 的 EFI 实现既不是 EFI 1.x 版本也不是 UEFI 2.x 版本,而是这两者的混合体。这类固件不被归入到任何 (U)EFI 规格中,因而不是标准的 UEFI 固件。除非特别指明,以下说明可通用,但部分内容在 Apple Macs 上可能无效或有所不同。

最新的 UEFI 标准位于 https://uefi.org/specifications

UEFI 固件架构[编辑 | 编辑源代码]

UEFI 下每一个程序,无论它是某个 OS 引导器还是某个内存测试或数据恢复的工具,都要兼容于 EFI 固件位数或体系结构。

目前主流的 UEFI 固件,包括近期的 Apple Macs,都采用了 x86_64 EFI 固件。目前还在用 IA32 即 32 位的 EFI 的已知设备只有于 2008 年前生产的 Apple Macs,一些 Intel Cloverfield 超级本和采用 EFI 1.10 固件的 Intel 服务器主板。

x86_64 EFI 不能兼容 32 位 EFI 程序。所以 UEFI 应用程序必须依固件处理器位数/体系结构编译而成。

注意: 这种平台需要一个支持 IA32 UEFI的启动加载器,比如带有i386-efi模块的GRUB

检查系统位数[编辑 | 编辑源代码]

Linux 系统[编辑 | 编辑源代码]

在运行Linux 4.0及以上内核的发行版中,可以通过 sysfs 接口查看 UEFI 系统位数。试着运行:

$ cat /sys/firmware/efi/fw_platform_size

如果返回 64 则代表 64 位(x86_64) UEFI 系统,如果返回 32 则代表 32 位(IA32) UEFI 系统。如果文件不存在,那么代表并没有进入 UEFI 模式。

macOS 系统[编辑 | 编辑源代码]

2008年以前的 Mac 大都使用 i386-efi 固件, 2008年以后大都使用 x86_64-efi 。有能力运行 Mac OS X Snow Leopard 64位内核的 Mac 都是 x86_64 EFI 1.x 版的固件。 在 Mac OS 下输入以下命令可以找出该 Mac 的 efi 固件:

$ ioreg -l -p IODeviceTree | grep firmware-abi

如果命令返回 EFI32 则对应的是 i386 EFI 1.x 版本的固件,返回 EFI64 对应的则是 x86_64 EFI 1.x 版的固件. Mac 没有 UEFI 2.x 固件,Apple的 EFI 实现也不完全跟 UEFI 标准兼容。

Windows 系统[编辑 | 编辑源代码]

64 位的 Windows 系统不支持在 32 位 UEFI 上启动。所以如果你在 UEFI 模式下启动了 32 位 Windows,那么你使用的是 32 位 UEFI。

可以通过运行 msinfo32.exe来查看系统位数。请看 系统摘要 条目下“系统类型”和“BIOS模式”对应的值。

如果是 64 位 UEFI 上的 64 位 Windows,则会有 系统类型:基于x64的电脑BIOS 模式:UEFI ;如果是 32 位 UEFI 上的 32 位 Windows,则会有 系统类型:基于x86的电脑BIOS 模式:UEFI.如果“BIOS”模式不是 UEFI ,那么 Windows 并没有用 UEFI 模式启动.

Linux 内核中有关 UEFI 的配置选项[编辑 | 编辑源代码]

UEFI 系统所要求的 Linux 内核配置选项[1]如下:

CONFIG_RELOCATABLE=y
CONFIG_EFI=y
CONFIG_EFI_STUB=y
CONFIG_X86_SYSFB=y
CONFIG_FB_SIMPLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y

UEFI 运行时变量支持(efivarfs 文件系统 —— /sys/firmware/efi/efivars)。该选项十分重要,因为它是使用如 /usr/bin/efibootmgr 的工具操作 UEFI 运行时变量所必须的。下面的选项已添加进了 3.10 及更新版本的内核中。

CONFIG_EFIVAR_FS=y

UEFI 运行时变量支持(老式 efivars sysfs 接口 —— /sys/firmware/efi/vars))。应当禁用该选项来避免同时启用 efivarfs 和 sysfs-efivars 所导致的潜在问题。

CONFIG_EFI_VARS=n

GUID 分区表 (GPT) 配置选项 —— UEFI 支持的强制需求

CONFIG_EFI_PARTITION=y

EFI 混合模式支持 —— 在 IA32 UEFI 上启动 x86_64 内核。

CONFIG_EFI_MIXED=y
注意: 以上所有选项都已在官方支持的内核中设置。

UEFI 变量[编辑 | 编辑源代码]

UEFI 定义了变量,通过它们操作系统可以与固件进行交互。 UEFI 引导变量只在早期系统启动时由引导加载程序和操作系统使用。UEFI运行时变量允许操作系统来管理固件的某些设置(如UEFI引导管理器)或 UEFI Secure Boot 协议的密钥。你可通过下面的命令来获得变量列表:

$ efivar -l

Linux 内核中的 UEFI 变量支持[编辑 | 编辑源代码]

Linux 内核通过两个接口来把 EFI 变量数据传递给用户空间:

  • 老式 sysfs-efivars 接口 (CONFIG_EFI_VARS) - 由位于 /sys/firmware/efi/vars 的内核模块 efivars 生成 - 每个变量数据最大大小为1024B, 不支持 UEFI Secure Boot 变量(由于大小限制),并再也不被上游推荐使用。现仍被上游支持但在 Arch 官方内核中已完全禁用
  • 新式 efivarfs (EFI VARiable FileSystem) 接口 (CONFIG_EFIVAR_FS) - 由位于 /sys/firmware/efi/efivarsefivarfs 内核模块挂载使用 - 老式 sysfs-efivars 接口的替代品,不限制变量数据大小,支持 UEFI Secure Boot 变量并被上游推荐使用。在3.8版的内核中引入,新的 efivarfs 模块在3.10版内核中从旧的 efivars 内核模块中分离。

efivarfs 和 sysfs-efivars 的不一致[编辑 | 编辑源代码]

同时启用老式的 sysfs-efivars 和新式的 efivarfs 会导致数据不一致的问题(更多信息见 https://lore.kernel.org/lkml/1366148520-29954-4-git-send-email-matt@console-pimps.org/ )。由于(自从 core/linux-3.11core/linux-lts-3.10)老式的 sysfs-efivars 在 Arch 官方内核中已完全禁用,新式的 efivarfs 将会被继续地启用/支持下去。自2013年10月1日起,在官方源中所有与 UEFI 变量相关的工具都支持 efivarfs.

注意: 作为禁用老式 sysfs-efivars 的副作用,efi_pstore 在 Arch 官方内核中也被禁用,因为 EFI pstore 功能依赖老式 sysfs-efivars 支持。

如果在使用任何用户空间工具访问 EFI VAR 数据前你同时开启了这两者,请禁用其中之一并重新开启另一个接口 (为了刷新数据和防止不一致) :

禁用 sysfs-efivars 并刷新 efivarfs:

# modprobe -r efivars

# umount /sys/firmware/efi/efivars
# modprobe -r efivarfs

# modprobe efivarfs
# mount -t efivarfs efivarfs /sys/firmware/efi/efivars

禁用 efivarfs 并刷新 sysfs-efivars:

# umount /sys/firmware/efi/efivars
# modprobe -r efivarfs

# modprobe -r efivars
# modprobe efivars

UEFI 变量正常工作的需求[编辑 | 编辑源代码]

  1. 内核处理器的位数应该与 EFI 处理器的位数相符。
  2. 内核应以 EFI 模式(通过 EFISTUBEFI 引导器,而不是 BIOS/CSM 或者同为 BIOS/CSM 的"bootcamp")启动。
  3. EFI 运行时服务支持应出现在内核中 (CONFIG_EFI=y, 运行 zgrep CONFIG_EFI /proc/config.gz 来核对是否共存 ).
  4. EFI 运行时服务在内核命令行中不应被禁用,即不应使用内核参数 noefi.
  5. efivarfs 文件系统应被挂载在 /sys/firmware/efi/efivars, 否则参考下文 #挂载 efivarfs 部分。
  6. efivar 应无错列出 (选项 -l) EFI 变量。参见输出内容 #UEFI 变量.

如果 EFI 变量支持在满足以上条件后仍有问题,尝试以下解决方案:

  1. 如果所有的用户空间工具都不能修改 EFI 变量数据,检查 /sys/firmware/efi/efivars/dump-* 文件是否存在。如果是,删掉,重启,再试一次。
  2. 如果上面的步骤没有解决问题,尝试以内核参数 efi_no_storage_paranoia 启动以禁用内核 EFI 变量存储空间来防止对 EFI 变量的写入/修改。
注意: efi_no_storage_paranoia 仅当需要时使用且不应留下作为正常启动参数。该内核参数的效果是关闭正在实施的安全保护,来避免 NVRAM 过满时机器故障。

挂载 efivarfs[编辑 | 编辑源代码]

如果 efivarfs 启动时并没有被 systemd 自动挂载在 /sys/firmware/efi/efivars, 你需要手动挂载来把 EFI 变量支持传递给像 efibootmgr 等的用户空间工具:

# mount -t efivarfs efivarfs /sys/firmware/efi/efivars
注意: 这个命令即使要运行的话也要在 chroot 之外(之前)和之内都运行一次。

如下通过 /etc/fstab 来自动挂载 efivarfs 也是极好的:

/etc/fstab
efivarfs    /sys/firmware/efi/efivars    efivarfs    defaults    0    0

用户空间工具[编辑 | 编辑源代码]

只有少量工具能够访问/修改 UEFI 变量,即

  • efivar — 操作 UEFI 变量的库和工具 (被 efibootmgr 用到)
https://github.com/vathpela/efivar || efivar,efivar-gitAUR
  • efibootmgr — 操作 UEFI 固件启动管理器设置的工具
https://github.com/rhboot/efibootmgr || efibootmgr
  1. uefivars — 转储 UEFI 变量和 PCI 相关信息 (内部使用 efibootmgr 源码)
https://github.com/fpmurphy/Various/tree/master/uefivars-2.0 || uefivars-gitAUR
  1. efitools — 创建与设置自己的 UEFI Secure Boot 证书,密钥和签名过的程序的工具 (需要 efivarfs)
https://git.kernel.org/cgit/linux/kernel/git/jejb/efitools.git || efitools-gitAUR
  1. Ubuntu的固件测试套件 — 固件检查工具
https://wiki.ubuntu.com/FirmwareTestSuite/ || fwts-gitAUR

efibootmgr[编辑 | 编辑源代码]

注意:
  • 如果 efibootmgr 完全无效,你可以重启进入 UEFI Shell 使用 bcfg 命令来给引导器创建一个启动条目。
  • 如果你不能使用 efibootmgr, 某些 UEFI 固件允许用户用内建的启动时界面管理启动条目。例如,某些华硕机有 "Add New Boot Option" 选项,能让你选择本地 EFI 系统分区并手动进入 EFI 存根位置 (例如 \EFI\refind\refind_x64.efi).
  • 下面的命令用 rEFInd 引导器作为例子。

要通过 efibootmgr 添加新的启动参数,需要确认:

  1. 包含 ESP 的磁盘编号: /dev/sdX
  2. ESP 在第几个分区 /dev/sdXY 中的 Y
  3. UEFI 程序相对 ESP 根目录的路径

假设要启动的引导器文件是 /boot/efi/EFI/refind/refind_x64.efi,/boot/efi 是 ESP 的挂载目录

$ findmnt /boot/efi
TARGET SOURCE  FSTYPE OPTIONS
/boot/efi /dev/sda1  vfat   rw,flush,tz=UTC

上面结果说明 ESP 位于 /dev/sda,分区编号是 1. UEFI 程序相对于 ESP 根的路径是/EFI/refind/refind_x64.efi. 应该用下面 efibootmgr 语句创建:

# efibootmgr --create --disk /dev/sda --part 1 --loader /EFI/refind/refind_x64.efi --label "rEFInd Boot Manager"

参考efibootmgr(8)efibootmgr README

注意: UEFI 使用反斜杠 \ 作为路径分隔符 (类似于 Windows 路径),Efibootmgr 解析路径之前内部会把 / 转换为 \.

UEFI Shell[编辑 | 编辑源代码]

UEFI Shell 是固件的终端,可用于启动包括引导器的 UEFI 程序。除此之外, Shell也可用于采集固件和系统的各种信息,例如内存映射 (memmap), 修改启动管理器变量 (bcfg), 运行分区程序 (diskpart), 加载 UEFI 驱动,编辑文本文件 (edit), 十六进制编辑等等。

获取 UEFI Shell[编辑 | 编辑源代码]

你可从 Intel 的 Tianocore UDK/EDK2 Sourceforge.net 工程下载以 BSD 许可证发布的 UEFI Shell.

Shell v2 在 UEFI 2.3+ 系统上表现最好,并比 Shell v1 优先推荐。Shell v1 应该在所有 UEFI 系统上有效并且与它们遵循的 UEFI 标准版本无关。更多信息见 ShellPkg

启动 UEFI Shell[编辑 | 编辑源代码]

部分基于 AMI Aptio x86_64 UEFI 固件的主板 (从 Sandy Bridge 起,尤其是华硕) 提供了一个叫做 "Launch EFI Shell from filesystem device" 的选项。对于这些主板,下载 x86_64 UEFI Shell ,复制进 EFI 系统分区,命名为 <EFI_SYSTEM_PARTITION>/shellx64.efi (大部分是 /boot/efi/shellx64.efi) .

Phoenix SecureCore Tiano UEFI 固件已内嵌 UEFI Shell, 可按 F6, F11F12 键来启动。

注意: 如果你用以上方法不能启动 UEFI Shell, 创建一个 FAT32 格式的 USB 并把 Shell.efi 复制到 (USB)/efi/boot/bootx64.efi. 这个 USB 会出现在固件的启动菜单里。启动它就会启动到 UEFI Shell.

重要 UEFI Shell 命令[编辑 | 编辑源代码]

UEFI Shell 命令通常支持 -b 选项,它在输出的每页末尾暂停. 运行 help -b 来列出所有可用命令。

更多信息见 https://software.intel.com/en-us/articles/efi-shells-and-scripting/

bcfg[编辑 | 编辑源代码]

bcfg 命令用于修改 UEFI NVRAM 条目,它能让用户改变启动条目或驱动器选项。在[https://www.uefi.org/sites/default/files/resources/UEFI_Shell_Spec_2_0.pdf

UEFI Shell Specification 2.0] PDF 文档的 83 页(Section 5.3) 有详细说明。
注意:
  • 仅当 efibootmgr 无法创建启动条目时才推荐尝试 bcfg.
  • UEFI Shell v1 官方二进制文件不支持 bcfg 命令。你可以下载一个 modified UEFI Shell v2 二进制文件[失效链接 2020-08-06 ⓘ],它在 UEFI 2.3前的固件有效。

转储当前启动条目:

Shell> bcfg boot dump -v

为 rEFInd (作为例子) 添加一个启动菜单条目,在启动菜单里是第4个 (从0开始计数) 选项:

Shell> bcfg boot add 3 fs0:\EFI\refind\refind_x64.efi "rEFInd"

fs0: 映射到 EFI 系统分区,fs0:\EFI\refind\refind_x64.efi i是要启动的文件。

To add an entry to boot directly into your system without a bootloader, configure a boot option using your kernel as an EFISTUB}:

Shell> bcfg boot add N fsV:\vmlinuz-linux "Arch Linux"	
Shell> bcfg boot -opt N "root=/dev/sdX# initrd=\initramfs-linux.img"

where N is the priority, V is the volume number of your EFI partition, and /dev/sdX# is your root partition.

删除第4个启动选项:

Shell> bcfg boot rm 3

把第3个启动选项移动到第0 (也就是说第1个是 UEFI 启动菜单的默认启动选项):

Shell> bcfg boot mv 3 0

bcfg 帮助文档:

Shell> help bcfg -v -b

或:

Shell> bcfg -? -v -b

map[编辑 | 编辑源代码]

map displays a list of device mappings i.e. the names of available file systems (fs0) and storage devices (blk0).

Before running file system commands such as cd or ls, you need to change the shell to the appropriate file system by typing its name:

 Shell> fs0:
 fs0:\> cd EFI/

edit[编辑 | 编辑源代码]

EDIT 命令提供了类似于 nano 界面的基本编辑器,但是功能略少一点。它以 UTF-8 编码并且行尾结束符兼容 LF 和 CRLF.

本例中,编辑在固件 EFI 系统分区 (fs0: 中 rEFInd 的 refind.conf

 Shell> edit FS0:\EFI\refind\refind.conf

输入 Ctrl-E 以获得帮助。

UEFI 可启动介质[编辑 | 编辑源代码]

从 ISO 创建 UEFI 可启动 USB[编辑 | 编辑源代码]

教程见 USB flash installation medium#Using the ISO as is (BIOS and UEFI).

从光学介质里移除 UEFI 启动支持[编辑 | 编辑源代码]

注意: 本部分提及的是给 CD/DVD only (光学介质)而不是 USB 闪存移除 UEFI 启动支持。

大部分32位 EFI Mac 机和部分64位 EFI Mac 机无法从 UEFI(X64)+BIOS 可启动 CD/DVD 启动。如果希望使用光学介质完成安装,可能首先需要移除 UEFI 启动支持。

  • 挂载官方安装介质并如前所述获取 archisolabel .
# mount -o loop input.iso /mnt/iso
  • 然后重建 ISO, 使用 libisoburnxorriso 移除 UEFI 光学介质启动支持。确认已设置正确的 archisolabel, 例如 "ARCH_201411"或类似的:
$ xorriso -as mkisofs -iso-level 3 \
    -full-iso9660-filenames\
    -volid "archisolabel" \
    -appid "Arch Linux CD" \
    -publisher "Arch Linux <https://archlinux.org>" \
    -preparer "prepared by $USER" \
    -eltorito-boot isolinux/isolinux.bin \
    -eltorito-catalog isolinux/boot.cat \
    -no-emul-boot -boot-load-size 4 -boot-info-table \
    -isohybrid-mbr "/mnt/iso/isolinux/isohdpfx.bin" \
    -output output.iso /mnt/iso/
  • output.iso 烧制进光学介质并照常完成安装。

原生无支持情况下测试 UEFI[编辑 | 编辑源代码]

虚拟机使用 OVMF[编辑 | 编辑源代码]

OVMF 是一个将 UEFI 添加到虚拟机的 tianocore 项目。OVMF 包含了一个 QEMU 使用的示例 UEFI 固件。

安装 edk2-ovmf.

建议先将虚拟机的非易逝变量本地保存一份。

$ cp /usr/share/ovmf/ovmf_vars_x64.bin my_uefi_vars.bin

然后在 QEME 命令中加入:

-drive if=pflash,format=raw,readonly,file=/usr/share/ovmf/ovmf_code_x64.bin \
-drive if=pflash,format=raw,file=my_uefi_vars.bin

示例:

 $ qemu-system-x86_64 -enable-kvm -m 1G -drive if=pflash,format=raw,readonly,file=/usr/share/ovmf/ovmf_code_x64.bin -drive if=pflash,format=raw,file=efi_vars.bin …

仅 BIOS 的系统使用 DUET[编辑 | 编辑源代码]

DUET 是一个 tianocore 工程用以从 BIOS 启动到完整 UEFI 环境,这与 BIOS 启动操作系统相似。在 https://www.insanelymac.com/forum/topic/186440-linux-and-windows-uefi-boot-using-tianocore-duet-firmware/ 里有广泛讨论。预建立的 DUET 镜像可从其中一个源 https://gitorious.org/tianocore_uefi_duet_builds[失效链接 2020-08-06 ⓘ] 下载。教程见 https://gitorious.org/tianocore_uefi_duet_builds/tianocore_uefi_duet_installer/blobs/raw/master/Migle_BootDuet_INSTALL.txt[失效链接 2020-08-06 ⓘ].

也可考虑 https://sourceforge.net/projects/cloverefiboot/ , 它提供的 DUET 镜像可能包含了一些系统的专用补丁,并且比 gitorious 源更新得更频繁。

疑难问题[编辑 | 编辑源代码]

困在 Windows 时启动到 Arch Linux[编辑 | 编辑源代码]

当被困在 Windows 时,要启动到 Arch Linux,可以通过 Windows PowerShell 命令 shutdown /r /o 或者通过设置 > 更新与安全 > 恢复 > 高级启动,选择现在重启 到达 Windows 的高级启动。当你到达高级启动菜单时,选择使用设备,这个菜单实际上包含你的 UEFI 启动选项(不限于 USB 或 CD,也可以启动硬盘中的操作系统),并选择“Arch Linux”。

Windows 7 无法以 UEFI 模式启动[编辑 | 编辑源代码]

如果你把 Windows 安装进了另一个 GPT 格式的硬盘并且你电脑里还有一个 MBR 格式的硬盘,那么可能 UEFI 固件启动了 CSM 支持(为从 MBR 分区启动的支持) 因而 Windows 无法启动。为解决问题,把 MBR 硬盘的内容合并到 GPT 硬盘中并禁用 MBR 硬盘使用的 SATA 接口或者直接把硬盘拔下来。

有此类问题的主板:

Gigabyte Z77X-UD3H rev. 1.1 (UEFI 版本 F19e)

- 固件启动选项 "UEFI Only" 并不妨碍以 CSM 启动。

Windows 改变了启动次序[编辑 | 编辑源代码]

例如你升级 Windows 后直接启动了Windows而不是选择启动菜单:

  • 确定UEFI固件设置中的"安全启动"(Secure Boot) 和 Windows 中的"快速启动" 选项没有启用.
  • 确定UEFI固件设置的启动顺序中Linux Boot Manager 先于 Windows Boot Manager.
注意: Windows 8.x+,和 Windows 10,可能会覆盖你在UEFI固件设置中设置的启动顺序并把自己设置成第一启动选项. 所以你应该知道如何修改"一次性启动选项".

你可以通过组策略和一个批处理文件(".bat")来阻止Windows更改启动设置,在Windows上这样做:

  1. 以管理员身份打开命令提示符,运行 bcdedit /enum firmware
  2. 寻找描述中带有"linux"的启动选项,例如 "Linux Boot Manager"
  3. 复制带大括号的描述符, 例如 {31d0d5f4-22ad-11e5-b30b-806e6f6e6963}
  4. 创建一个批处理文件 (例如 bootorder.bat) ,包含下列的内容: bcdedit /set {fwbootmgr} DEFAULT {这里是你在第三步中获得的描述符} (例如 bcdedit /set {fwbootmgr} DEFAULT {31d0d5f4-22ad-11e5-b30b-806e6f6e6963}).
  5. 运行 gpedit (组策略对象编辑器)本地计算机策略 > 计算机设置 > Windows 设置 > 脚本(启动/关机)中,选择"启动,会打开一个名为"启动选项:的对话框.
  6. 添加第四步中创建的批处理文件到"脚本"列表中.

或者让Windows 启动管理器加载systemd-boot的EFI应用程序,要这样做的话在Windows上以管理员身份运行:

bcdedit /set {bootmgr} path \EFI\systemd\systemd-bootx64.efi

USB 介质卡在黑屏界面[编辑 | 编辑源代码]

可能是 KMS 的问题。从 USB 启动时尝试 Disabling KMS.

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