从零写OS内核 | Windows Boot Manager vs GRUB:两种引导加载器的完整解析
从 360 到 362,我们讲了 BIOS/UEFI → MBR/GPT → GRUB 的启动链路。GRUB 是 Linux 的标配 bootloader,但 Windows 用的是另一套完全不同的系统——BOOTMGR(Boot Manager)和 BCD(Boot Configuration Data)。
你有没有想过这些问题:
- Windows 的”系统保留分区”(System Reserved)里到底装了什么?
- 为什么重装 Windows 会把 GRUB 覆盖掉,但反过来不会?
bcdedit命令改的到底是什么东西?- 为什么 Windows 10/11 可以从 VHD 文件启动,而不需要虚拟磁盘?
- GRUB 1 和 GRUB 2 有什么区别?为什么有些系统还在用 GRUB 1?
今天,我们来深入拆解这两种引导加载器——Windows 的 BOOTMGR + BCD,以及 GRUB 的 Stage 1/Stage 2 进化史。
Windows 引导加载器:BOOTMGR 的完整链路
三种固件模式,三种启动链路
Windows 的启动链路由固件类型决定:
Legacy BIOS + MBR:
POST → MBR(0x7C00) → BOOTMGR(C:BootBOOTMGR) → {BCD 在 C:}
UEFI + GPT(最常见):
POST → UEFI → NVRAM BootOrder → EFIMicrosoftBootbootmgfw.efi
→ BCD(C:BootBCD) → winload.efi → ntoskrnl.exe
Legacy BIOS + GPT(少见):
POST → MBR(Protective) → BIOS Boot Partition(GRUB/BOOTMGR 共存)
→ BOOTMGR → BCD我们重点讲最常见的 UEFI + GPT 链路。
BOOTMGR 是什么
BOOTMGR 是 Windows 的 Boot Manager,一个 32 位的压缩可执行文件(NTFS 压缩属性开启)。它的职责是:
- 读取 BCD(启动配置数据)
- 显示启动菜单(如果有多条启动项)
- 加载 Windows 启动加载器(winload.exe / winload.efi)
BOOTMGR 文件位置(UEFI 模式):
C:EFIMicrosoftBootbootmgfw.efi
BCD 文件位置:
C:BootBCD (UEFI 模式下在 ESP 根目录的 Boot 里)
BOOTMGR 依赖的系统文件:
C:WindowsSystem32winload.efi ← 真正的 Windows 内核加载器
C:WindowsSystem32ntoskrnl.exe ← Windows 内核本体System Reserved 分区(系统保留分区)
安装 Windows 时,如果用的是 MBR 磁盘,Windows 会自动创建一个 100MB 的 System Reserved 分区(也称”系统分区”)。这个分区包含:
System Reserved 分区内容:
├── Boot ← 启动文件夹
│ ├── BCD ← 启动配置数据
│ ├── BOOTMGR ← Windows Boot Manager
│ ├── fonts ← 启动字体(中文等)
│ └── Resources ← 启动动画资源
└── System Volume Information ← 锁定的元数据目录作用:即使 Windows 的 C 盘损坏或被格式化,System Reserved 分区里的 BOOTMGR + BCD 还在,可以启动修复环境(WinRE)。这也是为什么 Windows 10/11 安装时默认勾选”为 Windows 创建系统分区”——它不是浪费空间,是保命分区。
GPT 模式下不需要这个分区:UEFI 模式下,ESP(EFI System Partition)承担了 System Reserved 的角色,BCD 和 BOOTMGR 都存在 ESP 的 Boot 目录里。
BCD:启动配置的”注册表”
BCD(Boot Configuration Data)不是普通文件,是 Windows 的一个注册表配置单元(Registry Hive)。它存储在 BootBCD,和 Linux 的 grub.cfg 承担类似的信息角色——”从哪里加载内核”、”启动参数是什么”、”超时多久”——但格式完全不同。
BCD 用 registry 格式存储,里面有多个键,常见的有:
BCD 内容(bcdedit /store C:BootBCD /enum all 的简化视图):
{bootmgr}
device = partition=C: ← BOOTMGR 在哪个分区
locale = zh-CN ← 启动菜单语言
{default}
description = Windows 10 ← 默认启动项名称
osdevice = partition=C: ← Windows 在哪个分区
device = partition=C:
path = Windowssystem32winload.efi ← 内核加载器路径
systemroot = Windows
{memdiag}
description = Windows Memory Diagnostic ← 内存诊断工具
{ntfs}
description = 从 VHD 启动 (TEST) ← VHD 启动项
filepath = VHDstest.vhdx
devices = vhdbcdedit:Windows 的”GRUB 配置编辑器”
Linux 用文本编辑器改 grub.cfg,Windows 用 bcdedit.exe 命令行操作 BCD:
# 查看所有启动项(需要管理员权限)
bcdedit /enum all
# 查看当前启动项详细信息
bcdedit
# 修改启动项名称
bcdedit /set {default} description "Windows 10 Pro"
# 设置默认操作系统(从 GRUB 跳 Windows 时用)
bcdedit /default {default}
# 添加启动参数(禁用 DEP 等)
bcdedit /set "{default}" nx AlwaysOff
# 创建 VHD 启动项
bcdedit /copy {default} /d "Windows from VHD"
bcdedit /set "{new}" device vhd=[C:]VHDswin10.vhdx
bcdedit /set "{new}" osdevice vhd=[C:]VHDswin10.vhdx
bcdedit /set "{new}" path Windowssystem32winload.efi启动过程:winload.exe 之前发生了什么
UEFI 固件 → NVRAM BootOrder →
→ EFIMicrosoftBootbootmgfw.efi(UEFI 模式)
→ 挂载 FAT32 ESP,读 BootBCD
→ 显示启动菜单(或直接加载默认项)
→ 读取 BCD 的 {default} / osdevice
→ 定位 Windows 分区(C:)
→ 加载 WindowsSystem32winload.efi
→ 验证启动签名(Secure Boot)
→ 读取 WindowsSystem32configSYSTEM 注册表(获取驱动列表)
→ 加载内核 ntoskrnl.exe + 驱动
→ 启动 WindowsLegacy BIOS 模式:
POST → MBR → BOOTMGR(从 System Reserved 分区加载)
→ 读 C:BootBCD → winload.exe(非 EFI 版本)→ ntoskrnl.exeWinRE(Windows Recovery Environment)
Windows 安装后,会在系统分区里预留 WinRE 的路径:
# 检查 WinRE 状态
reagentc /info
# 输出示例:
# Windows Recovery Environment (Windows RE)
# 位置: ?GLOBALROOTdeviceharddisk0partition1RecoveryWindowsRE
# WinRE 启用: true如果 Windows 启动失败,按 F8 或(在 Win 10/11 里)长按电源键强制关机 3 次,Windows 会自动进入 WinRE——它实际上是一个精简的 Windows PE 环境,可以运行 diskpart、bcdedit、sfc /scannow 等修复工具。
VHD 原生启动:Windows 的”虚拟机启动”
从 Windows 7 之后,Windows 支持从 VHD(Virtual Hard Disk) 文件原生启动——不需要虚拟机,直接把 VHD 当作物理磁盘:
工作原理:
1. BCD 里有专门的 {ntfs} 条目,device=vhd
2. BOOTMGR 识别 VHD 类型,把 VHD 文件映射为"虚拟磁盘"
3. 从 VHD 里的 Windows 启动(和从物理盘启动完全一样)
# 创建 VHD 并附加为启动盘
diskpart
create vdisk file=C:VHDswin10.vhdx maximum=60000 type=fixed
attach vdisk这和 Linux 的 LVM 逻辑卷类似——逻辑卷不需要分区表,直接被当作”物理分区”用。
GRUB:完整阶段解析
GRUB 1(GRUB Legacy):Stage 结构
最初的 GRUB(现在叫 GRUB Legacy)设计于 1999 年,它的工作方式非常直白:
GRUB Legacy 启动阶段(MBR + 文件系统配合):
Stage 1(MBR,446 字节):
└── 放在 MBR 里,跳到 Stage 2(或 Stage 1.5)
Stage 1.5(MBR 后扇区,可选):
└── 理解文件系统(ext2/reiserfs/fat),找到 Stage 2
└── e2fs_stage1_5 → ext2 文件系统支持
└── ffs_stage1_5 → UFS/FFS 支持
└── ffs_stage1_5 → FAT 文件系统支持
Stage 2(/boot/grub/stage2):
└── GRUB 主程序,读取 menu.lst
└── 显示启动菜单
└── 加载内核 + initrd为什么要有 Stage 1.5?
Stage 1 只有 446 字节,放不下文件系统驱动——它只知道”从哪个扇区读下一段代码”。Stage 1.5 把文件系统驱动塞进 MBR 后的扇区(通常占用几十个扇区),让 GRUB 可以读取 /boot/grub/stage2。
没有 Stage 1.5,GRUB 无法理解文件系统,就找不到 Stage 2——Stage 2 在 /boot/grub/ 目录里,不在固定扇区。
GRUB 2(GRUB):模块化重写
2005 年后,GRUB 进行了完全重写,变成了 GRUB 2。主要变化:
| 特性 | GRUB Legacy | GRUB 2 |
|---|---|---|
| 配置文件 | menu.lst |
grub.cfg(自动生成,勿手动编辑) |
| 阶段结构 | Stage 1 / 1.5 / 2 | boot.img + core.img(动态生成) |
| 模块化 | 无(文件系统驱动硬编码) | 模块按需加载(.mod 文件) |
| 分区支持 | MBR 为主 | MBR + GPT + UEFI |
| 安装方式 | grub-install(简单) |
grub-install(自动生成 core.img) |
| 脚本支持 | 无 | 条件判断、循环、变量 |
GRUB 2 的引导阶段:
UEFI GRUB 2(最常见):
EFIubuntugrubx64.efi(或 shimx64.efi for Secure Boot)
├── 加载 grub.cfg
├── 加载模块(.mod 文件,从 /boot/grub/x86_64-efi/ 目录)
├── 读取 menu entries
└── 加载内核 + initrd
MBR GRUB 2:
boot.img(446 字节,MBR)→ core.img(嵌入式,包含基础模块 + 启动加载器)
└── boot.img 跳到 core.img(core.img 大小约 32KB,包含:
- 基础文件系统和驱动(ext2/fat/nfs 等)
- 压缩模块加载器
- 启动菜单和内核加载逻辑)
└── 从 /boot/grub/ 加载更多 .mod 模块
└── 读取 grub.cfgGRUB 2 的配置文件:grub.cfg
GRUB 2 的配置文件不是手写的——它是 grub-mkconfig(即 update-grub)自动生成的:
# 生成 /boot/grub/grub.cfg(自动检测内核和其他 OS)
sudo grub-mkconfig -o /boot/grub/grub.cfg
# 或者(Debian/Ubuntu)
sudo update-grubgrub-mkconfig 会扫描:
/boot/vmlinuz-*(Linux 内核)/boot/initrd-*(initramfs)/etc/grub.d/下的自定义脚本(40_custom 等)/etc/default/grub(全局默认参数)- 其他分区上的 OS(Windows bootmgfw.efi、Mac 等)
生成的 grub.cfg 示例:
# /boot/grub/grub.cfg(自动生成,不要手动改)
set timeout=5
set default=0
menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu {
recordfail
load_video
gfxmode $linux_gfx_mode
insmod gzio
insmod part_gpt
insmod ext2
search --no-floppy --fs-uuid --set=root 5a3c9f2b-1d2e-4f8a-9c3b
linux /boot/vmlinuz-6.5.0-rc7 root=UUID=5a3c9f2b-1d2e-4f8a-9c3b ro quiet splash
initrd /boot/initrd.img-6.5.0-rc7
}
menuentry 'Windows 10 (on /dev/sda1)' {
insmod ntfs
search --no-floppy --fs-uuid --set=root A2B3C4D5
chainloader +1
}/etc/default/grub:GRUB 2 的全局配置
grub.cfg 是自动生成的,手动改它没有意义(下次 update-grub 就没了)。真正的全局配置在 /etc/default/grub:
# /etc/default/grub
GRUB_DEFAULT=0 # 默认启动项(0=第一个,saved=记住上次选择)
GRUB_TIMEOUT=5 # 超时(秒)
GRUB_TIMEOUT_STYLE=hidden # 隐藏菜单(按 ESC 显示)
GRUB_CMDLINE_LINUX="quiet splash" # 内核启动参数
GRUB_DISABLE_RECOVERY="true" # 不显示 recovery 模式
# 生成 grub.cfg 后,如果想永久改 timeout,改这里的值,再 update-grubGRUB 2 的模块系统
GRUB 2 把功能拆成 .mod 模块,按需加载。常见模块:
| 模块 | 功能 |
|---|---|
linux.mod |
加载 Linux 内核 |
initrd.mod |
加载 initramfs |
chainloader.mod |
链式加载另一个 bootloader(如 Windows) |
search.mod |
按 UUID/LABEL/PARTUUID 查找设备 |
part_gpt.mod |
GPT 分区支持 |
ext2.mod |
ext2/ext3/ext4 文件系统支持 |
ntfs.mod |
NTFS/FAT 文件系统支持 |
linux16.mod |
16 位实模式启动(旧内核兼容) |
GRUB 2 安装到 UEFI 系统
# 安装 GRUB 到 ESP(UEFI 模式)
sudo grub-install /dev/sda
# 在哪里?/boot/grub/(文件)+ /EFI/ubuntu/(.efi 文件)
# 重新生成配置
sudo update-grub
# 查看 ESP 内容
ls /boot/efi/EFI/
# 输出:
# EFI/
# ubuntu/ ← GRUB 的 .efi
# Microsoft/ ← Windows Boot Manager
# Boot/ ← 默认回退 .efi(BOOTX64.EFI)Windows + GRUB 双系统:从安装到修复
安装顺序决定谁控制 MBR
先装 Windows,后装 Linux(推荐):
① Windows 装完 → MBR 有 BOOTMGR,Bcdedit 可用
② 安装 Linux → GRUB 安装到 MBR → 覆盖 BOOTMGR
③ GRUB 检测 Windows → 自动在 grub.cfg 里生成 chainloader 条目
④ 启动顺序:GRUB 菜单 → Windows → Ubuntu先装 Linux,后装 Windows(麻烦):
① Linux 装完 → GRUB 在 MBR
② Windows 安装 → 覆盖 MBR → BOOTMGR 替换 GRUB → Linux 无法启动
③ 修复:Linux Live USB → chroot → grub-installWindows Boot Manager 的 NVRAM 条目
在 UEFI 模式下,Windows 和 GRUB 都在 NVRAM 里注册了自己的启动项:
# 查看所有启动项(Linux)
sudo efibootmgr -v
# 示例输出:
# BootCurrent: 0001
# BootOrder: 0001, 0000
# Boot0000* Windows Boot Manager HD(1,GPT,...)/File(EFIMicrosoftBootbootmgfw.efi)
# Boot0001* ubuntu HD(2,GPT,...)/File(EFIubuntushimx64.efi)# 查看所有启动项(Windows,管理员权限)
bcdedit /enum firmware
# 输出显示 NVRAM 里的启动项(UEFI 模式下)从 GRUB 链式加载 Windows
GRUB 不能直接加载 Windows 内核(Windows 用的是 PE/COFF .efi 格式,但 BOOTMGR 不是标准 ELF)。解决方法是链式加载:
# grub.cfg 里的 Windows 启动条目
menuentry 'Windows 10' {
insmod ntfs # 加载 NTFS 读驱动
search --no-floppy --fs-uuid --set=root A2B3C4D5E6F7 # 找 Windows 分区
chainloader ($root)/EFI/Microsoft/Boot/bootmgfw.efi # 加载 BOOTMGR
boot # 跳转
}chainloader +1 的意思是”把这个分区的第一个扇区当作 bootloader 加载”,也就是加载这个分区根目录的 EFIMicrosoftBootbootmgfw.efi。
修复 GRUB:标准操作流程
最常见的问题:重装 Windows 后 GRUB 消失。
# 1. 用 Linux Live USB 启动(Arch/Ubuntu 均可)
# 2. 找到 Linux 根分区
sudo fdisk -l /dev/sda
# 假设 Linux root 是 /dev/sda2
# 3. 挂载
sudo mount /dev/sda2 /mnt
sudo mount /dev/sda1 /mnt/boot # 如果 /boot 是独立分区
sudo mount --bind /dev /mnt/dev
sudo mount --bind /sys /mnt/sys
sudo mount --bind /proc /mnt/proc
# 4. chroot 进入系统
sudo chroot /mnt
# 5. 重新安装 GRUB(UEFI 模式)
grub-install /dev/sda
update-grub # 自动检测 Windows
# 6. 退出重启
exit
sudo reboot修复 BOOTMGR(Windows 环境)
# 用 Windows 安装盘(或 WinRE)启动
# 选择"修复计算机" → "疑难解答" → "命令提示符"
# 重建 BCD
bootrec /fixmbr # 重建 MBR(不破坏分区)
bootrec /fixboot # 修复启动扇区(写新 BOOTMGR)
bootrec /scanos # 扫描可启动的 Windows 安装
bootrec /rebuildbcd # 重建 BCD
# 如果 bootrec 失败,手动用 bcdboot 重建
bcdboot C:Windows /s C: /f UEFI
# /s C: → 指定 ESP 盘符
# /f UEFI → 指定为 UEFI 模式Secure Boot:签名验证的游戏规则
签名链:shim → GRUB → 内核
在 Secure Boot 模式下,不是所有 .efi 都能启动——必须签名:
Secure Boot 启动链(启用签名时):
UEFI 固件(内置微软公钥)
↓
shimx64.efi(微软签名,Ubuntu/Red Hat 等发行版自带)
↓(验证)
grubx64.efi(发行版签名,shim 验证)
↓(验证)
vmlinuz(内核镜像,发行版签名)
↓
initramfs(initrd,通常内嵌在 kernel 里或单独签名)shim 的作用:shim 是微软签名的小型垫片(shim=垫片),它内置了发行版的公钥——这样,即使内核不是微软签名的,只要发行版在 shim 里注册了自己的公钥,就能启动。Ubuntu、Red Hat 都提供带 shim 的 GRUB。
禁用 Secure Boot(开发用)
如果需要加载未签名的 .efi(比如自己编译的 GRUB 或内核):
# 在 Linux 里查看 Secure Boot 状态
mokutil --sb-state
# SecureBoot enabled → 已启用
# SecureBoot disabled → 已禁用
# 在 UEFI 设置里禁用(按 Delete 或 F2 进入 BIOS 设置)
# Boot → Secure Boot → Disabled踩坑与注意事项
坑 1:Windows 安装时没有创建系统保留分区(MBR 模式)
现象:Windows 安装在已有 Linux 的磁盘上,安装程序问”把 Windows 安装在哪里”,选了整块盘,但”系统保留分区”灰色无法勾选。
原因:MBR 模式,安装程序检测到已有多个分区,不敢动。
解决:用 Disk Management 先压缩出一个 100MB 的未分配空间,再装 Windows,让安装程序自动用它创建 System Reserved。
坑 2:grub.cfg 被覆盖(手动改了 grub.cfg,update-grub 后丢失)
原因:grub.cfg 是 update-grub 自动生成的,手动改无效。
解决:在 /etc/grub.d/40_custom 里添加自定义条目,这是保留区,update-grub 不会覆盖它。
# /etc/grub.d/40_custom(这是你唯一应该手动编辑的文件)
menuentry 'My Custom Entry' {
set root='hd0,gpt2'
linux /boot/vmlinuz-linux root=/dev/sda2 quiet
initrd /boot/initrd.img-linux
}坑 3:GRUB 命令行能用,但菜单无法启动
现象:GRUB 菜单出现,但选 Ubuntu 就黑屏;按 c 进入命令行手动 linux /boot/vmlinuz... 可以启动。
原因:自动生成的内核路径或 UUID 错误,通常是 /etc/default/grub 的 GRUB_CMDLINE_LINUX_DEFAULT 有问题,或者磁盘 UUID 变了。
解决:在 GRUB 命令行里 set root=(hd0,gpt2) + linux ... + initrd ... + boot 手动启动,然后 sudo update-grub 重建配置。
坑 4:Windows BCD 损坏导致”启动设备未找到”
现象:UEFI 模式下,BIOS 可以看到磁盘,但按任意键后屏幕空白。
原因:BCD 文件损坏(可能因为磁盘清理工具误删)。
解决:Windows 安装盘启动 → 修复 → 命令提示符 → bootrec /rebuildbcd。
写在最后
Windows Boot Manager 和 GRUB,是两条完全不同的设计哲学:
| BOOTMGR + BCD | GRUB | |
|---|---|---|
| 配置格式 | BCD(二进制注册表 hive) | grub.cfg(文本文件) |
| 配置工具 | bcdedit(Windows 专有) | grub-mkconfig / update-grub |
| 多系统 | BOOTMGR 只能链式加载 Windows | GRUB 可以直接启动 Linux + 链式加载 Windows/macOS |
| 模块化 | 不可扩展(固件固定) | 模块化(.mod 按需加载) |
| 固件集成 | NVRAM 启动项(UEFI) | NVRAM + MBR 两套 |
| Secure Boot | 签名验证(bootmgfw.efi) | shimx64.efi 垫片 + GRUB + 内核 |
核心共同点:都不是操作系统的一部分,是操作系统的搬运工——它们做的工作,都是”把控制权交给 OS 内核”这一件事,区别只在”怎么找内核”、”找不到了怎么办”。
wandos 目前没有自己的 bootloader 实现,依赖 QEMU 的 -kernel 参数直接加载 ELF——如果要支持真实磁盘启动,需要先实现 GRUB 兼容的 Multiboot header(360 篇已讲过),然后参照 GRUB Stage 1/2 的设计,实现一个简化的 stage 加载器。
下篇预告(364):候选方向——文件系统(一):ext2 的 inode、块组与目录项,或者内存管理:Buddy System + SLAB 分配器的协作。你选哪个?
仓库:https://github.com/golang12306/os-kernel-from-scratch
相关阅读
- Windows BCD 存储格式:微软文档
BCD WMI Provider - GRUB 2 源码:
https://www.gnu.org/software/grub/ - UEFI Spec:Secure Boot 部分,
https://uefi.org/specifications - Linux Kernel Source:
arch/x86/boot/(Linux 的 boot protocol 实现) - https://github.com/zhangfuwen/wandos — Linux 内核教程
动手环节
想深入理解本文内容?动手实践是最好的方式:
今天的目标:在你的机器上同时操作 Windows BCD 和 GRUB 配置,体验两种系统的差异。
-
在 Linux 上查看 GRUB 配置生成过程:
# 查看 grub.cfg 是怎么生成的 sudo grub-mkconfig --print # 不写入文件,只看生成结果 # 注意:不要修改 /boot/grub/grub.cfg,直接改会被覆盖 # 正确做法是:改 /etc/default/grub 或 /etc/grub.d/40_custom -
查看 NVRAM 里的启动项:
sudo efibootmgr -v # 看看有没有 Windows Boot Manager 条目 # 如果没有,手动添加: sudo efibootmgr -c -d /dev/sda -p 1 -l "EFIMicrosoftBootbootmgfw.efi" -L "Windows" -
在虚拟机里练习修复(无风险):
# 用 QEMU 创建双系统虚拟机 # 先装 Windows,再装 Linux,观察 GRUB 菜单如何出现 # 然后重装 Windows,观察 GRUB 消失后的修复过程 -
分析 BOOTMGR 的结构(如果有 System Reserved 分区):
# 挂载 Windows System Reserved 分区(需要 root) sudo mkdir /mnt/win-sysres sudo mount /dev/sda1 /mnt/win-sysres -o ro ls -la /mnt/win-sysres/Boot/ # 看看 BCD 和 BOOTMGR 的大小和修改时间
提示:BCD 是一个注册表 hive,需要 bcdedit(Windows)或 bcdtools(Python 库)解析。在 Linux 上直接看 BCD 很难读懂内容,主要靠 efibootmgr 查看 NVRAM 条目。
评论