10.4 使用 GRUB 设定引导过程

10.4.1 概述

[警告]

警告

如果您不小心错误地配置了 GRUB,可能导致您的系统完全无法使用,除非使用 CD-ROM 或可引导的 USB 存储器等备用引导设备。本节不是引导您的 LFS 系统的唯一方案,您可能只要修改现有的启动加载器 (如 Grub-Legacy 或 GRUB2) 配置即可引导 LFS。

您务必保证自己拥有一个紧急引导磁盘,它在计算机不可用 (无法引导) 时能够 抢修 计算机。如果您现在还没有引导设备,您可以执行以下命令创建一个。在运行下列命令前,您需要跳到 BLFS,安装包含 xorriso libisoburn 软件包:

cd /tmp
grub-mkrescue --output=grub-img.iso
xorriso -as cdrecord -v dev=/dev/cdrw blank=as_needed grub-img.iso

10.4.2 关闭安全启动

LFS 不包含支持安全启动所需的软件包。因此,如果要按照本节的说明配置引导过程,必须在固件的配置界面关闭安全启动。阅读系统生产商提供的文档以找出关闭安全启动的方法。

10.4.3 GRUB 命名惯例

GRUB 使用一种独特的命名结构,为驱动器和分区命名。分区名的形式为 (hdn,m),这里 n 是硬盘驱动器编号,m 是分区编号。硬盘驱动器编号从 0 开始,但分区号对于主分区来说从 1 开始 (对于扩展分区来说从 5 开始)。例如,分区 sda1 在 GRUB 中的名字是 (hd0,1),而 sdb3 的名字是 (hd1,3)。和 Linux 不同,GRUB 不认为 CD-ROM 驱动器属于硬盘驱动器。例如,如果在 hdb 上有一个 CD-ROM 驱动器,而 hdc 上有第二个硬盘驱动器,则第二个硬盘驱动器仍然名为 hd1

10.4.4 设定 GRUB 配置

在使用 UEFI 固件的系统上,GRUB 将其主映像作为 PE-COFF 可执行文件存储在 EFI 系统分区中的标准位置:EFI/BOOT/BOOTLOONGARCH64.EFI。UEFI 固件从标准位置加载 PE-COFF 文件并执行它,就启动了 GRUB。

GRUB 主映像并不包含 GRUB 的大多数功能 (包括引导 Linux 内核)。实际上,这些功能作为 GRUB 模块,被存储在某个文件系统中。在多数 Linux 发行版中,这个文件系统的挂载点允许通过 /boot/grub 路径访问 GRUB 模块。为了避免“先有鸡还是先有蛋”的问题,grub-install 将访问这一文件系统所必须的模块嵌入到 GRUB 主映像中,使它能够找到和加载其他模块。

根据以上信息,确定 LFS 根分区的名称。下面假设 LFS 根分区是 sda2

为了通过 UEFI 进行引导,确认 EFI 系统分区已挂载到 /boot/efi。然后,将 GRUB 文件安装到 /boot/grub,并将 GRUB 主映像安装到 /boot/efi/EFI/BOOT/BOOTLOONGARCH64.EFI

[警告]

警告

以下命令会覆盖 /boot/efi/EFI/BOOT/BOOTLOONGARCH64.EFI 文件。如果这个文件已经存在,则它很可能是另一个引导加载器 (例如宿主发行版安装的 GRUB,或者 Windows 引导管理器)。建议备份它,以便后续将它复原,或从为 LFS 新安装的 GRUB 将它作为第二级引导加载器加载:

grub-install --target=loongarch64-efi --removable

--removable 选项使得 grub-install 使用标准路径,即 EFI/BOOT/BOOTLOONGARCH64.EFI,而非 GRUB 通常使用的路径 (EFI/GRUB/GRUBLOONGARCH64.EFI)。如果使用后者,则需要在 EFI 变量中记录这一路径,但 LFS 没有提供 BLFS 的 efibootmgr 软件包,而 GRUB 需要它才能在 EFI 变量中记录路径。

[注意]

注意

一些罕见的 UEFI 固件实现会忽略标准的 EFI 路径。如果发现固件设置界面没有标准路径对应的引导项,则需要安装 BLFS 的 efibootmgr 软件包,才能创建引导项。也可以通过宿主发行版的包管理器安装该软件包,并在宿主发行版而非 LFS 系统上使用它。这样可以暂时避免为 LFS 系统下载额外的源码包。

首先安装上述软件包,然后挂载 EFI 变量文件系统,除非它已被挂载:

mountpoint /sys/firmware/efi/efivars ||
  mount -v -t efivarfs efivarfs /sys/firmware/efi/efivars

现在创建一个 EFI 引导项:

efibootmgr -c -d /dev/sd<x> \
  -p <y> -L "LFS" -l '\EFI\BOOT\BOOTLOONGARCH64.EFI'

/dev/sd<x> 应改为 ESP 所在磁盘对应的设备节点路径。<y> 应改为 ESP 的分区编号。例如,如果 ESP 对应的设备节点是 /dev/sda2,则分区编号是 2.

一些 (实现不正确的) 固件需要向 efibootmgr 传递更多选项,类似 --full-dev-path 或者 -e 1 -E。详见手册页 efibootmgr(8)

取消挂载 EFI 变量文件系统:

umount -v /sys/firmware/efi/efivars

10.4.5 创建 GRUB 配置文件

生成 /boot/grub/grub.cfg

cat > /boot/grub/grub.cfg << "EOF"
# Begin /boot/grub/grub.cfg
set default=0
set timeout=5

insmod part_gpt
insmod ext2

set root=(hd0,2)

menuentry "GNU/Linux, Linux 7.1.8-lfs-loongarch-r13.0-261-systemd" {
        linux   /boot/vmlinuz-7.1.8-lfs-loongarch-r13.0-261-systemd root=/dev/sda2 ro
}

menuentry "Debian" {
        insmod fat
        insmod chain
        chainloader (hd0,1)/EFI/DEBIAN/GRUBLOONGARCH64.EFI
}

menuentry "Firmware Setup" {
        fwsetup
}
EOF

配置文件使用 insmod 命令加载 GRUB 模块 part_gptext2ext2 模块虽然其名称只包含一个文件系统,实际上却支持 ext2ext3,以及 ext4 文件系统。在典型的系统配置中,grub-install 命令已经将 part_gptext2 嵌入 GRUB 主映像中,此时对应的两条 insmod 命令不会产生任何效果。但是无论如何它们不会造成损害,而且在一些少见的系统配置中它们可能是必要的。

此处Debian一节展示了链式加载另一个 UEFI 引导加载器。如果您备份了运行 grub-install 之前的BOOTLOONGARCH64.EFI 文件,则也可以将其放回 ESP 中 (需要使用不同的路径),并这样链式加载它。

Firmware Setup一节展示fwsetup命令,它唤起 UEFI 固件提供的配置界面 (一般称为BIOS 设置)。

[注意]

注意

如果新增或移除了一些存储设备 (包括 USB 闪存盘等可移动存储设备),则 GRUB 赋予分区的编号可能发生改变。这可能导致引导失败,因为 grub.cfg 仍然在使用旧的编号。如果希望避免这种问题,可以使用分区和文件系统的 UUID 指定分区,以代替 GRUB 编号。运行 lsblk -o UUID,PARTUUID,PATH,MOUNTPOINT 以显示文件系统 (在 UUID 列) 和分区 (在 PARTUUID 列) 的 UUID。之后将 set root=(hdx,y) 替换为 search --set=root --fs-uuid <内核所在文件系统的 UUID>,并将 root=/dev/sda2 替换为 root=PARTUUID=<构建 LFS 使用的分区的 UUID>

注意分区的 UUID 和该分区中文件系统的 UUID 是完全不同的。一些在线资料可能建议使用 root=UUID=<文件系统 UUID> 代替root=PARTUUID=<分区 UUID>,但是这种方法依赖于 initramfs,而 initramfs 超出了 LFS 的范畴。

/dev 中分区对应的设备节点名也可能发生改变 (这一现象在在配备多块 NVME 盘的系统上经常出现)。在 /etc/fstab 中,也可以将 /dev/sda1 这样的设备节点路径改为 PARTUUID=<分区 UUID>,从而避免设备节点命名发生改变时可能导致的引导失败。

GRUB 是一个很强大的程序,它提供了非常多的选项,可以支持多种设备、操作系统和分区类型,还有很多用于定制启动屏幕、声音、鼠标输入等的选项。这些选项的细节超过了本书的范围,不予讨论。