Linux内核启动源码分析与初始化故障排查 - 第4节
4.1 GRUB2 配置文件 (grub.cfg) 的结构与语法
GRUB2 的核心配置文件为 /boot/grub/grub.cfg(或 /boot/grub2/grub.cfg)。该文件由 grub2-mkconfig 工具根据 /etc/default/grub 和 /etc/grub.d/ 目录下的脚本自动生成。理解其结构是分析内核加载流程的第一步。
4.1.1 配置文件层级结构
grub.cfg 采用嵌套的菜单项结构,核心语法包括:
- 菜单项定义:
menuentry "标题" { ... } - 子菜单定义:
submenu "标题" { ... } - 全局设置:
set default="0"、set timeout=5 - 加载模块:
insmod ext2、insmod lvm - 内核与 initrd 加载:
linux、initrd命令
grub.cfg 是只读文件,用户不应直接编辑。所有自定义修改应通过 /etc/default/grub 和 /etc/grub.d/40_custom 完成,然后执行 grub2-mkconfig -o /boot/grub2/grub.cfg 重新生成。
4.1.2 典型菜单项结构
以下是一个标准 Linux 内核启动菜单项的完整示例:
menuentry 'CentOS Linux (5.10.0-60.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os {
load_video
set gfxpayload=keep
insmod gzio
insmod part_msdos
insmod ext2
set root='hd0,msdos1'
linux /vmlinuz-5.10.0-60.el7.x86_64 root=/dev/mapper/cl-root ro crashkernel=auto rd.lvm.lv=cl/root rd.lvm.lv=cl/swap rhgb quiet
initrd /initramfs-5.10.0-60.el7.x86_64.img
}
| 命令/指令 | 作用说明 |
|---|---|
load_video |
加载视频驱动模块,支持图形化显示 |
set gfxpayload=keep |
保持图形模式,传递给内核 |
insmod gzio |
加载 gzip 解压模块,支持压缩的内核/initrd |
insmod part_msdos |
加载 MBR 分区表支持 |
insmod ext2 |
加载 ext2/3/4 文件系统驱动 |
set root='hd0,msdos1' |
设置根设备为第一块硬盘的第一个分区 |
linux |
指定内核映像路径及启动参数 |
initrd |
指定 initramfs 映像路径 |
4.2 菜单显示与用户交互
GRUB2 在加载配置文件后,会解析所有 menuentry 和 submenu 并构建启动菜单。用户可通过键盘选择、编辑启动项,或进入命令行模式。
4.2.1 菜单显示流程
4.2.2 菜单编辑与参数传递
在菜单界面按 e 键可进入编辑模式,用户可临时修改当前菜单项的启动参数。常见编辑场景包括:
- 修改 root 参数:如将
root=/dev/sda1改为root=/dev/sdb1 - 添加调试参数:如追加
single进入单用户模式,或rd.break中断 initramfs - 禁用 rhgb/quiet:移除这两个参数可查看完整的内核启动日志
/etc/default/grub 中的 GRUB_CMDLINE_LINUX 变量。
4.3 内核加载过程
当用户选择某个菜单项后,GRUB2 开始执行 linux 命令,将内核映像从磁盘加载到内存,并准备启动参数。
4.3.1 内核映像的定位与加载
GRUB2 根据 set root 指定的分区定位内核文件,然后通过文件系统驱动读取 /vmlinuz-* 文件。加载过程分为两个阶段:
- 读取内核头部:解析 ELF 或 bzImage 格式,获取入口地址、段信息
- 加载内核到内存:将内核代码段、数据段复制到指定物理地址(通常为 0x100000 即 1MB 处)
4.3.2 启动参数的传递
linux 命令中 root= 之后的全部内容构成内核命令行(kernel command line)。GRUB2 将这些参数按约定格式写入内存中的特定位置,内核在启动初期通过 boot_params 结构体读取。
| 参数类别 | 示例 | 说明 |
|---|---|---|
| 根文件系统 | root=/dev/mapper/cl-root |
指定内核挂载的根设备 |
| 挂载选项 | ro |
以只读方式挂载根文件系统(后续由 init 重新挂载为 rw) |
| LVM 逻辑卷 | rd.lvm.lv=cl/root |
initramfs 阶段激活 LVM 卷 |
| 调试与显示 | rhgb quiet |
图形化启动(Red Hat Graphical Boot),隐藏详细日志 |
| 内存配置 | crashkernel=auto |
为 kdump 预留内存 |
4.4 initrd / initramfs 的加载与传递
在 linux 命令之后,GRUB2 执行 initrd 命令,将 initramfs 映像加载到内存中,并将内存地址信息传递给内核。
4.4.1 initramfs 的作用
initramfs(initial RAM filesystem)是一个压缩的 cpio 归档文件,包含内核启动初期所需的驱动、工具和脚本。其核心使命是:
- 加载存储驱动:如 SCSI、NVMe、SATA 驱动,使内核能访问根文件系统
- 激活卷管理:如 LVM、MD RAID、dm-crypt
- 挂载根文件系统:执行 pivot_root 切换到真正的根
4.4.2 加载与解压流程
- GRUB2 读取 initramfs 文件:从磁盘读取
/initramfs-*.img到内存缓冲区 - 记录内存地址:将 initramfs 的起始地址和大小写入
boot_params结构体 - 内核解压:内核启动后,从指定地址读取 initramfs,解压到 rootfs 中
- 执行 /init:内核挂载 rootfs 后,执行其中的
/init脚本
4.4.3 多 initrd 支持
GRUB2 支持同时加载多个 initrd 映像,通过 initrd 命令后跟多个路径实现:
initrd /initramfs-5.10.0-60.el7.x86_64.img /microcode.img
其中 microcode.img 包含 CPU 微码更新,内核会优先处理微码,再加载主 initramfs。
4.5 启动流程总结
从 GRUB2 配置文件解析到内核与 initramfs 加载完成,整个流程可归纳为以下关键步骤:
| 步骤 | 操作 | 关键组件 |
|---|---|---|
| 1 | 读取并解析 grub.cfg | GRUB2 核心、文件系统驱动 |
| 2 | 显示启动菜单,等待用户选择 | gfxterm / 文本终端 |
| 3 | 执行 linux 命令,加载内核到内存 | vmlinuz、boot_params |
| 4 | 执行 initrd 命令,加载 initramfs | initramfs.img、cpio 归档 |
| 5 | 跳转到内核入口点,移交控制权 | startup_32 / startup_64 |
grub2-editenv list 查看当前默认启动项,使用 grub2-set-default 切换默认项。通过 cat /proc/cmdline 查看实际传递给内核的命令行参数,与 grub.cfg 中的配置进行对比验证。