EFI 系统分区
EFI 系统分区(也称为 ESP)是一个操作系统独立的分区,作为 UEFI 固件启动的 UEFI 启动加载器、应用程序和驱动程序的存储位置。 对于 UEFI 启动,它是强制性的。
检查现有分区
如果您正在具有已安装操作系统的支持 UEFI 的计算机上安装 Arch Linux,例如Windows 10,则很可能您已经拥有 EFI 系统分区。
要找出磁盘分区方案和系统分区,请以 root 身份在要从中启动的磁盘上使用 fdisk
# fdisk -l /dev/sdx
该命令返回
- 磁盘的分区表:如果分区表是 GPT,则指示
Disklabel type: gpt
;如果是 MBR,则指示Disklabel type: dos
。 - 磁盘上的分区列表:在列表中查找 EFI 系统分区,它通常至少为 100 MiB 大小,类型为
EFI System
或EFI (FAT-12/16/32)
。 要确认这是 ESP,挂载它并检查它是否包含名为EFI
的目录,如果包含,则这肯定是 ESP。
如果您找到了可接受的现有 EFI 系统分区,只需继续#挂载分区。 如果您没有找到,则需要创建它,请继续#创建分区。
创建分区
以下两节介绍了如何创建 EFI 系统分区 (ESP)。
分区大小应为存储引导加载程序和其他启动所需的文件提供足够的空间。
建议将分区大小设置为 1 GiB,以确保它有足够的空间容纳多个内核或统一内核映像、启动加载程序、固件更新文件以及任何其他操作系统或 OEM 文件。 如果仍然不确定,4 GiB 应该足够任何人使用,例如,对于像 Limine 引导加载器与 Snapper 集成以用于 Btrfs 这样的工具,它支持创建多个可启动快照。
- 对于早期和/或有缺陷的 UEFI 实现,可能需要至少 512 MiB 的大小。[1]
- 如果您计划将分区挂载到 /boot 并且不安装多个内核,则 400 MiB 就足够了。
- 当与 Windows 双启动时,对于逻辑扇区大小为 4096 的驱动器(高级格式 4Kn 驱动器),大小应至少为 300 MiB[2],否则至少为 100 MiB。[3]
- 为了确保分区可以格式化为 FAT32,在逻辑扇区大小为 512 字节的驱动器上,它应至少为 36 MiB,在逻辑扇区大小为 4096 的驱动器上,它应至少为 260 MiB。[4]
- 如果这些都不是相关问题,则分区大小可以小至 2 MiB,在这种情况下,它只能容纳一个引导加载程序。
GPT 分区磁盘
在 GUID 分区表上的 EFI 系统分区由分区类型 GUID C12A7328-F81F-11D2-BA4B-00A0C93EC93B
标识。
选择以下方法之一来为 GPT 分区磁盘创建 ESP
- fdisk:创建一个分区,并使用
t
命令更改其分区类型为EFI System
,别名为uefi
。 - gdisk:创建分区类型为
EF00
的分区。 - GNU Parted:创建一个文件系统类型为
fat32
的分区,并在其上设置esp
标志。
创建分区后,应使用文件系统对其进行格式化。 继续执行下面的#格式化分区部分。
MBR 分区磁盘
- 由于 Windows 安装程序 不支持,某些固件可能不支持 UEFI/MBR 启动。
- bootctl 不支持将 systemd-boot 安装到 MBR 分区磁盘; 请参阅 systemd 问题 1125。
另请参阅 分区#在 GPT 和 MBR 之间选择,了解 MBR 的限制和 GPT 的一般优势。
在 主启动记录分区表上的 EFI 系统分区由分区类型 ID EF
标识。
选择以下方法之一来为 MBR 分区磁盘创建 ESP
- fdisk:创建一个主分区,并使用
t
命令更改其分区类型为EFI (FAT-12/16/32)
。 - GNU Parted:创建一个文件系统类型为
fat32
的主分区,并在其上设置esp
标志。
创建分区后,应使用文件系统对其进行格式化。 继续执行下面的#格式化分区部分。
格式化分区
UEFI 规范强制要求支持 FAT12、FAT16 和 FAT32 文件系统(请参阅UEFI 规范版本 2.10,第 13.3.1.1 节),但任何符合规范的供应商都可以选择添加对其他文件系统的支持; 例如,Apple Mac 中的固件支持 HFS+ 文件系统。
为了防止与其他操作系统潜在的问题,并且由于 UEFI 规范指出 UEFI“包含系统分区使用 FAT32,可移动媒体使用 FAT12 或 FAT16”[5],建议使用 FAT32。 使用来自 dosfstools 的 mkfs.fat(8) 实用程序
# mkfs.fat -F 32 /dev/sdxY
如果您收到消息 WARNING: Not enough clusters for a 32 bit FAT!
并且您无法创建更大的 ESP,请使用 mkfs.fat -s2 -F32 ...
或 -s1
减小簇大小; 否则,UEFI 可能无法读取该分区。 有关支持的簇大小,请参阅 mkfs.fat(8)。
对于小于 32 MiB 的分区,可能无法使用 FAT32。 在这种情况下,将其格式化为 FAT16 甚至 FAT12。 例如,2 MiB ESP 只能支持 FAT12
# mkfs.fat -F 12 /dev/sdxY
挂载分区
内核、initramfs 文件以及在大多数情况下处理器 微码 需要可被 引导加载程序 或 UEFI 本身访问,才能成功启动系统。 因此,如果您想保持设置简单,您的引导加载程序选择会限制 EFI 系统分区的可用挂载点。
/boot
,请确保不要依赖 systemd 自动挂载机制(包括 systemd-gpt-auto-generator 的机制)在内核升级期间。 始终在任何系统或内核更新之前手动挂载它,否则您可能在更新后无法挂载它,从而将您锁定在当前正在运行的内核中,无法更新 ESP 上的内核副本。或者,在启动时预加载所需的内核模块,例如
/etc/modules-load.d/vfat.conf
vfat nls_cp437 nls_ascii
典型的挂载点
挂载 EFI 系统分区的三个典型场景是
- 挂载 ESP 到
/boot
- 这有助于系统维护和管理,因为
/boot
是微码软件包放置 CPU 微码 initramfs 文件以及 mkinitcpio 放置 内核 和 initramfs 镜像的默认路径。 - 这确保了大多数 引导加载程序 可以访问上述文件,因为并非所有引导加载程序都可以访问其他卷上的文件。
- 这阻止了设置特定于文件的 权限 和/或 扩展属性,因为 FAT 在挂载时设置全局权限
- 这增加了 ESP 的大小要求,因为通常安装在
/boot
中的文件将加入与 EFI 相关的文件。 - 在双启动的情况下,这会将特定于操作系统的引导文件暴露于来自其他操作系统的潜在危险操作。
- 这使得加密 /boot 变得不可能,因为 EFI 相关文件必须可被固件访问。
- 这有助于系统维护和管理,因为
- 挂载 ESP 到
/efi
- 它确保了操作系统相关文件和 EFI 相关文件之间的关注点分离,其中可能包括其他操作系统的文件,最好不要管它们。
- 它避免了通过不将安装到
/boot
的文件放置在其中来增加 ESP 的大小要求:只有 EFI 二进制文件(引导加载程序(和可选的驱动程序)和/或统一内核映像)将存储在 ESP 上,从而节省存储空间。 - 它允许为驻留在
/boot
中的文件保留特定于 Linux 的文件系统权限,从而避免 FAT 限制。 - 它允许根据需要单独挂载 ESP,例如,仅在升级引导加载程序时。
- 如果使用系统加密并进行适当的设置,它允许仅保留少量必需的文件未加密,而
/boot
保持受保护状态:这对于统一内核映像或引导加载程序可能很有用,这些引导加载程序具有文件系统驱动程序,能够访问存储在其他位置的内核和文件。
- 挂载 ESP 到
/efi
,并额外挂载一个“扩展引导加载程序分区”(XBOOTLDR) 到/boot
。 当先前创建的 ESP 太小而无法容纳多个引导加载程序和/或内核,但 ESP 无法轻松调整大小时(例如,在 Windows 之后安装 Linux 以进行 双启动 时),这可能很有用。 至少 systemd-boot 支持此方法。
其他的挂载点
如果您不使用#典型的挂载点之一,您将需要将引导文件复制到 ESP(以下简称 esp
)。
# mkdir -p esp/EFI/arch # cp -a /boot/vmlinuz-linux esp/EFI/arch/ # cp -a /boot/initramfs-linux.img esp/EFI/arch/ # cp -a /boot/initramfs-linux-fallback.img esp/EFI/arch/
此外,您需要使 ESP 上的文件与后续内核更新保持同步。 否则可能会导致系统无法启动。 以下各节讨论了用于自动化它的几种机制。
使用绑定挂载
您可以不将 ESP 本身挂载到 /boot
,而是使用绑定 挂载(参见 mount(8))将 ESP 的目录挂载到 /boot
。 这允许 pacman 直接更新内核,同时保持 ESP 有序。
/boot/
中需要符号链接的发行版)来说,这可能是个问题。 请参阅论坛帖子 [8]。就像在#其他的挂载点中一样,将所有引导文件复制到 ESP 上的目录,但将 ESP 挂载到 /boot
之外。 然后绑定挂载目录
# mount --bind esp/EFI/arch /boot
验证成功后,编辑您的 Fstab 以使更改持久化
/etc/fstab
esp/EFI/arch /boot none defaults,bind 0 0
使用 systemd
Systemd 具有事件触发的任务。 在这种特殊情况下,当 EFISTUB 内核和 initramfs 文件在 /boot/
中更新时,检测路径更改的能力用于同步它们。 监视更改的文件是 initramfs-linux-fallback.img
,因为这是 mkinitcpio 构建的最后一个文件,以确保在启动复制之前已构建所有文件。 要创建的 systemd 路径和服务文件是
/etc/systemd/system/efistub-update.path
[Unit] Description=Copy EFISTUB Kernel to EFI system partition [Path] PathChanged=/boot/initramfs-linux-fallback.img [Install] WantedBy=multi-user.target WantedBy=system-update.target
/etc/systemd/system/efistub-update.service
[Unit] Description=Copy EFISTUB Kernel to EFI system partition [Service] Type=oneshot ExecStart=/usr/bin/cp -af /boot/vmlinuz-linux esp/EFI/arch/ ExecStart=/usr/bin/cp -af /boot/initramfs-linux.img esp/EFI/arch/ ExecStart=/usr/bin/cp -af /boot/initramfs-linux-fallback.img esp/EFI/arch/
然后 启用 并 启动 efistub-update.path
。
ExecStart=/usr/bin/sbsign --key /path/to/db.key --cert /path/to/db.crt --output esp/EFI/arch/vmlinuz-linux /boot/vmlinuz-linux
使用文件系统事件
文件系统事件 可用于在内核更新后运行脚本以同步 EFISTUB 内核。 以下是使用 incron 的示例。
/usr/local/bin/efistub-update
#!/bin/sh cp -af /boot/vmlinuz-linux esp/EFI/arch/ cp -af /boot/initramfs-linux.img esp/EFI/arch/ cp -af /boot/initramfs-linux-fallback.img esp/EFI/arch/
/boot/initramfs-linux-fallback.img
是要监视的文件。 第二个参数 IN_CLOSE_WRITE
是要监视的操作。 第三个参数 /usr/local/bin/efistub-update
是要执行的脚本。/etc/incron.d/efistub-update.conf
/boot/initramfs-linux-fallback.img IN_CLOSE_WRITE /usr/local/bin/efistub-update
为了使用此方法,启用 incrond.service
。
使用 mkinitcpio 预设
由于 /etc/mkinitcpio.d/
中的预设支持 shell 脚本,因此只需编辑预设即可复制内核和 initramfs。
替换 mkinitcpio 钩子
编辑文件 /etc/mkinitcpio.d/linux.preset
/etc/mkinitcpio.d/linux.preset
# mkinitcpio preset file for the 'linux' package # Directory to install the kernel, the initramfs... ESP_DIR="esp/EFI/arch" #ALL_config="/etc/mkinitcpio.conf" ALL_kver="${ESP_DIR}/vmlinuz-linux" PRESETS=('default' 'fallback') #default_config="/etc/mkinitcpio.conf" default_image="${ESP_DIR}/initramfs-linux.img" default_options="" #fallback_config="/etc/mkinitcpio.conf" fallback_image="${ESP_DIR}/initramfs-linux-fallback.img" fallback_options="-S autodetect"
要测试,只需运行
# rm /boot/initramfs-linux-fallback.img /boot/initramfs-linux.img # mv /boot/vmlinuz-linux esp/EFI/arch/ # mkinitcpio -p linux
另一个例子
/etc/mkinitcpio.d/linux.preset
ESP_DIR="esp/EFI/arch" #ALL_config="/etc/mkinitcpio.conf" ALL_kver="$ESP_DIR/vmlinuz-linux$suffix" PRESETS=('default') default_config="/etc/mkinitcpio.conf" default_image="$ESP_DIR/initramfs-linux$suffix.img"
/etc/mkinitcpio.d/linux-zen.preset
suffix='-zen' source /etc/mkinitcpio.d/linux.preset
使用 mkinitcpio 后期钩子
mkinitcpio 后期钩子 可用于在生成 initramfs 后将内核和 initramfs 镜像复制到所需的目录。
/etc/initcpio/post/copy-kernel-and-initramfs
#!/usr/bin/env bash kernel="$1" initrd="$2" target_dir="esp/EFI/arch" files_to_copy=() for file in "$kernel" "$initrd"; do if [[ -n "$file" ]] && ! cmp -s -- "$file" "${target_dir}/${file##*/}"; then files_to_copy+=("$file") fi done (( ! ${#files_to_copy[@]} )) && exit 0 cp -af -- "${files_to_copy[@]}" "${target_dir}/"
使用 pacman 钩子
最后一个选项依赖于在事务结束时运行的 pacman 钩子。
第一个文件是一个监视相关文件的钩子,如果在之前的事务中修改了这些文件,则会运行它。
/etc/pacman.d/hooks/999-kernel-efi-copy.hook
[Trigger] Type = Path Operation = Install Operation = Upgrade Target = usr/lib/modules/*/vmlinuz Target = usr/lib/initcpio/* Target = boot/*-ucode.img [Action] Description = Copying linux and initramfs to EFI directory... When = PostTransaction Exec = /usr/local/bin/kernel-efi-copy.sh
第二个文件是脚本本身。 创建文件并使其可执行
/usr/local/bin/kernel-efi-copy.sh
#!/bin/sh # # Copy kernel and initramfs images to EFI directory # ESP_DIR="esp/EFI/arch" for file in /boot/vmlinuz* do cp -af "$file" "$ESP_DIR/$(basename "$file").efi" [ $? -ne 0 ] && exit 1 done for file in /boot/initramfs* do cp -af "$file" "$ESP_DIR/" [ $? -ne 0 ] && exit 1 done [ -e /boot/intel-ucode.img ] && cp -af /boot/intel-ucode.img "$ESP_DIR/" [ -e /boot/amd-ucode.img ] && cp -af /boot/amd-ucode.img "$ESP_DIR/" exit 0
技巧与诀窍
替换为更大的分区
在具有预先存在的操作系统的磁盘上,EFI 系统分区可能小于#创建分区中建议的大小。 例如,Windows 安装程序在非 4Kn 驱动器上创建了一个微不足道的 100 MiB EFI 系统分区。
在这种情况下,创建新的、更大的 EFI 系统分区可能是个好主意,以防止在其上空间不足。
在 Windows 中为新分区释放空间
在 Windows 中,可以使用磁盘管理 (diskmgmt.msc
) 以图形方式或从命令行使用 diskpart.exe
实用程序管理分区。
以管理员身份运行 diskmgmt.msc
。
- 右键单击“(C:)”分区(默认 Windows 创建的分区中唯一可以在线调整大小的分区),然后选择压缩卷...。
- 输入
4096
作为要压缩的量,然后单击压缩。
现在,“(C:)”分区之后应该有 4 GiB 的未分配空间。
启动进入 Arch Linux 或 Arch Linux 安装介质以继续创建新分区。
删除旧分区并创建新分区
首先,确保备份 EFI 系统分区的内容。 例如,esp 是其挂载点
# cp -a esp /esp_backup
卸载 EFI 系统分区
# umount esp
运行 blkid 并记下 UUID 和 PARTUUID 值。 它们稍后将用于新分区。
# blkid
/dev/sdxY: UUID="XXXX-XXXX" BLOCK_SIZE="512" TYPE="vfat" PARTLABEL="EFI system partition" PARTUUID="YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY"
# sgdisk --delete=Y /dev/sdx
在最大的未分配空间中创建新分区,同时重用旧的 PARTUUID 和 PARTLABEL
# sgdisk --align-end --largest-new=0 --typecode=0:ef00 --change-name=0:'EFI system partition' --partition-guid=0:YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY /dev/sdx
通过使用 fdisk 列出分区来确认已创建新的、大小为 4 GiB 的 EFI 系统分区
# fdisk -l /dev/sdx
... Device Start End Sectors Size Type /dev/sdx1 158099456 166488063 8388608 4G EFI System /dev/sdx2 206848 239615 32768 16M Microsoft reserved /dev/sdx3 239616 158099455 157859840 75.3G Microsoft basic data /dev/sdx4 166488064 167768063 1280000 625M Windows recovery environment /dev/sdx5 167768064 176156671 8388608 4G Linux swap /dev/sdx6 176156672 243265535 67108864 32G Linux root (x86-64) Partition table entries are not in disk order.
分区号在删除和创建分区时不会重新排序,因此磁盘上的 EFI 系统分区号可能与以前相同。
将分区格式化为 FAT32,重用旧的 UUID(同时从中删除破折号)
# mkfs.fat -F 32 -i XXXXXXXX /dev/sdxY
最后,挂载新分区并从备份还原其内容
# mount /dev/sdxY esp # cp -a /esp_backup/. esp/
如果您之前停止了 esp.automount
,请启动它。
牺牲相邻的交换分区来扩大 ESP
如果交换分区紧跟在 EFI 系统分区之后,您可以牺牲它来为扩大 EFI 系统分区腾出空间。 例如,布局类似于
# fdisk -l /dev/sdx
... Device Start End Sectors Size Type /dev/sdx1 2048 616447 614400 300M EFI System /dev/sdx2 616448 9005055 8388608 4G Linux swap /dev/sdx3 9005056 125827071 116822016 55.7G Linux root (x86-64)
使用 fdisk 删除交换分区并扩大 EFI 系统分区。
- 运行
# fdisk -l /dev/sdx
- 使用
d
命令删除交换分区(在上面的示例布局中为分区号2
)。 - 使用
e
命令扩大 EFI 系统分区(在上面的示例布局中为分区号1
)。 使用建议的默认值作为新大小,然后按Enter
。 - 通过
w
命令将更改写入磁盘并退出。
调整分区大小后,您需要在其中调整文件系统的大小。 由于 fatresize(1) 不起作用,并且 libparted 无法调整某些大小的 FAT 卷大小,因此唯一的选择是从现有文件系统中备份文件并创建一个占用分区所有空间的新文件系统。
记下文件系统 UUID 以允许将其重用于新文件系统
$ lsblk -dno UUID /dev/sdxY
XXXX-XXXX
备份 EFI 系统分区的内容。 例如,esp 是其挂载点
# cp -a esp /esp_backup
卸载 EFI 系统分区
# umount esp
从分区中擦除文件系统签名,以避免旧文件系统中的任何伪影
# wipefs -af /dev/sdxY
将分区格式化为 FAT32,重用旧的 UUID(同时从中删除破折号)
# mkfs.fat -F 32 -i XXXXXXXX /dev/sdxY
最后,挂载新分区并从备份还原其内容
# mount /dev/sdxY esp # cp -a /esp_backup/. esp/
如果您之前停止了 esp.automount
,请启动它。
现在交换分区已消失,请在交换文件上设置交换空间。
故障排除
软件 RAID1 上的 ESP
可以使 ESP 成为 RAID1 阵列的一部分,但这样做会带来数据损坏的风险,并且在创建 ESP 时需要进一步考虑。 请参阅 [9] 和 [10] 了解详细信息,并参阅 UEFI 启动和 RAID1 了解包含解决方案的深入指南。
关键部分是使用 --metadata 1.0
以将 RAID 元数据保留在分区末尾,否则固件将无法访问它
# mdadm --create --verbose --level=1 --metadata=1.0 --raid-devices=2 /dev/md/ESP /dev/sdaX /dev/sdbY
或者,由于 ESP 不经常更新,因此可以在相关更新期间通过将主 ESP 复制到不同磁盘上的辅助 ESP 来管理辅助 ESP。 然后可以使用 efibootmgr 手动添加辅助 ESP 的启动项。 请参阅 debian wiki 以获取实现示例。 请注意,虽然这避免了 RAID 方法的一些风险,但它仅在使用单个操作系统时才有效。
固件无法识别 EFI 目录
如果您为 FAT 文件系统提供卷名(即文件系统标签),请确保将其命名为 EFI
以外的名称。 这可能会触发某些固件中的错误(由于卷名与 EFI 目录名匹配),这将导致固件的行为就像 EFI 目录不存在一样。