Linux内核启动链路分析与系统初始化调试 - 第4节

4.1 GRUB2 配置文件结构

GRUB2(GRand Unified Bootloader version 2)是当前 Linux 发行版默认的引导管理器。其核心配置文件为 /boot/grub/grub.cfg,该文件由 grub-mkconfig 工具根据 /etc/default/grub 和 /etc/grub.d/ 目录下的脚本自动生成。

4.1.1 配置文件层级与生成流程

GRUB2 采用“模板 + 脚本”的生成式配置架构,用户不应直接编辑 grub.cfg,而应修改 /etc/default/grub 或 /etc/grub.d/ 下的脚本。

组件 路径 作用
主配置文件 /boot/grub/grub.cfg GRUB2 实际读取的引导菜单与参数
用户配置 /etc/default/grub 定义超时、默认菜单项、内核参数等全局变量
脚本目录 /etc/grub.d/ 包含 00_header、10_linux、30_os-prober 等生成模块
生成命令 grub-mkconfig -o /boot/grub/grub.cfg 合并配置与脚本,输出最终配置文件
关键原则:每次修改 /etc/default/grub 或 /etc/grub.d/ 后,必须执行 grub-mkconfig -o /boot/grub/grub.cfg 才能生效。

4.1.2 grub.cfg 核心语法

grub.cfg 使用 GRUB2 脚本语言,支持函数、变量、条件判断和菜单项定义。以下是一个典型的内核启动菜单项:

menuentry 'Ubuntu, with Linux 5.15.0-91-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.0-91-generic-advanced-xxxxxxxx' {
    recordfail
    load_video
    gfxmode $linux_gfx_mode
    insmod gzio
    if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
    insmod part_gpt
    insmod ext2
    set root='hd0,gpt2'
    if [ x$feature_platform_search_hint = xy ]; then
      search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2  xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    else
      search --no-floppy --fs-uuid --set=root xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    fi
    linux   /boot/vmlinuz-5.15.0-91-generic root=UUID=yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy ro  quiet splash
    initrd  /boot/initrd.img-5.15.0-91-generic
}
语法要点:
  • menuentry 定义菜单项,花括号内为启动指令序列。
  • set root 指定根设备(分区),支持 hd0,gpt2 或 UUID 方式。
  • linux 指令加载内核映像并传递命令行参数。
  • initrd 指令加载初始 RAM 磁盘映像。

4.1.3 配置文件结构 SVG 图

GRUB2 配置文件生成结构 /etc/default/grub /etc/grub.d/ 脚本目录 grub-mkconfig 工具 /boot/grub/grub.cfg 最终引导配置文件 GRUB2 运行时解析 grub.cfg 显示引导菜单 加载内核 + initrd 用户应修改 /etc/default/grub 和 /etc/grub.d/,然后运行 grub-mkconfig 生成 grub.cfg

4.2 菜单选择机制

GRUB2 在启动时读取 grub.cfg 并解析所有 menuentry 块,生成可交互的引导菜单。用户可通过键盘选择启动项,或等待超时自动启动默认项。

4.2.1 菜单选择流程

  1. 加载配置文件:GRUB2 从 /boot/grub/grub.cfg 读取菜单项和全局设置。
  2. 解析默认项:读取 set default="0" 或 set default="saved" 确定默认启动项。
  3. 设置超时:读取 set timeout=5,若超时内无按键则自动启动默认项。
  4. 显示菜单:在屏幕上列出所有 menuentry 标题,等待用户选择。
  5. 执行指令:用户选择或超时后,执行对应 menuentry 块内的指令序列。

4.2.2 关键变量与参数

变量 示例值 说明
default 0、saved、"Ubuntu" 默认启动项索引、名称或 saved(记住上次选择)
timeout 5、-1 自动启动等待秒数;-1 表示无限等待
gfxmode auto、1024x768 图形模式分辨率
recordfail — 记录上次启动失败,用于故障恢复菜单
常见问题:若 timeout 设置为 0,GRUB2 将不显示菜单直接启动默认项。如需强制显示菜单,可在启动时按住 Shift 键(BIOS)或 Esc 键(UEFI)。

4.2.3 菜单选择流程 SVG 图

GRUB2 菜单选择与启动流程 读取 grub.cfg 解析 default / timeout 显示引导菜单 用户选择菜单项 超时自动启动默认项 执行 menuentry 指令序列:加载内核与 initrd

4.3 内核与 initrd 加载过程

当用户选择某个菜单项后,GRUB2 执行该 menuentry 块内的指令序列,核心步骤包括:设置根设备、加载内核映像、加载 initrd 映像、传递控制权。

4.3.1 加载步骤详解

步骤 指令 说明
1. 设置根设备 set root='hd0,gpt2' 指定内核和 initrd 所在的分区
2. 加载内核 linux /boot/vmlinuz-xxx root=UUID=yyy ro quiet 将内核映像从磁盘读入内存,并附加命令行参数
3. 加载 initrd initrd /boot/initrd.img-xxx 将初始 RAM 磁盘映像读入内存
4. 启动内核 boot(隐式执行) GRUB2 将控制权交给内核,内核开始执行

4.3.2 内核命令行参数

linux 指令后的参数直接传递给内核,常见参数包括:

  • root=UUID=...:指定根文件系统的 UUID。
  • ro:以只读方式挂载根文件系统(后续由 init 重新挂载为读写)。
  • quiet:减少内核启动时的日志输出。
  • splash:显示启动画面(plymouth)。
  • nomodeset:禁用内核模式设置,用于显卡驱动问题排查。
  • single 或 1:进入单用户模式(维护模式)。
调试技巧:在 GRUB2 菜单界面按 e 键可编辑当前菜单项,临时修改 linux 行参数(如删除 quiet splash 添加 single),按 Ctrl+X 或 F10 启动。此修改仅本次生效。

4.3.3 initrd 的作用

initrd(Initial RAM Disk)是一个临时的根文件系统,包含内核启动初期所需的驱动和工具。其核心使命是:

  1. 加载存储控制器驱动(如 SCSI/NVMe/AHCI)。
  2. 加载文件系统驱动(如 ext4、xfs、btrfs)。
  3. 解密加密的根分区(LUKS)。
  4. 挂载真正的根文件系统。
  5. 执行 switch_root 将控制权移交给真正的 init 系统(systemd)。

4.3.4 内核与 initrd 加载流程 SVG 图

内核与 initrd 加载流程 阶段1:set root 设置根设备 阶段2:linux 加载内核映像 阶段3:initrd 加载 initrd 映像 阶段4:boot 移交控制权给内核 内核初始化:解压 initrd → 加载驱动 → 挂载根文件系统 → 启动 systemd initrd 是临时根文件系统,负责加载必要驱动并挂载真正的根分区,之后通过 switch_root 切换到实际根文件系统

4.4 实战:手动编辑 GRUB2 菜单项

以下演示如何在 GRUB2 启动时临时修改内核参数,用于故障排查或单用户模式恢复。

4.4.1 操作步骤

  1. 系统启动时,在 GRUB2 菜单界面按 e 键进入编辑模式。
  2. 使用方向键定位到以 linux 开头的行。
  3. 在行尾添加或修改参数,例如将 quiet splash 替换为 single。
  4. 按 Ctrl+X 或 F10 使用修改后的参数启动。
# 原始 linux 行
linux   /boot/vmlinuz-5.15.0-91-generic root=UUID=xxxx ro quiet splash

# 修改后(进入单用户模式)
linux   /boot/vmlinuz-5.15.0-91-generic root=UUID=xxxx ro single
注意:临时编辑不会保存到 grub.cfg。如需永久修改,应编辑 /etc/default/grub 中的 GRUB_CMDLINE_LINUX_DEFAULT 变量,然后运行 grub-mkconfig -o /boot/grub/grub.cfg。

4.4.2 永久修改示例

# 编辑 /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
# 修改为
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash nomodeset"

# 更新 grub.cfg
sudo grub-mkconfig -o /boot/grub/grub.cfg

4.5 本章小结

  • GRUB2 配置文件采用生成式架构,grub.cfg 由 grub-mkconfig 根据 /etc/default/grub 和 /etc/grub.d/ 自动生成。
  • 菜单选择流程包括读取配置、解析默认项、显示菜单、等待用户选择或超时自动启动。
  • 内核加载过程分为设置根设备、加载内核映像、加载 initrd 映像、移交控制权四个阶段。
  • initrd 是临时根文件系统,负责加载驱动并挂载真正的根文件系统。
  • 在 GRUB2 菜单按 e 可临时编辑内核参数,用于调试和故障恢复。