UEFI_USB_BIOS_Dump_实现详解

UEFI_USB_BIOS_Dump_实现详解 UEFI U 盘自动打印 BIOS 信息实现详解最终目标目标是让电脑重启后在 BIOS 或 Boot Menu 里选择 U 盘启动然后自动打印BIOS/UEFI 中所有 Protocol所有 UEFI Variable所有 Boot Option并把结果保存到 U 盘根目录bios_dump.txt也就是说不需要手动进入 UEFI Shell 再敲命令而是做到选择 U 盘启动 - 自动运行程序 - 打印并保存结果UEFI 启动原理UEFI 固件从 U 盘启动时会默认寻找这个文件\EFI\BOOT\BOOTX64.EFI对于普通 64 位 x86 PC默认启动文件名就是BOOTX64.EFI所以实现自动启动的关键是把编译出来的 UEFI 程序复制成 D:\EFI\BOOT\BOOTX64.EFI这样 BIOS 选择 U 盘启动时就会直接运行我们的程序。最初方案通过 UEFI Shell 自动运行最开始的结构是BOOTX64.EFI UEFI Shell startup.nsh 自动脚本 BiosDumpApp.efi 打印程序启动流程是BIOS 启动 U 盘 - 运行 UEFI Shell - Shell 自动执行 startup.nsh - startup.nsh 再运行 BiosDumpApp.efi这个方案可行但多依赖了一层 Shell。有些 Shell 不一定自动执行startup.nsh所以后来改成了更直接、更稳的方案。最终方案直接启动打印程序最终结构改成BOOTX64.EFI BiosDumpApp 本身启动流程变成BIOS 启动 U 盘 - 直接运行 BiosDumpApp - 打印 Protocol、Variable、Boot Option - 保存 bios_dump.txt这样就不依赖 Shell 脚本自动执行了。U 盘中的文件最终 U 盘里主要有D:\EFI\BOOT\BOOTX64.EFI D:\EFI\BOOT\BiosDumpApp.efi D:\EFI\BOOT\Shell.efi D:\BiosDumpApp.efi它们的作用如下。D:\EFI\BOOT\BOOTX64.EFI这是最重要的文件。UEFI 固件启动 U 盘时默认寻找它。现在它就是我们的打印程序。D:\EFI\BOOT\BiosDumpApp.efi这是同一个程序的备用副本方便以后手动运行或对比。D:\BiosDumpApp.efi这是放在 U 盘根目录的程序副本。如果以后进入 UEFI Shell可以直接运行它。D:\EFI\BOOT\Shell.efi这是保留的 UEFI Shell。默认不会启动它但以后如果需要调试可以手动使用。为什么必须使用 FAT32很多 BIOS/UEFI 固件从 U 盘启动时对 FAT32 支持最好、最稳定。之前 U 盘是exFAT有些机器能识别有些机器不能识别。为了最大兼容性最后将 U 盘格式化为FAT32当前确认结果是FileSystem FAT32 Label BIOSDUMP这符合标准 UEFI 可移动启动盘要求。为什么要关闭 Secure BootSecure Boot 的作用是只允许运行受信任签名的 EFI 程序。我们自己编译出来的BOOTX64.EFI没有微软或厂商信任签名。如果 Secure Boot 开启BIOS 可能在程序运行前直接拦截。检测到当前机器状态为UEFISecureBootEnabled 1这表示 Secure Boot 开启。所以启动前需要进入 BIOS 关闭 Secure Boot否则可能看到Security Violation Invalid Signature Detected或者 U 盘程序无法启动。EDKII 程序整体结构程序是一个 UEFI Application不是 Windows 程序也不是 DOS 程序。入口函数是EFI_STATUS EFIAPIUefiMain(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE*SystemTable)程序主要执行三件事1. DumpProtocols() 2. DumpVariables() 3. DumpBootOptions()打印所有 ProtocolUEFI 中很多功能都通过 Protocol 暴露例如磁盘访问文件系统键盘输入屏幕输出PCI 设备网络USB程序调用gBS-LocateHandleBuffer(AllHandles,...)含义是找到当前系统里所有 handle然后对每个 handle 调用gBS-ProtocolsPerHandle(...)含义是查看这个 handle 上安装了哪些 protocol最后打印每个 protocol 的 GUID。输出类似Handle[0]0x... [0] xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx [1] xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx程序打印 GUID而不是协议名字。原因是协议名字不是 UEFI 固件标准必须提供的很多 BIOS 中没有 GUID 到名字的数据库。打印所有 UEFI VariableUEFI Variable 是 BIOS/固件保存配置的地方。常见变量包括BootOrder Boot0000 Boot0001 SecureBoot SetupMode PK KEK db dbx程序调用gRT-GetNextVariableName(...)逐个枚举固件中的变量。然后对每个变量调用gRT-GetVariable(...)读取变量名Vendor GUID属性数据大小数据内容前 64 字节之所以只打印前 64 字节是因为有些变量很大而且很多内容是二进制。完整打印会刷屏预览前 64 字节更安全、更可读。输出类似[1] BootOrder xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Attributes : 0x00000007 [NV BS RT] Size : 8 bytes Data : 00 00 01 00 02 00 03 00属性含义NV Non-Volatile断电保存 BS Boot Service 阶段可访问 RT Runtime 阶段可访问打印 Boot OptionBIOS 启动菜单里的每个启动项通常就是一个 UEFI Variable。名字格式为Boot0000 Boot0001 Boot0002启动顺序保存在BootOrder例如BootOrder 0001, 0000, 0002表示先尝试 Boot0001 再尝试 Boot0000 再尝试 Boot0002每个Boot####变量内部是一个EFI_LOAD_OPTION结构里面包含启动项属性显示名称设备路径可选参数程序解析Boot####后可以打印启动项名称是否 active对应设备路径是否在 BootOrder 中输出类似Boot0000 (BootOrder[0]) Description : Windows Boot Manager Attributes : 0x00000001 [ACTIVE] FilePathLen : ... DevicePath : ... OptionalData: ...为什么程序自己写 bios_dump.txt如果程序只把内容打印到屏幕输出可能太长很难拍照、复制或分析。所以程序加入了日志功能启动时打开当前启动盘根目录的 bios_dump.txt然后所有输出同时写到屏幕 bios_dump.txt也就是“双输出”显示器上能看到 U 盘里也保存一份打印完成后回到 Windows 打开 U 盘就能看到bios_dump.txt为什么程序结束要等待按键如果 EFI 程序运行完直接退出有些 BIOS 会立即返回 Boot Menu 或黑屏可能看不到结果。所以程序最后会显示Done. Press any key to exit.并等待用户按任意键。这样可以确认程序已经跑完也能看到屏幕输出。完整实现流程完整流程如下1. 写 EDKII UEFI Application 源码 2. 使用 EDKII build 编译成 BiosDumpApp.efi 3. 修改程序让它自己保存 bios_dump.txt 4. 再次编译 5. 把 U 盘格式化成 FAT32 6. 创建标准 UEFI 启动目录 D:\EFI\BOOT\ 7. 把程序复制成 D:\EFI\BOOT\BOOTX64.EFI 8. 保留备用副本 D:\EFI\BOOT\BiosDumpApp.efi D:\BiosDumpApp.efi D:\EFI\BOOT\Shell.efi 9. 重启后 BIOS 选择 U 盘 UEFI 启动 10. 程序自动运行并生成 bios_dump.txt实际使用步骤现在使用时只需要1. 重启电脑 2. 进入 BIOS 3. 关闭 Secure Boot 4. 进入 Boot Menu 5. 选择 U 盘的 UEFI 启动项 6. 等程序打印完成 7. 回 Windows 查看 U 盘中的 bios_dump.txt如果一切正常U 盘根目录会出现bios_dump.txt这就是最终打印结果。