如果您不小心错误地配置了 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
LFS 不包含支持安全启动所需的软件包。因此,如果要按照本节的说明配置引导过程,必须在固件的配置界面关闭安全启动。阅读系统生产商提供的文档以找出关闭安全启动的方法。
GRUB 使用一种独特的命名结构,为驱动器和分区命名。分区名的形式为 (hdn,m),这里 n 是硬盘驱动器编号,m 是分区编号。硬盘驱动器编号从 0 开始,但分区号对于主分区来说从 1 开始
(对于扩展分区来说从 5 开始)。例如,分区 sda1 在 GRUB
中的名字是 (hd0,1),而 sdb3 的名字是 (hd1,3)。和 Linux 不同,GRUB 不认为 CD-ROM
驱动器属于硬盘驱动器。例如,如果在 hdb 上有一个 CD-ROM
驱动器,而 hdc 上有第二个硬盘驱动器,则第二个硬盘驱动器仍然名为
hd1。
如果使用 BIOS 引导系统,GRUB 会在硬盘的首个扇区 (称为主引导记录,或 MBR) 写入一个端桩。MBR 区域不属于任何文件系统。BIOS 会加载并执行 MBR 的内容,这样端桩即可从 BIOS Boot 分区 (没有文件系统结构) 加载 GRUB 主映像。这样,端桩就不需要支持任何文件系统,才能小到足以存放到 MBR 中。
如果通过 UEFI 引导系统,GRUB 将其主映像写入到位于标准位置的 PE-COFF 可执行文件 EFI/BOOT/BOOTX64.EFI 中 (对于 i386-efi 则是 EFI/BOOT/BOOTIA32.EFI)。UEFI 固件从标准位置加载并执行这个文件,启动
GRUB。
GRUB 主映像并不包含 GRUB 的大多数功能 (包括引导 Linux 内核)。实际上,这些功能作为 GRUB
模块,被存储在某个文件系统中。在多数 Linux 发行版中,这个文件系统的挂载点允许通过 /boot/grub 路径访问 GRUB
模块。为了避免“先有鸡还是先有蛋”的问题,grub-install 将访问这一文件系统所必须的模块嵌入到
GRUB 主映像中,使它能够找到和加载其他模块。
引导分区的位置可由负责进行配置的用户自行决定,作者推荐创建一个小的 (建议大小为 200 MB) 分区,专门存放引导信息。这样,不仅是
LFS,安装在硬盘上的所有 Linux 发行版都能访问各个发行版的引导文件。如果您选择这样做,您需要挂载这个单独的分区,将
/boot 中已有的文件 (例如上一节中构建的 Linux 内核)
移动到新的分区中。之后,解除该分区的挂载,再将它重新挂载为 /boot。另外,还要注意更新 /etc/fstab。
如果宿主发行版为 /boot 使用了单独的分区,且希望 LFS
系统也以这个分区作为 /boot,直接在宿主发行版将它挂载到
$LFS/boot 即可。Linux
内核允许将一个分区挂载到多个挂载点。
直接将 /boot 目录保留在 LFS
分区也是可以的,但这样在配置多系统启动时比较麻烦。
在 第 2.4 节 “创建新的分区” 可以找到引导分区布局的更多信息和示例。
根据以上信息,确定 LFS 根分区 (或 boot 分区,如果使用了独立的 boot 分区) 的名称。下面假设 LFS 根分区 (或
boot 分区) 是 sda2。
以下各节描述配置 BIOS 和 UEFI 引导的方法。为 BIOS,64 位 UEFI,以及 32 位 UEFI 安装的 GRUB 可共存并共用一份配置,它们的代码和数据存放在不同的位置。因此,可以既创建 BIOS Boot 分区,又创建 EFI 系统分区,再为所有支持的固件类型安装 GRUB (即运行三次 grub-install。在不确定固件类型,或者计划将硬盘移动到其他计算机上使用的情况下,可以这样直接覆盖所有情况。
如果使用 UEFI 引导系统,但已经创建了 Grub BIOS 分区,则可以执行配置 BIOS 引导的命令,以作为 UEFI 引导不能正常工作时的备份。
如果只需要为一种引导方案安装 GRUB,只运行为该引导方案进行安装的命令即可。
如果需要使用 BIOS 引导 LFS,首先确认 boot 分区已经挂载(如果使用了单独的 boot 分区),并确认 BIOS
Boot 分区存在。然后即可将 GRUB 文件安装到 /boot/grub 并设定引导磁道:
以下命令会覆盖当前启动引导器,如果您不希望这样做,例如要使用第三方引导管理器管理 MBR,则不要运行该命令。
grub-install /dev/sda --target=i386-pc
如果需要使用 UEFI 引导 LFS,首先确认 boot 分区已经挂载(如果使用了单独的 boot 分区),并确认 EFI
系统分区已经挂载到 /boot/efi。然后即可将 GRUB
文件安装到 /boot/grub 并将 GRUB 主映像安装到
/boot/efi/EFI/BOOT/BOOTX64.EFI:
以下命令会覆盖 /boot/efi/EFI/BOOT/BOOTX64.EFI
文件。如果该文件已经存在,则它很可能是另一引导加载器的入口点(例如宿主发行版安装的 GRUB,或者 Windows
引导管理器)。可以备份该文件,这样之后可以恢复它,或使用 LFS 新安装的 GRUB 将其加载为次级引导加载器。
grub-install --target=x86_64-efi --removable
上述命令假设 UEFI 固件是 64 位的。如果需要通过 32 位 UEFI 固件引导系统,需要将命令中的
x86_64-efi 改为 i386-efi。
--removable 选项使得
grub-install
使用标准位置,EFI/BOOT/BOOTX64.EFI (或者对于
i386-efi 则为 EFI/BOOT/BOOTIA32.EFI),而非 GRUB 通常使用的位置
(EFI/GRUB/GRUBX64.EFI 或者
EFI/GRUB/GRUBIA32.EFI。)如果使用非标准位置,则需要将它记录在一个 EFI
变量中,但 LFS 没有 BLFS 软件包
efibootmgr,而 GRUB 需要它才能在 EFI 变量记录位置。
一些很少见的 UEFI 固件实现会忽略标准路径。这些系统一般出现在较为陈旧的系统上,例如旧款的的联想 Thinkpad 或 HP 台式机/笔记本。如果在固件设置中找不到对应于标准路径的引导项,则需要使用 BLFS 软件包 efibootmgr 创建引导项。如果宿主发行版提供了该软件包,也可以通过其包管理器安装并使用它。这样可以暂时避免为 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\BOOT<X64>.EFI'
其中 /dev/sd 应改为 ESP
所在磁盘对应的设备节点,<x><y>
应改为 ESP 在磁盘上的编号,例如如果 ESP 对应的设备节点是 /dev/sda2,则编号就是 2。如果使用 32 位 UEFI,需要将 <X64> 替换成 IA32。
一些 (实现不正确的) 固件需要向 efibootmgr 传递更多选项,类似
--full-dev-path 或者
-e 1 -E。详见手册页 efibootmgr(8)。
取消挂载 EFI 变量文件系统:
umount -v /sys/firmware/efi/efivars
生成 /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)
# For UEFI
insmod efi_gop
insmod efi_uga
set gfxpayload=1024x768x32
menuentry "GNU/Linux, Linux 6.19.12-lfs-r13.0-84-systemd" {
linux /boot/vmlinuz-6.19.12-lfs-r13.0-84-systemd root=/dev/sda2 ro
}
EOF
配置文件使用 insmod 命令加载
GRUB 模块 part_gpt,ext2,efi_gop,以及
efi_uga。ext2 模块虽然其名称只包含一个文件系统,实际上却支持 ext2,ext3,以及
ext4 文件系统。在 UEFI 系统上,efi_gop 和 efi_uga
提供视频输出支持。GOP,即图形输出协议,是现代 UEFI 固件采用的视频接口。UGA,即通用图形适配器,则出现在一些老式 UEFI
固件上。在典型的系统配置中,grub-install 命令已经将 part_gpt 和 ext2 嵌入
GRUB 主映像中,此时对应的两条 insmod
命令不会产生任何效果。但是无论如何它们不会造成损害,而且在一些少见的系统配置中它们可能是必要的。
set gfxpayload=1024x768x32 命令设置 VESA 帧缓冲的分辨率和色深。内核 SimpleDRM 驱动需要它才能使用 VESA 帧缓冲。可以自行改用更适合显示器的分辨率和色深值。这一行在使用 UEFI 引导系统时没有作用,但也不会造成损害。
从 GRUB 的视角来看,内核文件的位置相对于它使用的分区。如果您使用了单独的 /boot 分区,需要从上面的 linux 行删除 /boot,然后修改 set root 行,指向 /boot 分区。
如果新增或移除了一些存储设备 (包括 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=,但是这种方法依赖于 initramfs,而 initramfs 超出了
LFS 的范畴。
<分区
UUID>
/dev 中分区对应的设备节点名也可能发生改变 (这一现象在在配备多块
NVME 盘的系统上经常出现)。在 /etc/fstab 中,也可以将
/dev/sda1 这样的设备节点路径改为 PARTUUID=,从而避免设备节点命名发生改变时可能导致的引导失败。
<分区
UUID>
GRUB 是一个很强大的程序,它提供了非常多的选项,可以支持多种设备、操作系统和分区类型,还有很多用于定制启动屏幕、声音、鼠标输入等的选项。这些选项的细节超过了本书的范围,不予讨论。
有一个命令 grub-mkconfig 可用于自动创建配置文件。它使用 /etc/grub.d 中的脚本创建新配置文件,这会覆盖您手动编写的配置。这些脚本主要是为非源代码发行版设计的,在 LFS 中不推荐使用它们。但是,如果您安装了商业发行版,它很可能在发行版中被运行,记得备份 grub.cfg 以防它被覆盖。