某天在群里和大佬们作OT的闲聊时觉得 GRUB 作为 Bootloader 过于臃肿,于是就产生了更换一个更轻量的 Bootloader 的想法。

因为 systemd-boot 与 systemd 关系紧密,而且有一些其他 Bootloader 没有的优秀特性,我决定更换这个 Bootloader 。

安装 systemd-boot

首先需要安装 systemd-boot

注意使用 systemd-boot 时需要将 ESP 挂载为 Boot 分区。

这里假设只有一个 ESP ,如果有多个 ESP ,需要指定额外的参数。

bootctl install

配置 systemd-boot

systemd-boot 需要自行编写配置文件和启动项配置。

Bootloader 配置

创建并编辑 /boot/loader/loader.conf 文件:

#timeout 10
#console-mode keep
default arch.conf

timeout 即菜单超时,默认值为 0 。为 0 时自动引导默认启动项,若开机时按下按键(不是所有按键都有用,可以按空格),将显示菜单。个人很喜欢这个设计,既可以节省宝贵的一秒钟,还不会牺牲扩展性。

console-mode 默认值为 keep 。最好别动,否则启动菜单可能不会以屏幕分辨率呈现。

default 为初始的默认启动项,值为 /boot/loader/entries/ 下的文件名,此处为 arch.conf ,则 entries 文件夹下必须存在一个叫 arch.conf 的启动项文件。默认启动项可以使用 bootctl 覆盖或在启动菜单里使用 D 键指定默认启动项。

一般写这么多就够了。

启动项配置

创建并编辑 /boot/loader/entries/arch.conf 文件:

title   Arch Linux Zen Kernel
linux   /vmlinuz-linux-zen
initrd  /amd-ucode.img
initrd  /initramfs-linux-zen.img
options root=UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx rw

格式大致如上。

title 是该启动项在菜单中的显示名称

linux, initrd, options 是引导 Linux 系统必需的参数,可以参考 GRUB 的配置文件修改。

此处要注意不同版本内核的内核文件名不一致,需要修改。我使用的是 Linux-zen 内核,所以这里的内核文件带 zen 后缀。

别忘了添上微码补丁的加载项。

内核参数可以从 /boot/grub/grub.cfg 中去抄。不要从 /etc/default/grub 里抄,可能会少参数。

还可以创建一个 fallback entry 。参考 GRUB ,不过用处不大。

如果只是使用 LUKS 加密系统(或者没加密),完成这一步就可以卸载 GRUB 重启了。

配置安全启动

如果还设置了安全启动,需要继续配置内核自动签名。ArchWiki1 提供了两种方法,这里依旧手动配置 pacman hook 。

关于安全启动的详细配置过程,请参考这篇文章

配置 pacman hook

如果使用 GRUB 时按照上面的教程配置了 HOOK ,这里需要删除这些 HOOK 。

/etc/pacman.d/hooks/90-mkinitcpio-install.hook

/usr/local/share/libalpm/scripts/mkinitcpio-install

创建两个新 HOOK

  • 内核或 systemd 更新时触发签名 Kernel 和 Bootloader 的 HOOK

    /etc/pacman.d/hooks/99-secureboot.hook

    [Trigger]
    Type = Package
    Operation = Install
    Operation = Upgrade
    Target = systemd
    Target = usr/lib/modules/*/vmlinuz
    Target = usr/lib/initcpio/* 
    
    [Action]
    Description = Signing Kernel for SecureBoot
    When = PostTransaction
    Exec = /usr/bin/sh -c "/usr/bin/find /boot/ -type f \( -name 'vmlinuz-*' -o -name 'systemd*' \) -exec /usr/bin/sh -c 'if ! /usr/bin/sbverify --list {} 2>/dev/null | /usr/bin/grep -q \"signature certificates\"; then /usr/bin/sbsign --key db.key --cert db.crt --output {} {}; fi' \;"
    Depends = sbsigntools
    Depends = findutils
    Depends = grep
    

    需要将 db.keydb.crt 修改为对应的绝对路径。

  • systemd 更新时触发更新 systemd-boot 的 HOOK

    /etc/pacman.d/hooks/100-systemd-boot.hook

    [Trigger]
    Type = Package
    Operation = Upgrade
    Target = systemd
    
    [Action]
    Description = Updating systemd-boot
    When = PostTransaction
    Exec = /usr/bin/bootctl update
    

这个 HOOK 做了一些修改(参考 GRUB 的 HOOK),兼容所有内核。

注意更新 Bootloader 的 HOOK 必须比签名 HOOK 先执行。

这里 systemd-boot.hook 使用 100 作为前缀,好像看起来 99 排在 100 前面,但 Linux 的文件排序是逐字符对比排序的,所以 100 要比 99 先执行。

签名 systemd-boot

最后需要手动执行一次签名操作:

sbsign --key db.key --cert db.crt --output /boot/EFI/systemd/systemd-bootx64.efi /boot/EFI/systemd/systemd-bootx64.efi
sbsign --key db.key --cert db.crt --output /boot/EFI/BOOT/BOOTX64.EFI /boot/EFI/BOOT/BOOTX64.EFI

同样需要将 db.keydb.crt 修改为对应的绝对路径。

卸载 GRUB

sudo pacman -R grub os-prober

卸载完后 pacman 会提示有两个文件被转移,这两个文件也要删掉。

然后删除 Boot 分区中的 grub 文件夹和 ESP 中的 grub 启动文件,最后用 efibootmgr 清理掉残留的 GRUB 启动项即可。

参考资料

  1. https://wiki.archlinux.org/title/Systemd-boot#Preparing_a_unified_kernel_image