GRUB

GRUB 的原始版本更名为 GRUB Legacy。GRUB Legacy 上继续进行少量维护,但最后一个版本(0.97)是在 2005 年发布的。

大约在 2007 年,GNU/Linux 发行版开始在有限的范围内使用 GRUB 2,到 2009 年底,多个主要发行版都默认安装它。

GRUB 2 (GRand Unified Bootloader version 2) 是 Linux 系统中广泛使用的引导加载器。它在操作系统启动之前运行,负责加载操作系统内核到内存,并将控制权移交给内核。理解 GRUB 2 对于系统维护、故障排除以及多系统引导至关重要。

1. GRUB 2 核心概念

GRUB 2 的设计非常模块化且强大,其核心概念包括:

  • 多阶段引导 (Multi-stage Booting):

    • boot.img (Stage 1): 位于硬盘的 MBR (Master Boot Record) 或 EFI 系统分区 (ESP) 的引导扇区。它非常小,主要任务是加载 core.img

    • core.img (Stage 1.5): 包含文件系统驱动(让 GRUB 能识别各种文件系统,如 Ext4, NTFS, FAT32 等)和必要的模块。它负责找到并加载位于 /boot/grub//boot/grub2/ 目录下的 GRUB 模块和配置文件。

    • 模块 (.mod 文件) 和 grub.cfg (Stage 2): GRUB 的大部分功能都在这里以模块的形式存在,包括各种文件系统支持、终端、加密等。grub.cfg 是 GRUB 的主配置文件,定义了引导菜单和每个操作系统或内核的引导参数。

  • 文件系统感知 (Filesystem Awareness): GRUB 可以直接从各种文件系统(而不仅仅是连续扇区)加载文件,这意味着您可以将内核和 initramfs 放在普通的文件系统上。

  • 引导模式 (Boot Modes):

    • BIOS (Legacy) 引导: 传统的引导方式,GRUB 通常安装到 MBR 或分区的引导扇区。

    • UEFI (Unified Extensible Firmware Interface) 引导: 现代主板使用的引导方式。GRUB 的 EFI 应用程序 (grubx64.efi) 放置在 EFI 系统分区 (ESP) 中,由 UEFI 固件直接调用。

  • 配置文件生成体系: GRUB 2 的 grub.cfg 文件不推荐手动编辑。它通过一套脚本自动生成:

    • /etc/default/grub: 用户的全局配置,例如超时时间、默认启动项、内核参数等。

    • /etc/grub.d/ 目录下的脚本: 这些脚本按照数字顺序执行,用于检测系统上的内核、其他操作系统(通过 os-prober)并生成相应的引导条目。**40_custom** 脚本是您添加自定义引导项的最佳位置。

  • GRUB Shell / GRUB Rescue: 当 GRUB 无法找到配置文件或关键文件时,它会进入一个简化的命令行界面,允许用户手动指定文件位置并尝试引导。

2. GRUB 命令行界面 (CLI)

GRUB 命令行是故障排除和高级操作的核心工具。您可以:

  • 在 GRUB 菜单出现时,按 c进入 GRUB 命令行。

  • 当系统无法正常引导,进入 grub>grub rescue> 提示符时。

以下是 GRUB 命令行中最常用和最重要的命令:

2.1 文件系统和设备操作

  • ls: 列出 GRUB 识别的设备和文件系统内容。

    • ls: 列出所有硬盘和分区,例如 (hd0), (hd0,msdos1), (hd0,gpt1)

    • ls (hd0,gpt1)/: 列出 (hd0,gpt1) 分区根目录下的内容。

    • ls (hd0,gpt2)/boot/: 列出 (hd0,gpt2) 分区下 /boot 目录的内容。

    • 用途: 用于找出您的 /boot 分区或根分区。

  • set 查看或设置变量。

  • set root=(hdX,Y): 设置 GRUB 的根设备,这是 GRUB 查找文件(如内核、initramfsgrub.cfg)的起始点。

    • hdX 表示第 X 块硬盘(从 0 开始)。

    • Y 表示分区号,对于 MBR 分区,msdos1 是第一个主分区;对于 GPT 分区,gpt1 是第一个分区。

    • 例子: set root=(hd0,gpt2) 表示将根设备设置为第一个硬盘的第二个 GPT 分区。

  • set prefix=(hdX,Y)/path/to/grub: 设置 GRUB 模块和配置文件的路径。

    • 通常是 set prefix=(hd0,gpt2)/boot/grub (如果 /boot 是独立分区,那么 (hd0,gpt2) 就是 /boot 分区)。

    • 如果 /boot 是根分区的一部分,那么可能是 set prefix=(hd0,gpt2)/grub

    • 用途: 告诉 GRUB 它的模块在哪里,以便它能加载进一步的功能。

  • search 查找文件/标签所在分区 search –file /vmlinuz

  • cat: 查看文件内容。 cat (hd0,1)/boot/grub/grub.cfg

2.2 模块加载

  • insmod <module_name>: 加载 GRUB 模块。当 GRUB 进入 grub rescue> 模式时,通常是因为缺少必要模块,需要手动加载。

    • insmod normal: 加载正常模式模块,用于显示 GRUB 菜单。

    • insmod linux: 加载 Linux 引导模块,以便使用 linuxinitrd 命令。

    • insmod loopback: 加载 loopback 模块,用于从 ISO 文件引导。

    • insmod ext2: 加载 ext2/3/4 文件系统支持模块。

    • insmod fat: 加载 FAT 文件系统支持模块(用于 UEFI 的 ESP)。

    • insmod part_msdos: 加载 MBR (DOS) 分区表支持模块。

    • insmod part_gpt: 加载 GPT 分区表支持模块。

    • 用途: 扩展 GRUB 的功能,使其能够识别文件系统、显示菜单或引导特定操作系统。

  • lsmod: 显示已加载模块。

  • rmmod <module_name>: 卸载模块。rmmod ext2

2.3 引导操作系统

  • linux /path/to/vmlinuz [kernel_parameters]: 加载 Linux 内核。

    • /path/to/vmlinuz: 这是内核文件在 root 设备下的路径。例如 /boot/vmlinuz-5.15.0-XX-generic

    • kernel_parameters: 传递给内核的启动参数。最常用的是 root=/dev/sdXN (指定根文件系统所在的分区) 和 ro (以只读模式挂载根文件系统)。其他常用参数有 quiet, splash (控制启动过程的详细程度和图形界面)。

    • 例子: linux /boot/vmlinuz-5.15.0-78-generic root=/dev/sda2 ro quiet splash

  • initrd /path/to/initrd.img: 加载 initramfs (初始 RAM 文件系统)。

    • /path/to/initrd.img: initramfs 镜像文件在 root 设备下的路径。例如 /boot/initrd.img-5.15.0-XX-generic

    • 用途: initramfs 包含必要的驱动和工具,以便内核能够识别硬件并挂载真正的根文件系统。

  • boot: 执行之前用 linuxinitrd 命令加载的内核。

  • chainloader +1: 用于链式加载另一个引导加载器(如 Windows 的引导管理器)。

    • +1 表示加载当前分区(由 set root 指定)的第一个扇区。

    • 用途: 引导 Windows 或其他非 Linux 操作系统。

  • configfile /path/to/grub.cfg: 加载指定的 GRUB 配置文件。

    • 通常用于在 GRUB 救援模式下,手动找到并加载正确的 grub.cfg

    • 例子: configfile (hd0,gpt2)/boot/grub/grub.cfg

2.4 其他常用命令

  • normal: 如果 prefixroot 已正确设置且 normal 模块已加载,此命令会尝试进入正常的 GRUB 菜单。

  • exit: 退出 GRUB 命令行,尝试继续正常启动流程或重启。

  • reboot: 重启系统。

  • halt: 关闭系统。

  • search --file /path/to/file --set root: 搜索包含特定文件的分区,并将其设置为 root。在不知道具体分区号时非常有用。

    • 例子: search --file /boot/vmlinuz --set root (搜索包含 vmlinuz 的分区,并将其设为根)。
  • test: 评估表达式,用于脚本调试。

  • echo: 在屏幕上显示消息。

除了我们之前讨论的用于文件系统和引导的核心命令 (ls, set root, linux, initrd, boot, chainloader, insmod), GRUB 命令行还提供了其他功能强大的命令,用于调试、配置和特殊引导任务。

3. 变量与流程控制

GRUB 命令行不仅仅是执行命令,它还支持变量和简单的流程控制,这对于编写更复杂的引导脚本或在命令行中调试非常有用。

  • set <variable_name>=<value>: 设置一个 GRUB 环境变量。这些变量只在当前会话中有效,不会持久保存。

    • 用途: 临时存储路径、文件名或引导参数。

    • 示例: set my_kernel_path=/boot/vmlinuz-generic

  • unset <variable_name>: 取消设置一个环境变量。

  • echo <message>: 在屏幕上显示消息。

    • 用途: 调试或提供用户提示。

    • 示例: echo "Attempting to boot Linux..."

  • if...then...else...fi: 条件判断语句。

    • 用途: 根据条件执行不同的引导逻辑,例如检查文件是否存在。

    • 示例:

      代码段

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      if [ -f (hd0,gpt2)/boot/vmlinuz-custom ]; then
      echo "Custom kernel found!"
      linux (hd0,gpt2)/boot/vmlinuz-custom
      initrd (hd0,gpt2)/boot/initrd.img-custom
      boot
      else
      echo "Custom kernel not found, trying default."
      linux (hd0,gpt2)/boot/vmlinuz-standard
      initrd (hd0,gpt2)/boot/initrd.img-standard
      boot
      fi
  • for...in...do...done: 循环语句。

    • 用途: 遍历列表,例如搜索特定文件。

    • 示例: for i in (hd0,gpt*) ; do ls $i/boot/vmlinuz ; done (此示例语法可能因 GRUB 版本略有不同,但理念一致)

  • load_video: 初始化显卡以显示图形菜单。

    • 用途: 如果 GRUB 菜单是文本模式的,加载此模块可以启用更高分辨率的图形模式,前提是你的 grub.cfg 配置了图形模式。

    • 示例: load_video

  • sleep <seconds>: 暂停执行指定的秒数。

    • 用途: 在执行某些操作前提供延迟,例如给用户阅读信息的时间。

    • 示例: sleep 5

4. 磁盘与分区检测

  • probe: 探测设备上的文件系统或分区表。

    • 用途: 获取更多关于设备的信息,例如文件系统类型、UUID 等。

    • 示例: probe --fs-uuid (hd0,gpt2) (获取分区的 UUID)

    • probe --label (hd0,gpt2) (获取分区的标签)

  • search: 根据 UUID、文件标签或特定文件来查找分区。这是在不知道分区号时非常有用的命令。

    • 语法: search [--file <path_to_file>] [--label <label>] [--fs-uuid <uuid>] [--set <variable_name>] [--no-floppy] [--hint-bios=<dev>] [--hint-efi=<dev>]

    • --set <variable_name>: 找到后将分区路径赋值给一个变量。

    • 用途: 自动定位根文件系统或引导分区,尤其在磁盘顺序变化或使用 LiveCD 修复时。

    • 示例:

      代码段

      1
      2
      3
      4
      search --fs-uuid YOUR_ROOT_UUID_HERE --set root_part
      linux ($root_part)/boot/vmlinuz-generic root=UUID=YOUR_ROOT_UUID_HERE ro
      initrd ($root_part)/boot/initrd.img-generic
      boot

      (你需要替换 YOUR_ROOT_UUID_HERE 为你实际的根分区 UUID,通过 blkidls -l /dev/disk/by-uuid/ 查找)

4. 文件操作

  • cat <file>: 显示文件的内容。

    • 用途: 查看 grub.cfg、内核参数文件或任何文本文件的内容进行调试。

    • 示例: cat (hd0,gpt2)/boot/grub/grub.cfg

  • cmp <file1> <file2>: 比较两个文件。

    • 用途: 检查文件是否相同。
  • cp <source_file> <destination_file>: 复制文件。

    • 用途: 在 GRUB 环境中复制文件,例如复制配置文件。
  • rm <file>: 删除文件。

    • 用途: 清理不再需要的文件。
  • md_image (raid): 用于软件 RAID 阵列。如果你的 /boot 位于软件 RAID 上,这个模块是必需的。

    • insmod md_raid0, insmod md_raid1, insmod md_raid5 等:加载特定 RAID 级别支持。

    • 用途: 允许 GRUB 识别并访问 RAID 卷上的文件。

5. 调试与信息

  • terminal_output console / terminal_input console: 设置 GRUB 的输入/输出终端。

    • 用途: 在进行串口调试时非常有用。

    • 示例: terminal_output serial (输出到串口)

  • set debug=all: 开启所有调试输出。

    • 用途: 当 GRUB 行为异常时,开启调试模式可以提供大量诊断信息。
  • clear: 清除屏幕。

  • help [command]: 显示 GRUB 命令的帮助信息。

    • 用途: 学习新命令或回忆命令用法。

    • 示例: help linux

6. 高级引导技术

  • GRUB Scripting: GRUB 命令行支持的变量、条件和循环,使得你可以编写复杂的 GRUB 脚本来处理各种引导场景,远超简单的菜单选择。这在 /etc/grub.d/ 下的脚本中体现得淋漓尽致。

  • 网络引导 (PXE): GRUB 可以通过网络从 PXE 服务器引导操作系统。这需要 tftpdhcp 模块的支持。

    • insmod tftp

    • insmod net

    • set net_default_server=<IP>

    • linux (tftp)/path/to/vmlinuz

    • 用途: 无盘工作站、大规模部署操作系统。

  • 加密磁盘引导: GRUB 支持通过密码解锁加密的 /boot 分区或根文件系统。这涉及到 cryptodiskluks 模块。

    • insmod cryptodisk

    • insmod luks

    • cryptomount -u <UUID>

    • 用途: 增强系统安全性。