无须 Grub2, 使用 EFIStub 直接通过 UEFI 启动 Debian

默认情况下,Debian 的启动经历了主板启动 Grub2, 再由 Grub2 启动 Linux 内核的过程。

然而从 Debian Wheezy 起,Debian Linux 内核包含了一个自己的 BootLoader 叫作 EFI stub (或者叫作 EFI boot stub)。因此可以从 UEFI 直接启动内核,而不需要额外的 bootloader 例如 Grub2.

要实现以上所述,需要进行一些设置,大致可以分为以下两步:

  1. 复制 kernel 和 initrd 到 EFI 分区
  2. 创建 UEFI 启动条目

复制 kernel 和 initrd 到 EFI 分区

根据 EFIStub - Debian Wiki , UEFI 启动只能从 EFI 分区加载文件。因此需要将内核文件和 initrd 文件放置到 EFI 分区。

使用 lsblk 查看分区挂载情况:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ lsblk

NAME                 MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
...
nvme0n1              259:0    0 476.9G  0 disk
|-nvme0n1p1          259:1    0   976M  0 part /boot/efi
|-nvme0n1p2          259:2    0   977M  0 part /boot
`-nvme0n1p3          259:3    0   475G  0 part
  |-Debian-root      254:0    0  31.3G  0 lvm  /
...

手动复制内核和 initrd

默认情况下,Debian 的内核和 initrd 文件位于 Boot 分区,即 /boot/ 下,如:

1
2
3
4
$ ls -Alhs /boot/{vmlinuz,initrd}*

45M -rw-r--r-- 1 root root 45M Dec 31 03:37 /boot/initrd.img-6.12.63+deb13-amd64
12M -rw-r--r-- 1 root root 12M Dec 31 03:37 /boot/vmlinuz-6.12.63+deb13-amd64

复制内核文件

1
sudo cp --verbose "/boot/vmlinuz-$(uname -r)" /boot/efi/EFI/debian/vmlinuz.efi

复制 initrd 文件

1
sudo cp --verbose "/boot/initrd.img-$(uname -r)" /boot/efi/EFI/debian/initrd.img

自动复制内核和 initrd

创建脚本 /etc/kernel/postinst.d/zz-update-efistub

1
sudo nano /etc/kernel/postinst.d/zz-update-efistub

填入内容:

1
2
3
4
#!/bin/bash
set -e

cp --verbose "$2" /boot/efi/EFI/debian/vmlinuz.efi

授予执行权限:

1
sudo chmod +x /etc/kernel/postinst.d/zz-update-efistub

创建脚本 /etc/initramfs/post-update.d/zz-update-efistub

1
2
sudo mkdir -p /etc/initramfs/post-update.d/
sudo nano /etc/initramfs/post-update.d/zz-update-efistub

填入内容:

1
2
3
4
#!/bin/bash
set -e

cp --verbose "$2" /boot/efi/EFI/debian/initrd.img

授予执行权限:

1
sudo chmod +x /etc/initramfs/post-update.d/zz-update-efistub

警告

根据 EFIStub - Debian Wiki,以上脚本会在每一个 kernel 或 initrd 更新时被执行,根据更新操作的顺序可能会导致复制错误版本的文件到 EFI 分区,可能无法正常启动系统。因此建议保留其他启动手段如 Grub2 或 rEFInd 作为备用。

测试脚本是否正常运行

执行:

1
sudo dpkg-reconfigure linux-image-$(uname -r)

从输出的日志中,可以看到前面创建的脚本被运行,内核文件和 initrd 文件被复制到 EFI 分区。

1
2
3
4
update-initramfs: Generating /boot/initrd.img-6.12.63+deb13-amd64
'/boot/initrd.img-6.12.63+deb13-amd64' -> '/boot/efi/EFI/debian/initrd.img'
/etc/kernel/postinst.d/zz-update-efistub:
'/boot/vmlinuz-6.12.63+deb13-amd64' -> '/boot/efi/EFI/debian/vmlinuz.efi'

创建 UEFI 启动条目

本文使用 efibootmgr 为例创建 UEFI 条目,使用其他工具或方法也是可行的。

使用 efibootmgr 创建 UEFI 启动条目,如:

1
2
3
4
5
sudo efibootmgr --create \
    --disk /dev/sdX --part YY \
    --label "LABEL_NAME" \
    --loader /EFI/debian/vmlinuz.efi \
    --unicode "root=BLOCK_DEVICE_IDENTIFIER ro quiet initrd=\\EFI\\debian\\initrd.img"
  • --disk 指定硬盘设备。
  • --part 指定硬盘第几个分区为 EFI 分区。
  • --label 指定自己喜欢的名字,会显示在主板开机启动项菜单中。
  • BLOCK_DEVICE_IDENTIFIER 填写系统根目录 / 所在分区的标识符,一般是 UUID=******* 的形式。可以通过 lsblk -f 或者 blkid 查询。也可以参照 Grub2 的配置文件进行设置 sudo cat /boot/grub/grub.cfg | grep -i 'root='

该命令在不指定 --index 参数的情况下,创建的条目将会被放在启动顺序 0 的位置, 即开机时第一个启动。

示例

以我的电脑为例,我的硬盘为 /dev/nvme0n1, 第 1 个分区为 EFI 分区。因为我将根分区安装在 LVM 中,参考 Grub2 的配置文件写作 root=/dev/mapper/Debian-root

1
2
3
4
5
$ sudo cat /boot/grub/grub.cfg | grep -i 'root='

...
        linux   /vmlinuz-6.12.63+deb13-amd64 root=/dev/mapper/Debian-root ro  quiet
...
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$ sudo efibootmgr --create \
    --disk /dev/nvme0n1 --part 1 \
    --label "Debian EFIstub" \
    --loader /EFI/debian/vmlinuz.efi \
    --unicode "root=/dev/mapper/Debian-root ro quiet initrd=\\EFI\\debian\\initrd.img"

BootCurrent: 0000
Timeout: 2 seconds
BootOrder: 0000,0002,0010,0011,0012,0013,0018,0019,001A,0017,0016,001B
Boot0002* debian        HD(1,GPT,c7bzfazx-bap4-q7ch-bd3m-bucyj939s4hq,0x800,0x1e8000)/File(\EFI\debian\shimx64.efi)
...
Boot0000* Debian EFIstub        HD(1,GPT,c7bzfazx-bap4-q7ch-bd3m-bucyj939s4hq,0x800,0x1e8000)/File(\EFI\debian\vmlinuz.efi)root=/dev/mapper/Debian-root ro quiet initrd=EFI\debian\initrd.img

可以看到新增了一个 Boot0000 的条目,名为 Debian EFIstub

Boot0002 debian 是原有 Grub2 的 UEFI 启动条目。

测试

完成以上设置后,正常情况下,重启电脑,成功通过 UEFI 直接启动 Debian,而无须经由 Grub2 启动。

提示

根据 EFIStub - Debian WikiEFI boot stub CONs 的建议,最好保留例如 Grub2 这样 bootloader 以避免意外情况下无法启动系统。

有关 efibootmgr

显示所有 UEFI 启动条目

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ sudo efibootmgr -u

BootCurrent: 0000
Timeout: 2 seconds
BootOrder: 0000,0002,0010,0011,0012,0013,0018,0019,001A,0017,0016,001B
Boot0000* Debian EFIstub        HD(1,GPT,c7bzfazx-bap4-q7ch-bd3m-bucyj939s4hq,0x800,0x1e8000)/File(\EFI\debian\vmlinuz.efi)root=/dev/mapper/Debian-root ro quiet initrd=EFI\debian\initrd.img
Boot0002* debian        HD(1,GPT,c7bzfazx-bap4-q7ch-bd3m-bucyj939s4hq,0x800,0x1e8000)/File(\EFI\debian\shimx64.efi)
...
...
...

删除 UEFI 启动条目

本文写作时,efibootmgr 没有编辑条目的功能,但可以删除指定条目:

1
sudo efibootmgr --delete-bootnum --bootnum YYYY

批量删除所有名为 Debian EFIstub 的条目:

1
sudo efibootmgr | grep 'Debian EFIstub' | awk -F'Boot' '{print substr($2, 1, 4)}' | xargs -I {} sudo efibootmgr --delete-bootnum --bootnum {}

参考

使用 Hugo 构建
主题 StackJimmy 设计