我正在尝试了解 Windows 启动过程。我了解到 EFI 启动管理器正在加载 Windows 启动管理器。但随后它必须访问 BCD 才能继续加载操作系统或链式加载下一个启动管理器。它究竟是如何找到 BCD 的?
例如,在我的系统中,GPT 磁盘上有两个 BCD:一个在 ESP 上,另一个在系统保留分区上,后者是从旧 MBR 磁盘克隆的。启动管理器是否只因为驱动器是 GPT 而查找 ESP?它是否查找“当前”文件夹(鉴于尚未加载操作系统,现阶段是否存在这样的文件夹)?还是涉及更复杂的算法?
一个奇怪的事实:如果我删除系统保留分区,启动管理器将无法启动,并抱怨 BCD 丢失。但是,如果我对两个 BCD 进行一些更改(例如设置不同的超时),则会按预期使用 ESP BCD 设置。
答案1
引导管理器在 ESP 上查找 BCD,因为这是目前唯一已知的分区,并且固件可能只能读取 FAT 分区。ESP/EFI/Microsoft/Boot/BCD
上 BCD ( ) 的路径可能是硬编码的。UEFI 从一开始就被设计为支持来自不同供应商的软件共存,并且/EFI/Microsoft
是 Microsoft 在 ESP 上的“游乐场”。
答案2
我可以回答它如何在 Windows 7 的 MBR 磁盘上找到它。
这BIOS IPL 表包含要从中启动的磁盘号,并将其传递给条目中的向量,该向量将是所有 BAID 共享的代码。此代码使用检查有效 MBR 的磁盘加载第一个扇区INT 13h
,0x7c00
然后传递控制。MBR 包含一个存根,它将自身移出0x7c00
并加载活动分区(对应于A:
我的操作系统上的卷)的第一个扇区(即 VBR),然后0x7c00
跳转到该第一个扇区的第一个字节,即 VBR。我猜它将磁盘号传递给 VBR 以用于 BIOS 实模式服务。
然后,活动分区的 VBR 将 IPL(与前面提到的 IPL 缩写无关)从分区的 1-15 扇区加载到内存中,并使用 VBR BPB 中的 HiddenSectors 定位内存(HiddenSectors 告诉它相对于磁盘起始位置的扇区号(分区的扇区 0)。VBR 知道 BPB 相对于自身的位置,因此它可以将其句柄传递给 IPL 代码(它已经加载到内存中,因为它是扇区 0 的一部分,这是 MBR 加载的扇区)。我想它还会传递磁盘号。IPL 代码现在知道每个簇有多少个扇区以及 MFT 的簇,因为信息在 BPB 中,因此它可以使用 IPL 中的原始 NTFS 驱动程序代码在 BPB 所属的分区上查找 BCD。因此,它只是在提供给它的 BPB 中的 MFT 的根目录中查找,这当然是当前分区的 BPB。这就是为什么系统保留分区需要处于活动状态,否则 Windows MBR 将不知道哪个分区是系统保留分区,因此它不知道要加载哪个 VBR。MBR+系统 rsvd 分区 VBR+IPL+Bootmgr 是主引导加载程序,而 winload 是辅助引导加载程序。如果您安装 GRUB,它将用自己的存根覆盖 MBR 以加载自己的主引导加载程序,而不关心哪个分区处于活动状态。要恢复加载活动分区的 VBR 的 MBR,请使用bootrec /fixmbr
。bootsect /nt60 SYS
或bootrec /fixboot
修复系统分区上的 VBR 和 IPL。bootsect /nt60 SYS /mbr
还修复了 mbr。
IPL 定位 bootmgr(可能首先通过 BCD,否则我不知道 BCD 中 bootmgr 条目的要点是什么),将 bootmgr 开头的 startup.com 部分加载到实模式地址空间中,在我的情况下,它将其加载到0x20000
aka。2000:0000
并将控制权传递给它。Startup.com 是一个以 E9 跳转开头的 DOS COM 文件,而不是“DOS 存根”(在 bootmgr.exe 的开头有一个)。
实模式程序 (Startup.com) 从 16 位实模式切换到 16 位,然后切换到禁用分页的 32 位保护模式。然后,Startup.com 大概会读取 BCD(通过其自己的 NTFS 逻辑,或者使用 IPL,或者在内存中将 BCD 传递给它)并从0x7BF3
bootmgr 中的偏移量加载 bootmgr.exe,到0x400000
我的系统上,然后使用 对其进行解压缩lznt1
。然后,它将控制权传递给bootmgr!BmMain
,而不是“DOS 存根”,后者接收 ,PBOOT_APPLICATION_PARAMETER_BLOCK
其中包含 的偏移量BL_APPLICATION_ENTRY
,其中包含 ,BL_BCD_OPTION
它是应用程序条目(bootmgr、winload 等)的 BCD 选项链中的第一个。对于 MBR,BCD 应用程序条目包含“设备”选项中的磁盘和分区偏移量,而不是驱动器号(因为 bootmgr 由多个 Windows 安装及其各自的 winload.exe 使用,因此驱动器号没有任何意义)。似乎 winload 和操作系统也可以位于不同的分区上。
Bootmgr 将启用分页并切换到 64 位长模式,然后加载并将控制权传递给所选条目,使用 BCD 条目中的 winload.exe 卷和路径来解析 MFT。此时,它知道卷符号链接之类的分区C:
对应哪个分区。我相信当您这样做时bcdedit
,您将从当前正在使用的任何操作系统的角度看到驱动器号——BCD 只将分区的 MBR 签名 + 偏移量存储在条目中,并且为了方便起见,使用当前操作系统符号链接(从 mountmgr 数据库构建)上下文中的驱动器号显示或编辑它。
它将 winload.exe 加载到0x2ef000
我的系统作为 OS 入口,并将控制权传递给winload!OslMain
。Bootmgr.exe 是它自己的内核,具有自己的调试引擎和驱动程序。Winload 是它自己的内核,具有自己的调试引擎和驱动程序。这两者都只能处理 COM 端口 1 上的调试。Winload 负责加载主内核 ntosrkrnl.exe,它有自己的调试引擎和驱动程序。注意,x64 始终支持 MP 并且没有 PAE(因此不是 ntkrnlpamp.exe),所以它们被称为 hal.dll 和 ntoskrnl.exe,而不是 halmapic.dll 和 ntkrnlmp.exe,尽管它本质上是 ntkrnlmp.exe。您可以使用.pdb
在 之前为二进制文件下载的名称!
,因此如果它是 ntkrnlmp.pdb(适用于 Windows 7 ntoskrnl.exe),您可以在 Windows 内核调试器中使用ntkrnlmp!
它nt!
。