GRUB 引导程序
固件把控制权交给磁盘后,真正把内核搬进内存、并把你调到的那行内核参数交给内核的,是引导加载器(bootloader)。Linux 世界里它几乎姓 GRUB——Debian/Ubuntu 与 RHEL/CentOS/Rocky 默认都是 GRUB2,Arch 则把选择权交给用户(GRUB、systemd-boot 或 rEFInd 都常见)。GRUB 是一个完整的小型操作系统:它有菜单、有命令行、能读 ext4/Btrfs 文件系统、能在 32 位保护模式下寻址,这正是它比当年 BIOS 时代那 446 字节的 stub 复杂得多的原因。
理解 GRUB 的关键在于分层:你平时改的是"源"(/etc/default/grub、/etc/grub.d/),系统执行的是"生成物"(grub.cfg),而引导失败时你要动的往往是更底层的"安装"(grub-install 写入 MBR 或 ESP)。把这三层混为一谈,就会出现"改了配置没生效"、"救回来了但菜单还是坏的"这类经典困境。本页从结构讲到配置,再给出一套三系通用的救援流程。
内容参考自 GNU GRUB 手册、Arch Wiki 与鸟哥的私房菜,见文末参考资料。
学习目标
- 分清 GRUB 的两级加载结构(BIOS 与 UEFI 路径差异)
- 理解配置的三层来源,知道为什么不能直接编辑
grub.cfg - 掌握三系重新生成 GRUB 配置与重装 GRUB 的命令差异
- 会用 GRUB 菜单按
e临时修改内核参数(进救援/单用户模式的标准入口) - 掌握 Live USB + chroot 的完整引导救援流程,区分 BIOS 与 UEFI 的
grub-install参数
1. GRUB 的两级结构
BIOS/Legacy 路径
- 第一级:
boot.img——写在 MBR 前 446 字节。它只做一件事:定位并加载第二级。 - 第二级:
core.img——通常紧随 MBR 之后的间隙,或放在 BIOS Boot 分区(GPT 上专为它留的小分区)。core.img包含文件系统驱动,能读出/boot/grub/i386-pc/下的模块,最终加载normal.mod并解析grub.cfg。 grub.cfg读出来后,GRUB 展示菜单,选中项把内核(vmlinuz-*)与 initramfs(initrd.img-*)读入内存,跳转到内核入口。
UEFI 路径
- 固件按 NVRAM 启动项找到 ESP 里的
.efi文件(通常是\EFI\<发行版>\grubx64.efi,或经shimx64.efi中转)。 - 该
.efi文件本身就是完整的 GRUB(EFI 版),它读取 ESP 或/boot/grub/下的grub.cfg。 - 后续与 BIOS 路径一致:菜单 → 加载内核/initramfs → 内核启动。
两条路径的共同终点都是 grub.cfg 和内核镜像;分歧只在"谁把它读出来"。理解这一点,救援时就知道要分别修复:BIOS 要修 MBR/core.img,UEFI 要修 ESP 里的 .efi 文件与 NVRAM 条目。
$ ls /boot/grub/ # Debian/Ubuntu、Arch;RHEL 系为 /boot/grub2/
grub.cfg fonts grubenv locale x86_64-efi/ i386-pc/2. 配置的三层结构
GRUB 的配置是生成式的,这也是新手最容易踩坑的地方:
| 层 | 位置 | 你该不该改 |
|---|---|---|
| 用户变量 | /etc/default/grub | 日常改这里(超时、默认项、内核参数) |
| 菜单生成脚本 | /etc/grub.d/* | 进阶用(自定义菜单项、双系统探测) |
| 最终配置 | /boot/grub/grub.cfg 或 /boot/grub2/grub.cfg | 永远不改,改了也会被覆盖 |
grub.cfg 文件头就写着 "DO NOT EDIT THIS FILE"——它由 grub-mkconfig 调用 grub.d 下的脚本、读取 /etc/default/grub 汇总生成。正确工作流永远是:改源 → 重新生成 → 验证。
$ cat /etc/default/grub
GRUB_DEFAULT=0 # 默认菜单项索引(0 = 第一个),也可写子菜单字符串
GRUB_TIMEOUT=5 # 菜单停留秒数;0 则直接启动默认项(藏菜单)
GRUB_DISTRIBUTOR="Ubuntu" # 菜单里发行版名字
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash" # 追加到正常启动项的参数
GRUB_CMDLINE_LINUX="" # 追加到所有项(含 recovery)的参数
GRUB_DISABLE_OS_PROBER=false # 是否探测 Windows/macOS 生成菜单项GRUB_CMDLINE_LINUX_DEFAULT 与 GRUB_CMDLINE_LINUX 的区别:前者只作用于正常启动项(quiet splash 这类"日常参数"放这里),后者作用于所有项包括恢复模式(root=/dev/sda2 这类"硬性参数"由安装器自动写入)。
修改示例——把默认启动项改为第 2 个、关掉 quiet 便于排障:
$ sudo sed -i 's/GRUB_DEFAULT=0/GRUB_DEFAULT=1/' /etc/default/grub
$ sudo sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"/GRUB_CMDLINE_LINUX_DEFAULT=""/' /etc/default/grub/etc/grub.d/ 下的脚本按文件名数字顺序执行,常见几个:
| 脚本 | 作用 |
|---|---|
00_header | 读取 /etc/default/grub,生成通用设置(主题、超时、模块加载) |
05_debian_theme | 背景图/字体(Debian/Ubuntu) |
10_linux | 扫描 /boot 下的内核并生成 Linux 菜单项(最关键) |
30_os-prober | 探测其他操作系统(Windows、其他发行版) |
40_custom | 留给用户手写菜单项,每次重新生成都会被保留 |
3. 重新生成与重装(三系对照)
重新生成配置(改完 /etc/default/grub 后必做):
# Debian/Ubuntu
$ sudo update-grub
Sourcing file `/etc/default/grub'
Found linux image: /boot/vmlinuz-6.8.0-45-generic
Found initrd image: /boot/initrd.img-6.8.0-45-generic
Found Windows Boot Manager on /dev/sda1@/EFI/Microsoft/Boot/bootmgfw.efi
done
# Arch(显式指定输出路径)
$ sudo grub-mkconfig -o /boot/grub/grub.cfg
# RHEL/CentOS/Rocky(二进制与路径都带 2)
$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg重装 GRUB 本身(引导代码损坏、换磁盘、chroot 救援时用)——这一步才是"写 MBR"或"写 ESP":
# BIOS/Legacy:写入整块磁盘的 MBR(注意是磁盘,不是分区)
$ sudo grub-install /dev/sda
# UEFI:写入 ESP 并向 NVRAM 注册启动项
$ sudo grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=GRUB
# --efi-directory:ESP 挂载点(Arch 若 ESP 挂 /boot 则改为 /boot)
# --bootloader-id:ESP 下 EFI/ 后的目录名,也是 NVRAM 条目显示名
# RHEL 系(命令名带 2)
$ sudo grub2-install /dev/sda # BIOS
$ sudo grub2-install --target=x86_64-efi --efi-directory=/boot/efi # UEFI常见坑:
- UEFI 下漏写
--efi-directory——GRUB 会默认找/boot/efi,若你的 ESP 挂在/boot(Arch 常见布局)就会装错位置,重启后 NVRAM 指向的文件不存在。 - 把分区当磁盘传给
grub-install——BIOS 模式应传/dev/sda(磁盘),不是/dev/sda1(分区)。传错通常会报this utility will not install grub to one of your platform firmware或静默装到错误位置。 - 生成了
grub.cfg但没grub-install——只修了菜单、没修引导代码,开机依然停在grub>提示符或no bootable device。 - Arch 上用
update-grub——该命令是 Debian 专属脚本,Arch 没有,直接command not found。Arch 一律用grub-mkconfig -o ...。
4. 临时修改内核参数(GRUB 菜单按 e)
不需要改配置文件、重启立即生效的排障入口:开机出现 GRUB 菜单时按 e 进入编辑模式,找到以 linux(或 linuxefi/linux16)开头的行,在行尾追加参数,然后按 Ctrl+X(或 F10)以修改后的参数启动。
linux /boot/vmlinuz-6.8.0-45-generic root=UUID=... ro quiet splash $vt_handoff
# ↑ 光标移到行尾,空格追加 systemd.unit=rescue.target,再按 Ctrl+X 启动常用救援参数:
| 参数 | 用途 |
|---|---|
systemd.unit=rescue.target | 救援模式(单用户 + 网络关闭,需 root 密码) |
systemd.unit=emergency.target | 紧急模式(最小环境,initramfs 阶段失败后用) |
init=/bin/bash | 直接以 bash 当 PID 1(无需密码,改 fstab/sudoers 后补救) |
systemd.unit=multi-user.target | 不启动图形界面(Xorg 驱动坏了时进 tty) |
ro → rw | 强制以读写挂载根分区(只读导致改不了文件时) |
rd.break(RHEL 系 initramfs) | 在挂载真实根之前停下,改 root 密码用 |
改 root 密码的标准路径(三系通用思路):GRUB 菜单按 e → 在 linux 行末尾加 rw init=/bin/bash → Ctrl+X 进 root shell → mount -o remount,rw /(若已是 rw 则跳过)→ passwd root → exec /sbin/init 或直接 reboot。这条链不依赖知道旧密码,也是物理接触机器时的安全边界来源——服务器机房锁好、BIOS 设密码,都是在补这层"物理 = 最高权限"的洞。
编辑完菜单后,这只是本次启动临时生效;要永久生效仍需改 /etc/default/grub 并重新生成。
5. 引导失败救援流程(Live USB + chroot)
适用场景:开机停在 grub> 提示符、error: no such partition、kernel panic - not syncing: VFS: Unable to mount root fs、或 NVRAM 里根本没有启动项。
三系共用的骨架如下,差异集中在 grub-install/生成配置的命令名与路径上:
# ---- 1. Live USB 启动,确认磁盘布局 ----
$ lsblk -f # 假设 sda1 = ESP(FAT32),sda2 = ext4 根分区
# ---- 2. 挂载根分区 ----
$ sudo mount /dev/sda2 /mnt
# ---- 3. 挂载 ESP(UEFI 救援必做;Arch 常见为 /mnt/boot)----
$ sudo mount /dev/sda1 /mnt/boot/efi
# ---- 4. 绑定虚拟文件系统 ----
$ sudo mount --bind /dev /mnt/dev
$ sudo mount --bind /proc /mnt/proc
$ sudo mount --bind /sys /mnt/sys
$ sudo mount --bind /run /mnt/run
# ---- 5. 进入 chroot(此后 / 即原系统根)----
$ sudo chroot /mnt
# ---- 6a. BIOS:重装到磁盘 MBR(RHEL 系用 grub2-install)----
grub-install /dev/sda
# ---- 6b. UEFI:重装到 ESP(Arch 若 ESP 挂 /boot 则 --efi-directory=/boot)----
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=GRUB
# ---- 7. 重新生成配置(按发行版选一条)----
update-grub # Debian/Ubuntu
# grub-mkconfig -o /boot/grub/grub.cfg # Arch
# grub2-mkconfig -o /boot/grub2/grub.cfg # RHEL/CentOS/Rocky
# ---- 8. 内核也损坏时重建 initramfs(三系各一条)----
# update-initramfs -u / mkinitcpio -P / dracut --force
# ---- 9. 退出并重启 ----
exit
sudo umount -R /mnt
sudo reboot判断走 6a 还是 6b:回到第 0 步——Live 环境里 ls /sys/firmware/efi 存在说明固件是 UEFI,对应 6b;不存在则对应 6a。另可看 ESP 是否存在(有 c12a7328-... 类型的 FAT 分区基本就是 UEFI)。
只修 NVRAM、不重写文件:如果 efibootmgr -v 显示 GRUB 条目还在,只是顺序乱了,根本不用 chroot,直接 sudo efibootmgr -o 调顺序即可。救援的复杂度应与损坏层级匹配——先用只读命令定位,再决定动哪一层。
6. 三系差异速览
| 主题 | Debian/Ubuntu | Arch | RHEL/CentOS/Rocky |
|---|---|---|---|
| 默认 bootloader | GRUB2 | 用户选择(GRUB / systemd-boot / rEFInd) | GRUB2 |
| 配置源 | /etc/default/grub、/etc/grub.d/ | 同左(GRUB);systemd-boot 用纯文本 entry 文件 | /etc/default/grub、/etc/grub.d/ |
| 生成的配置 | /boot/grub/grub.cfg | /boot/grub/grub.cfg | /boot/grub2/grub.cfg |
| 重新生成 | sudo update-grub | sudo grub-mkconfig -o /boot/grub/grub.cfg | sudo grub2-mkconfig -o /boot/grub2/grub.cfg |
| 重装(BIOS) | grub-install /dev/sda | grub-install /dev/sda | grub2-install /dev/sda |
| 重装(UEFI) | grub-install --target=x86_64-efi ... | 同左,注意 --efi-directory | grub2-install --target=x86_64-efi ... |
| 典型 ESP 挂载点 | /boot/efi | /boot(ESP 即 /boot,Wiki 推荐) | /boot/efi |
| initramfs 工具 | update-initramfs | mkinitcpio | dracut |
| 双系统菜单探测 | os-prober(update-grub 自动调用) | 需自行 pacman -S os-prober 并在 grub.d 启用 | os-prober(grub2-mkconfig 自动调用) |
7. 常见坑
改了
/etc/default/grub但菜单没变。忘记重新生成。改源永远只是第一步,update-grub/grub-mkconfig/grub2-mkconfig才是"提交"。直接编辑
grub.cfg。下次重新生成会被覆盖,且文件头已警告。改源或改40_custom。救援时
grub-install报找不到 EFI 变量或目录。多半是 chroot 后 ESP 没挂、或--efi-directory路径与实际挂载点不符。先在 chroot 里mount | grep efi、ls /boot/efi确认。Arch 上 ESP 挂成
/boot,却照抄 Debian 的/boot/efi路径。两处都要对齐:挂载点、--efi-directory、grub-mkconfig -o的输出路径。GRUB_TIMEOUT=0 导致看不到菜单、进不了救援参数入口。开机时疯狂按
Shift(BIOS)或Esc(部分 UEFI/GRUB 构建)可强制弹出菜单;或临时GRUB_TIMEOUT=3重新生成。只跑了
grub-install没跑grub-mkconfig(或反过来)。前者修"引导器本体",后者修"菜单内容";引导失败往往两层都有问题,救援流程里两步都要执行。Btrfs 根分区 + 多级子卷时
root=指向错误。grub.cfg里root=UUID=...必须指向子卷(如@),不是顶层设备。用cat /etc/fstab对照确认,救援时这一步错了内核会 panic 在挂根阶段。
参考资料
- GNU GRUB 手册 — gnu.org
- Arch Wiki - GRUB — wiki.archlinux.org
- Arch Wiki - systemd-boot(替代方案对照) — wiki.archlinux.org
- Arch Wiki - Kernel parameters — wiki.archlinux.org
- Debian Wiki - GRUB — wiki.debian.org
- RHEL 9 - 使用 GRUB2 配置系统引导(内核命令行参数章节) — docs.redhat.com
- 鸟哥的私房菜 - 开机流程与 GRUB — linux.vbird.org
man grub-install、man grub-mkconfig、man grub-reboot、man os-prober