Arch Linux 配置记录:shim + systemd-boot + UKI + MOK
参考
关键流程
shim-signed 在 AUR,安装阶段必须关闭 Secure Boot。进入系统装好 AUR 包、签名、导入 MOK 后,再进固件开启。
本文使用:
- shim(AUR
shim-signed,微软签名的引导垫片) - systemd-boot(EFI 启动管理器)
- UKI(Unified Kernel Image,统一内核镜像)
- MOK(Machine Owner Key,机器所有者密钥)
- BTRFS(带子卷布局的快照能力)
没有使用:sbctl、GRUB、传统 vmlinuz + initramfs 分离式启动。
TL;DR
- SB 关 → 安装系统(BTRFS 子卷 + UKI + systemd-boot)→ 重启进桌面
- 装 AUR 的
shim-signed→ 生成 MOK key → 签名 systemd-boot 和 UKI mokutil --import→ 重启 → MokManager 确认 → 进固件开 SB → 完成- pacman hook 签名并部署 systemd-boot 的主启动和 fallback 副本,mkinitcpio post hook 签名 UKI
- BTRFS 快照用于根子卷回滚;涉及内核升级时,还需保留与快照匹配的 UKI
一、启动链
UEFI Secure Boot
→ shim (EFI/Arch/shimx64.efi,微软签名)
→ systemd-boot (EFI/Arch/grubx64.efi,MOK 签名)
→ UKI (EFI/Linux/arch-linux.efi,MOK 签名)UEFI 固件通过 db 中受信任的 Microsoft UEFI CA 验证 shim,shim 使用 MOK 验证 systemd-boot,随后 systemd-boot 通过 shim 提供的验证机制加载 UKI。固件需要信任签署该 shim 的第三方 UEFI CA。ArchWiki:使用已签名的引导器
shim 默认加载同目录下的 grubx64.efi,因此把 systemd-boot 的 EFI 二进制以这个名字放在 shim 旁边即可。这里的文件名沿用 shim 的约定,实际运行的是 systemd-boot。ArchWiki:设置 shim
主启动链放在 ESP 的 /EFI/Arch/ 中,fallback 副本放在 /EFI/BOOT/ 中。bootctl 只用于初次安装;切换到 shim 后,签名和部署由自定义脚本维护,避免更新机制相互覆盖(见 7.6 节和 8.1 节)。
shim 的镜像验证还涉及 EFI 加载接口以及 systemd-boot、systemd-stub 的实现,不能全部概括为
shim_lock协议。systemd-boot 源码、systemd-stub 源码
二、分区布局与 BTRFS 子卷
2.1 分区方案
| 分区 | 大小 | 类型 | 挂载点 | 用途 |
|---|---|---|---|---|
/dev/sdX1 | 1G | EFI System (vfat) | /efi | ESP |
/dev/sdX2 | 剩余 | BTRFS | / | 系统 + 数据 |
/dev/sdX3 | 16G+ | swap | — | 交换空间 |
本文命令中的设备路径请替换为你实际的磁盘。
2.2 创建 BTRFS 子卷
mkfs.btrfs -L arch /dev/sdX2
mount /dev/sdX2 /mnt
btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@home
btrfs subvolume create /mnt/@snapshots
umount /mnt子卷职责:
@— 根文件系统/@home— 用户数据/home,独立于系统快照@snapshots— 只读快照存放位置,挂载到/.snapshots
CachyOS 的完整子卷布局参考
| 子卷 | 挂载点 | 用途 |
|---|---|---|
@ | / | 根文件系统 |
@home | /home | 用户数据 |
@root | /root | root 用户家目录 |
@srv | /srv | 服务数据 |
@cache | /var/cache | 包缓存等可变缓存数据 |
@tmp | /var/tmp | 临时文件 |
@log | /var/log | 日志(隔离防止日志写满根分区) |
2.3 挂载
# 根子卷
mount -o subvol=/@ /dev/sdX2 /mnt
mkdir -p /mnt/{home,.snapshots,efi,boot}
# 用户数据
mount -o subvol=/@home /dev/sdX2 /mnt/home
# 快照目录
mount -o subvol=/@snapshots /dev/sdX2 /mnt/.snapshots
# ESP
mkfs.fat -F32 /dev/sdX1
mount /dev/sdX1 /mnt/efi三、安装基础系统
3.1 pacstrap
pacstrap -K /mnt base base-devel linux linux-firmware \
btrfs-progs intel-ucode \
networkmanager sudo vim zsh \
efibootmgr sbsigntools mokutil注意:
shim-signed在 AUR,不进 pacstrap。完整包列表见文末附录。
3.2 生成 fstab
genfstab -U /mnt >> /mnt/etc/fstab最终 fstab 示例:
# /dev/sdf2 LABEL=arch
UUID=c236f1be-cb6e-4555-884d-885e959130d3 / btrfs rw,noatime,compress=zstd:3,discard=async,space_cache=v2,subvol=/@ 0 0
# /dev/sdf2 LABEL=arch
UUID=c236f1be-cb6e-4555-884d-885e959130d3 /home btrfs rw,noatime,compress=zstd:3,discard=async,space_cache=v2,subvol=/@home 0 0
# /dev/sdf2 LABEL=arch
UUID=c236f1be-cb6e-4555-884d-885e959130d3 /.snapshots btrfs rw,noatime,compress=zstd:3,discard=async,space_cache=v2,subvol=/@snapshots 0 0
# /dev/sdf1
UUID=FB11-EED2 /efi vfat rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,errors=remount-ro 0 2
# /dev/sdf3
UUID=c40265f9-4bae-4619-a31f-59976d605b43 none swap defaults 0 0挂载参数说明:
| 参数 | 作用 |
|---|---|
noatime | 禁止访问时间戳更新,减少写入 |
compress=zstd:3 | 透明压缩,zstd level 3 兼顾速度与压缩比 |
discard=async | 异步 TRIM,对 SSD 友好 |
space_cache=v2 | BTRFS 第二版空间缓存,提升性能 |
subvol=/@ | 指定挂载的子卷 |
四、基础配置 (chroot)
arch-chroot /mnt4.1 时区、本地化、主机名
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
hwclock --systohc
# 编辑 /etc/locale.gen,取消 en_US.UTF-8 UTF-8 和 zh_CN.UTF-8 UTF-8 的注释
locale-gen
echo "LANG=en_US.UTF-8" > /etc/locale.conf
echo "archbox" > /etc/hostname4.2 用户与权限
passwd # 设置 root 密码
useradd -m -G wheel -s /bin/zsh yoimiya
passwd yoimiya # 设置用户密码
EDITOR=vim visudo # 取消 %wheel ALL=(ALL:ALL) ALL 的注释4.3 基础服务
systemctl enable NetworkManager bluetooth五、配置 UKI(统一内核镜像)
5.1 内核命令行
mkdir -p /etc/cmdline.d
cat > /etc/cmdline.d/root.conf <<'EOF'
rootdelay=5 root=UUID=c236f1be-cb6e-4555-884d-885e959130d3 rootflags=subvol=@ rw
EOFmkinitcpio 可读取 /etc/cmdline.d/*.conf,把参数嵌入 UKI。其默认查找顺序中,/etc/kernel/cmdline 和 /usr/lib/kernel/cmdline 优先于该目录;已有这些文件时,需要确认其中的参数与本节一致。示例 UUID 应替换为实际根分区的 UUID。mkinitcpio(8):UKI 选项
rootdelay=5:给 BTRFS 设备 5 秒就绪等待,因为这个示例是移动硬盘rootflags=subvol=@:指定根子卷- 如果需要
quiet或splash,可以追加
5.2 mkinitcpio 配置
确认 /etc/mkinitcpio.conf 中 HOOKS:
HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole block filesystems fsck)
systemdhook 用于 systemd-based initramfs;filesystems自动处理 BTRFS 多设备挂载等场景。
5.3 定制 preset 生成 UKI
编辑 /etc/mkinitcpio.d/linux.preset:
# linux.preset
ALL_kver="/boot/vmlinuz-linux"
PRESETS=('default')
default_uki="/efi/EFI/Linux/arch-linux.efi"
default_options="--splash /usr/share/systemd/bootctl/splash-arch.bmp"
default_uki指定 UKI 输出路径。systemd-boot 会自动扫描EFI/Linux/目录下的 EFI 文件作为启动项,无需手动写 loader entries。
生成 UKI(此时未签名):
mkinitcpio -p linux六、搭建 systemd-boot
6.1 安装
bootctl install这会把 systemd-boot 安装到 /efi/EFI/systemd/systemd-bootx64.efi 和 /efi/EFI/BOOT/BOOTx64.EFI(fallback)。
6.2 loader 配置
mkdir -p /efi/loader
cat > /efi/loader/loader.conf <<'EOF'
default @saved
timeout 3
console-mode keep
editor no
EOFdefault @saved:记住上次启动的选项timeout 3:3 秒选择超时editor no:禁止启动时编辑内核参数(安全考量)
UKI 放在 EFI/Linux/ 下 systemd-boot 自动发现,不需要手写 /efi/loader/entries/*.conf。
初次安装使用 6.1 节的 bootctl install,在 Secure Boot 关闭时完成首次启动。切换到独立的 shim 启动链后,实际引导文件按 8.1 节更新。
6.3 退出 chroot、重启进桌面
exit
umount -R /mnt
reboot # SB 保持关闭,先进桌面七、进桌面后:Secure Boot 配置
此时 Secure Boot 仍然是关闭的。
7.1 安装 shim-signed (AUR)
paru -S shim-signed7.2 信任链概览
| 组件 | ESP 路径 | 签名者 | 信任来源 |
|---|---|---|---|
| shim | EFI/Arch/shimx64.efi | Microsoft | UEFI 固件的 db |
| systemd-boot | EFI/Arch/grubx64.efi | MOK | shim |
| UKI | EFI/Linux/arch-linux.efi | MOK | shim 提供的验证机制 |
7.3 生成 MOK 密钥对
cd ~
openssl req -newkey rsa:4096 -nodes -keyout MOK.key \
-new -x509 -sha256 -days 3650 \
-subj "/CN=my Machine Owner Key/" \
-out MOK.crt
# Export the DER certificate for MokManager.
openssl x509 -outform DER -in MOK.crt -out MOK.cer保护私钥:
sudo mkdir -p /etc/ssl/private/secure_boot
sudo cp MOK.key MOK.crt /etc/ssl/private/secure_boot/
sudo chown root:root /etc/ssl/private/secure_boot/*
sudo chmod 400 /etc/ssl/private/secure_boot/MOK.key妥善离线备份私钥和证书。自动签名使用的私钥应仅允许 root 读取;生成时留在用户家目录中的私钥也需要保护,完成备份和部署后移除不必要的副本。私钥不可复制到 ESP 或提交到 Git 仓库。丢失私钥后,将无法继续用这套密钥签署新的 UKI。
7.4 摆放 shim、签名、创建 EFI 启动项
安装 shim-signed 并生成 MOK 密钥后,把主启动链部署到 /EFI/Arch/,同时在 /EFI/BOOT/ 保留可移动磁盘的 fallback 入口。执行前确认 ESP 已挂载到 /efi;挂载检查失败时,先处理挂载问题。
mountpoint /efi
KEY=/etc/ssl/private/secure_boot/MOK.key
CRT=/etc/ssl/private/secure_boot/MOK.crt
# 1. Create the main and fallback directories.
sudo mkdir -p /efi/EFI/Arch /efi/EFI/BOOT
# 2. Deploy shim and MokManager.
sudo install -m 0644 \
/usr/share/shim-signed/shimx64.efi \
/efi/EFI/Arch/shimx64.efi
sudo install -m 0644 \
/usr/share/shim-signed/mmx64.efi \
/efi/EFI/Arch/mmx64.efi
# 3. Sign and verify systemd-boot.
sudo sbsign --key "$KEY" --cert "$CRT" \
--output /efi/EFI/Arch/grubx64.efi \
/usr/lib/systemd/boot/efi/systemd-bootx64.efi
sudo sbverify --cert "$CRT" /efi/EFI/Arch/grubx64.efi
# 4. Deploy the same chain to the fallback directory.
sudo install -m 0644 \
/efi/EFI/Arch/shimx64.efi \
/efi/EFI/BOOT/BOOTx64.EFI
sudo install -m 0644 \
/efi/EFI/Arch/mmx64.efi \
/efi/EFI/BOOT/mmx64.efi
sudo install -m 0644 \
/efi/EFI/Arch/grubx64.efi \
/efi/EFI/BOOT/grubx64.efi
# 5. Sign the UKI, verify it, then replace the unsigned image.
UKI=/efi/EFI/Linux/arch-linux.efi
sudo sbsign --key "$KEY" --cert "$CRT" \
--output "${UKI}.signed" "$UKI" &&
sudo sbverify --cert "$CRT" "${UKI}.signed" &&
sudo mv -f "${UKI}.signed" "$UKI"
# 6. Inspect the SBAT metadata of the second-stage loader.
objdump -j .sbat -s /efi/EFI/Arch/grubx64.efi
# 7. Create the main NVRAM boot entry.
sudo efibootmgr --create --disk /dev/sdX --part 1 \
--loader '\EFI\Arch\shimx64.efi' \
--label 'Arch Linux (shim)' --unicode--disk 和 --part 应替换为实际 ESP 所在磁盘及分区编号。
shim 15.3 及之后的版本要求它加载的第二阶段 EFI 程序包含有效的 SBAT 元数据。上面的 objdump 命令用于查看 .sbat;检查失败时应先解决兼容性问题。ArchWiki:shim
fallback 入口可在 NVRAM 启动项丢失或外置硬盘接到另一台电脑时使用默认 EFI 路径。MOK 登记属于当前机器的固件配置,更换机器后仍需确认它信任 shim,并登记相应的 MOK。
7.5 导入 MOK 证书
# Submit the DER certificate and set a one-time password.
sudo mokutil --import "$HOME/MOK.cer"
reboot重启时选择 Arch Linux (shim),确保进入 shim 启动链。MokManager 出现后,选择 Enroll MOK,确认待登记证书,输入临时密码,完成登记并重启。这是在确认已提交的登记请求,区别于 Enroll key from disk 手动从磁盘选择证书的流程。
进入系统后检查登记结果:
sudo mokutil --test-key "$HOME/MOK.cer"
sudo mokutil --list-enrolled确认登记成功后,再进固件启用 Secure Boot。启用后分别测试 NVRAM 主启动项和固件提供的可移动磁盘 fallback 启动路径,并按 8.3 节检查状态。
7.6 清理旧的 systemd-boot 部署
通过 shim 成功启动 Arch、确认 Secure Boot 正常,并验证主启动和 fallback 路径后,再清理初次 bootctl install 留下的标准副本。删除前确认该副本没有被其他系统或启动项使用。
Arch 从 systemd 261.2-1 起,在升级时检测到已安装的 systemd-boot 后,会通过 systemd-boot-update.service 执行 bootctl 更新。本文由自定义脚本维护 shim 启动链,因此需移除标准部署,避免自动更新机制继续管理这些启动文件。ArchWiki:自动更新
# Check the current loader and NVRAM entries.
bootctl status
sudo efibootmgr -v
# Confirm that both shim chains are deployed.
ls -l /efi/EFI/Arch/
ls -l /efi/EFI/BOOT/
# Remove the unused standard systemd-boot deployment.
sudo rm -f /efi/EFI/systemd/systemd-bootx64.efi此前若创建过指向 \EFI\systemd\systemd-bootx64.efi 的旧 NVRAM 启动项,可在确认新启动项正常后,通过 efibootmgr 按实际编号删除。
后续使用 8.1 节的部署脚本维护实际启动文件,不再运行 bootctl install 或 bootctl update。bootctl status、bootctl list 仍可用于查看状态和启动项。
八、自动化签名
pacman hook 负责更新 systemd-boot 的两个部署副本,mkinitcpio post hook 负责签名新生成的 UKI。
8.1 pacman hook:自动签名 systemd-boot
systemd 包更新 /usr/lib/systemd/boot/efi/systemd-bootx64.efi 后,由脚本完成签名、验证,并直接部署到主启动和 fallback 目录。
创建 /usr/local/sbin/update-shim-loader:
sudo mkdir -p /usr/local/sbin
sudoedit /usr/local/sbin/update-shim-loader脚本内容:
#!/usr/bin/env bash
set -euo pipefail
src=/usr/lib/systemd/boot/efi/systemd-bootx64.efi
key=/etc/ssl/private/secure_boot/MOK.key
cert=/etc/ssl/private/secure_boot/MOK.crt
main_dir=/efi/EFI/Arch
fallback_dir=/efi/EFI/BOOT
# Check the ESP before writing any files.
if ! mountpoint -q /efi; then
echo "ESP is not mounted at /efi" >&2
exit 1
fi
# Require the signing inputs and both shim chains.
for required in "$src" "$key" "$cert" \
"$main_dir/shimx64.efi" "$main_dir/mmx64.efi" \
"$fallback_dir/BOOTx64.EFI" "$fallback_dir/mmx64.efi"; do
if [[ ! -f "$required" ]]; then
echo "Missing required file: $required" >&2
exit 1
fi
done
# Register cleanup before creating the second temporary file.
tmp_main=$(mktemp "$main_dir/.grubx64.XXXXXXXX")
tmp_fallback=
trap 'rm -f -- "$tmp_main" "$tmp_fallback"' EXIT
tmp_fallback=$(mktemp "$fallback_dir/.grubx64.XXXXXXXX")
# Sign the new loader and verify it before deployment.
sbsign \
--key "$key" \
--cert "$cert" \
--output "$tmp_main" \
"$src"
sbverify --cert "$cert" "$tmp_main"
cp "$tmp_main" "$tmp_fallback"
# Replace each loader using a temporary file in the same directory.
mv -f "$tmp_main" "$main_dir/grubx64.efi"
mv -f "$tmp_fallback" "$fallback_dir/grubx64.efi"
echo "Signed systemd-boot deployed successfully."设置执行权限,并先手动运行一次:
sudo chmod 755 /usr/local/sbin/update-shim-loader
sudo /usr/local/sbin/update-shim-loader脚本成功后,创建 pacman hook:
sudo mkdir -p /etc/pacman.d/hooks
sudoedit /etc/pacman.d/hooks/99-shim-loader.hook文件内容:
[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = systemd
[Action]
Description = Signing and deploying systemd-boot for shim
When = PostTransaction
Exec = /usr/local/sbin/update-shim-loader如果已按旧配置创建 /etc/pacman.d/hooks/80-secureboot.hook,移除它,避免保留两套签名机制:
sudo rm -f /etc/pacman.d/hooks/80-secureboot.hooksystemd 更新后,99-shim-loader.hook 调用脚本,将同一份已验证的 systemd-boot 部署到 EFI/Arch/grubx64.efi 和 EFI/BOOT/grubx64.efi。
8.2 mkinitcpio post hook:自动签名 UKI
mkinitcpio 成功生成镜像后会执行 post hook,并通过第三个参数提供 UKI 路径。此脚本不依赖具体内核版本,可用于 linux、linux-lts 等内核的 UKI preset。mkinitcpio(8):post hooks
sudo mkdir -p /etc/initcpio/post
sudoedit /etc/initcpio/post/uki-sbsign脚本内容:
#!/usr/bin/env bash
set -euo pipefail
uki="${3:-}"
[[ -n "$uki" ]] || exit 0
key=/etc/ssl/private/secure_boot/MOK.key
cert=/etc/ssl/private/secure_boot/MOK.crt
# Check the ESP and signing inputs.
if ! mountpoint -q /efi; then
echo "ESP is not mounted at /efi" >&2
exit 1
fi
for required in "$uki" "$key" "$cert"; do
if [[ ! -f "$required" ]]; then
echo "Missing required file: $required" >&2
exit 1
fi
done
# Skip images already signed with this certificate.
if sbverify --cert "$cert" "$uki" >/dev/null 2>&1; then
exit 0
fi
# Verify the signed copy before replacing the generated UKI.
tmp=$(mktemp "$(dirname "$uki")/.uki-sbsign.XXXXXXXX")
trap 'rm -f -- "$tmp"' EXIT
sbsign \
--key "$key" \
--cert "$cert" \
--output "$tmp" \
"$uki"
sbverify --cert "$cert" "$tmp"
mv -f "$tmp" "$uki"sudo chmod 755 /etc/initcpio/post/uki-sbsign8.3 验证自动签名
# Rebuild the UKI and run its signing hook.
sudo mkinitcpio -p linux
# Verify the UKI with the expected certificate.
sudo sbverify \
--cert /etc/ssl/private/secure_boot/MOK.crt \
/efi/EFI/Linux/arch-linux.efi
# Verify both deployed systemd-boot copies.
sudo sbverify \
--cert /etc/ssl/private/secure_boot/MOK.crt \
/efi/EFI/Arch/grubx64.efi
sudo sbverify \
--cert /etc/ssl/private/secure_boot/MOK.crt \
/efi/EFI/BOOT/grubx64.efi
# Check the current boot chain and Secure Boot state.
bootctl status
mokutil --sb-state
sudo efibootmgr -vsbverify --list 只列出签名信息,sbverify --cert 用指定证书验证镜像。sbverify(1)
九、最终 ESP 布局
/efi/
├── EFI/
│ ├── Arch/
│ │ ├── shimx64.efi # shim (Microsoft-signed)
│ │ ├── grubx64.efi # systemd-boot (MOK-signed)
│ │ └── mmx64.efi # MokManager
│ ├── BOOT/
│ │ ├── BOOTx64.EFI # shim (fallback)
│ │ ├── grubx64.efi # systemd-boot (MOK-signed)
│ │ └── mmx64.efi # MokManager
│ └── Linux/
│ └── arch-linux.efi # UKI (MOK-signed)
└── loader/
├── loader.conf
├── entries/
└── random-seed这些路径均相对于 ESP:/EFI/Arch/ 用于 NVRAM 主启动项,/EFI/BOOT/ 用于 fallback,/EFI/Linux/ 存放自动发现的 UKI,/loader/ 存放 systemd-boot 的共享配置。
十、验证与排错
# List enrolled MOK certificates.
sudo mokutil --list-enrolled
# Verify the UKI and both second-stage loaders.
CRT=/etc/ssl/private/secure_boot/MOK.crt
sudo sbverify --cert "$CRT" /efi/EFI/Linux/arch-linux.efi
sudo sbverify --cert "$CRT" /efi/EFI/Arch/grubx64.efi
sudo sbverify --cert "$CRT" /efi/EFI/BOOT/grubx64.efi
# Inspect the current loader and NVRAM boot entries.
bootctl status
sudo efibootmgr -v
# Check firmware state and kernel messages after booting.
mokutil --sb-state
sudo dmesg | grep -i secure
# Expected kernel message: Secure boot enabled若启动时报 prohibited by secure boot policy:
- 检查 MOK 证书是否已在 MokManager 中确认导入
- 用
sbverify --cert逐一验证 UKI 和两个 systemd-boot 副本 - 确认实际启动项指向 shim,并检查 fallback 入口是否仍是 shim
- 检查固件是否信任该 shim 的签名,以及第二阶段 EFI 文件的 SBAT 元数据是否兼容
十一、日常维护速查
| 场景 | 操作 |
|---|---|
更新 linux | mkinitcpio 自动构建 UKI,post hook 自动签名;确认成功后重启 |
更新 systemd | pacman hook 签名并部署两个 systemd-boot 副本;确认成功后重启 |
| 手动重建 UKI | sudo mkinitcpio -p linux,post hook 自动签名 |
| 手动重新部署 systemd-boot | sudo /usr/local/sbin/update-shim-loader |
更新 shim-signed | 检查新 shim、SBAT 和 MokManager 的兼容性,手动更新主启动和 fallback 中的 shim、MokManager 副本 |
新增 linux-lts | 配置独立的 UKI preset,复用已有 mkinitcpio 签名 hook,验证后重启 |
| 更换 MOK | 生成并导入新证书,完成 MokManager 登记,重新签名原先由 MOK 签名的 EFI 文件;验证启动成功后再删除旧 MOK |
十二、BTRFS 快照回滚 (Proof of Concept)
BTRFS 子卷布局的核心好处是快照与回滚。
12.1 确认子卷布局
sudo btrfs subvolume list / | grep -E '@$|@home|@snapshots'
mount | grep btrfs12.2 拍快照
# 安装前创建只读快照
sudo btrfs subvolume snapshot -r / /.snapshots/pre-neovim_$(date +%Y%m%d_%H%M%S)
# 安装软件
sudo pacman -S neovim
which nvim && echo "nvim installed"
# 查看快照
sudo btrfs subvolume list -s / | grep pre-neovim12.3 从快照回滚
模拟需要回滚的场景:
# 从 livecd 或另一个系统操作:
# 挂载 BTRFS 顶层(subvolid=5)
sudo mkdir -p /mnt/btrfs
sudo mount -o subvolid=5 /dev/sdX2 /mnt/btrfs
# 挂载 ESP
sudo mkdir -p /mnt/btrfs/efi
sudo mount /dev/sdX1 /mnt/btrfs/efi
# 备份当前的 @
sudo mv /mnt/btrfs/@ /mnt/btrfs/@_broken
# 从快照恢复
sudo btrfs subvolume snapshot /mnt/btrfs/@snapshots/pre-neovim_20260618_143022 /mnt/btrfs/@
reboot重启后系统回到快照时的状态,Neovim 消失。
BTRFS 根子卷快照不包含独立的 ESP,因此无法单独完成内核升级后的完整系统回滚。升级后的 UKI 留在 ESP 上,而根子卷回滚可能恢复旧版
/usr/lib/modules/,造成运行内核与模块版本不匹配。ArchWiki:快照与启动分区
12.4 清理
# 挂载顶层
sudo mount -o subvolid=5 /dev/sdX2 /mnt/btrfs
# 删除已废弃的备份子卷
sudo btrfs subvolume delete /mnt/btrfs/@_broken
# 清理快照
sudo btrfs subvolume delete /mnt/btrfs/@snapshots/pre-neovim_20260618_143022删除子卷前注意是否有嵌套子卷。用
sudo btrfs subvolume list /mnt/btrfs检查top level字段,先删除嵌套子卷再删父子卷。
十三、与 Gentoo shim + GRUB 方案对比
另一个用 Gentoo + GRUB 做过的 Secure Boot 配置,两者的关键差异:
| Arch 方案(本文) | Gentoo 方案 | |
|---|---|---|
| 引导器 | systemd-boot | GRUB |
| 内核格式 | UKI(单文件) | vmlinuz + initramfs(分离) |
| UKI / 镜像签名 | mkinitcpio post hook 自动 sbsign | 手动或通过自定义构建流程签名 |
| bootloader 签名 | pacman hook 调用 sbsign,直接部署主启动和 fallback 副本 | Portage 签名机制或手动签名 |
| 模块签名 | 无需单独处理(Arch 内核包自带机制) | Portage MODULES_SIGN_* 自动 |
| 自动化程度 | 内核与 systemd-boot 由 hook 维护,shim 手动更新 | 模块自动签,镜像由手动或自定义流程维护 |
| 快照 | BTRFS 子卷快照 | 无内置(需外部工具) |
两者共同的信任根:shim + MOK,通过 MokManager 一次性确认。
附录:完整包列表 (pacman -Qqe)
7zip
adw-gimp3-git
archlinuxcn-keyring
baobab
base
bluez-utils
chromium
chrony
clash-party-bin
cockpit
code
dconf-editor
direnv
efibootmgr
extension-manager
eza
fastfetch
fd
fzf
gdm
gnome-backgrounds
gnome-characters
gnome-logs
gnome-shell-extension-appindicator
gnome-shell-extension-dash-to-dock
gnome-shell-extension-gsconnect
gnome-shell-extension-vitals
gnome-text-editor
gnome-tweaks
gradia
htop
ibus-rime
intel-ucode
kvantum
kvantum-manjaro
libgda6
libva-nvidia-driver
linux
linux-firmware
linuxqq
loupe
mokutil
nano
noto-fonts-cjk
noto-fonts-emoji
nvidia-open
nvtop
pacman-contrib
papers
papirus-icon-theme
paru
pkgfile
pnpm
ptyxis
qt6-5compat
qt6ct
refine
resources
ripgrep
sbsigntools
shim-signed
showtime
starship
telegram-desktop
tree
ttf-cascadia-mono-nerd
vim
vkmark
wechat-bin
wget
wimlib
xorg-xwininfo
zoxide
zsh-autosuggestions7zip
ark
aspnet-runtime
aspnet-targeting-pack
base
base-devel
bash-completion
bat
bind
cargo-xwin
chromium
chrony
clang
cloudflared
dolphin
dotnet-sdk
efibootmgr
eza
fastfetch
fcitx5-chinese-addons
fcitx5-configtool
fd
filelight
furmark
fwupd
git
grub
gwenview
htop
intel-media-driver
intel-ucode
kate
kdiskmark
konsole
lact
less
linux-firmware
linuxqq
mangohud
mihomo-party-bin
mission-center
nodejs
noto-fonts-cjk
ntfsprogs-plus
nvidia-open
openai-codex
openssh
pacman-contrib
pkgfile
plasma-meta
pnpm
power-profiles-daemon
rsync
rustup
s-tui
starship
stress-ng
tela-circle-icon-theme-all
tree
ttf-cascadia-code-nerd
ttf-harmonyos-sans
ttf-inconsolata-nerd
turbostat
vim
visual-studio-code-bin
vkmark
vulkan-intel
wget
xfsprogs
xorg-xwininfo
yay
zoxide
zsh-autosuggestions
zsh-history-substring-search
zsh-syntax-highlighting