ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

UEFI Driver 从刷显卡到开发:一文讲透固件驱动的加载与排障

UEFI Driver 从刷显卡到开发:一文讲透固件驱动的加载与排障 你看热搜里那个hd6450 刷uefi我第一反应是被勾起一段黑历史。当年为了让老平台能开 Secure Boot把一张 Radeon HD 6450 的 VBIOS 刷成了带 GOP 的 UEFI 版本刷完开机主板的 UEFI 界面终于不再是黑屏。那一瞬间我才真正意识到所谓刷 UEFI折腾的对象其实不是系统、不是引导器而是藏在固件里的那一层 UEFI Driver。很多人天天跟UEFI 无法安装UEFI 引导修复虚拟机选不了 UEFI打交道却始终没搞明白 UEFI Driver 到底是什么、它被放在哪里、什么时候被加载、坏了会出什么症状。这篇就把 UEFI Driver 从底层逻辑到日常踩坑一次讲透适合两类人看一类是纯用户只想把引导问题修复、把系统装明白另一类是想自己动手写固件驱动、搞 EDK2 开发的玩家。看完你会对启动过程中的每个黑盒子都心里有数。1. 一个老显卡玩家最先遇见的UEFI DriverHD6450 刷 GOP1.1 为什么老显卡在 UEFI 模式下黑屏先把最直观的场景说清楚。你有一张 2012 年左右的显卡比如 Radeon HD 6450插到只支持 UEFI 启动的主板上开机发现主板 logo 不显示、进不了 BIOS 设置界面但系统如果自动引导进去了又能正常显示桌面。这个诡异现象背后就是 UEFI Driver 缺失。传统显卡固件里只有一段 Legacy OptionROM也就是传统 BIOS 时代用来初始化和输出画面的 VBIOS。UEFI 固件启动时如果开启了纯 UEFI 模式、关闭了 CSMCompatibility Support Module它不会去执行那段 Legacy OptionROM 的 INT 10h 中断服务而是去找一种叫 GOPGraphics Output Protocol的东西。GOP 本质上就是一个运行在 UEFI 环境里的显卡驱动负责初始化显存、设置显示模式、输出画面。显卡固件里没有 GOPUEFI 固件就看不见这块显卡的显示输出结果就是黑屏。网上一堆显卡刷 UEFI的教程表面上是改固件实质上是往显卡 VBIOS 里嵌入一个 UEFI Driver。刷完之后VBIOS 里同时有了 Legacy OptionROM 和 UEFI GOP 驱动两份代码固件按启动方式各取所需。这也从根上解释了为什么刷了 UEFI GOP 的老显卡在传统 BIOS 和 UEFI 模式下都能正常工作。1.2 刷写工具、步骤与翻车现场刷显卡 VBIOS 这件事我自己的经历可以分成两台机器一台是 N 卡用 nvflash另一台就是那张 HD 6450用的是 atiflash。典型的刷写流程是准备一个 DOS 启动 U 盘或者直接用 UEFI Shell 环境下的工具版。备份当前 VBIOSatiflash -s 0 backup.rom这里的 0 是显卡序号。找一个匹配型号、带 GOP 的 BIOS 文件。如果是改版卡最好自己用工具把原 BIOS 和 GOP 模块合在一起不要直接刷别人整卡提取的 ROM否则显存频率、风扇策略不匹配很容易翻车。执行刷新atiflash -p -f 0 new_gop.rom。-f 是强制刷写跳过 ID 校验。重启进 UEFI 模式验证。这里有一个经常被忽略的坑刷完 GOP 之后如果主板还开着 CSM或者显卡的输出接口接错了还是会黑屏。UEFI GOP 驱动只是解决固件能不能初始化显卡的问题不解决你的显示器接在哪个口、CSM 到底关没关的问题。我当年刷完开机黑屏一度以为刷成砖了结果是 CSM 没关固件还是走了 Legacy 初始化路径。重要刷 VBIOS 前必须确认主板有核显或第二张 PCIE 亮机卡同时备份原始 ROM。VBIOS 刷写失败后很多卡无法用软件恢复只能上编程器硬刷风险不小。2. 底层视角UEFI Driver 在启动流程里的确切位置与生命周期2.1 从 SEC 到 BDS驱动是分批次登场的要真正理解 UEFI Driver得先看 UEFI 启动的分阶段流程。现代 UEFI 固件的启动大致走六个阶段SEC、PEI、DXE、BDS、TSL、RT。前面两个阶段负责 CPU 初始化、内存探测、芯片组基础设置这个阶段基本没有驱动的概念更多是 PEIM 模块在干活。到了 DXE 阶段DXE DispatcherDXE 分发器开始干活了。它按照固件里注册的依赖关系把一堆 DXE Driver 加载到内存里执行。这些驱动包括内存管理器、PCI Host Bridge 驱动、SMBIOS 表、ACPI 表准备等等。也就是说主板固件自己内置了一大批 UEFI Driver它们不是操作系统里的 .sys 文件而是编译成 PE32 格式的固件模块直接烧写在 SPI Flash 里。接下来的 BDSBoot Device Selection阶段固件才开始扫描外部设备上的 OptionROM。这里补充一个容易混淆的点显卡的 GOP、NVMe 硬盘的 DXE 驱动、网卡的 PXE 驱动这些存放在设备自身固件里的 UEFI Driver本质上是在 BDS 阶段被加载的。主板上的 DXE Driver 是出厂就有的设备带的是临时发现的来源完全不同。2.2 UEFI Driver 的四种类型别再混为一谈UEFI 规范里Driver 其实分好几种很多教程把它们统称为UEFI 驱动但生命周期和调用方式差得很远。类型加载阶段生命周期典型例子Boot Service DriverDXE / BDSExitBootServices 之前有效大部分 PCI 驱动、SMBIOS 驱动Runtime DriverDXE一直保留到操作系统关机RTC、NVRAM 变量服务、UpdateCapsuleUEFI Driver ModelBDS支持 Bind/Start/Stop可动态绑定设备现代 GOP、网卡、存储控制器驱动UEFI Application任意阶段由用户或引导器加载退出后即终止Shell.efi、bootmgfw.efi、刷机工具Boot Service Driver 的生命周期在 ExitBootServices 之后终结。Windows 内核接管后这批驱动占用的内存会被释放。Runtime Driver 则不一样它们常驻内存操作系统需要读时间、设置启动变量、重启机器时都要通过 UEFI Runtime Services 调回这部分代码。热搜里那条using simple offset uefi rts说的就是和 UEFI Runtime Services 打交道时常见的地址换算问题——操作系统要把虚拟地址映射给固件固件里的时间服务、变量服务才能被安全调用。如果你在 Linux 下看过 dmesg 里的 EFI 相关日志会发现 Runtime Services 的虚拟地址映射出了幺蛾子时间和 NVRAM 就会一起出问题。2.3 驱动存在哪UEFI 怎么决定加载哪些UEFI Driver 存放的位置主要有三处主板 SPI Flash 固件里、设备自带的 OptionROM 里、以及 ESP 系统分区的 EFI 目录里。最后一种很容易被忽略你打开 ESP 分区除了 EFI\Microsoft、EFI\grub 这些引导器目录还能看到 EFI\Drivers 目录有些 OEM 会把用于兼容特定硬件的 DXE 驱动放在这里。UEFI 固件加载哪些外部驱动靠的是 NVRAM 里的 Driver#### 和 DriverOrder 变量。理解这个机制可以帮助解决一些疑难杂症比如某些主板的启动项里残留了陈旧驱动引导多次失败。在 UEFI Shell 里执行 drivers 命令能列出当前加载的所有驱动和句柄再配合 dh -p 查看协议状态基本能判断是哪个驱动出了问题。3. 普通用户天天撞上的隐形 UEFI Driver磁盘布局与 CSM3.1 磁盘布局不受 UEFI 支持到底是谁的锅热搜词里出现频率极高的一句话无法安装 Windows因为这台电脑的磁盘布局不受 UEFI 支持。这句话系统没讲清楚的是问题不在磁盘而在固件找不到可用于加载引导程序的 UEFI Driver 和分区结构。UEFI 固件启动 Windows 时需要从一个 ESPEFI System Partition里读取引导应用。ESP 是 FAT 格式的分区里面存放的是 bootmgfw.efi 这类 UEFI Application。GPT 磁盘天然就支持创建 ESP而 MBR 磁盘在 UEFI 规范里没有标准位置放 ESP固件也就没法在这个磁盘上找到引导程序。所以 UEFI 模式 MBR 磁盘的组合在现代固件上基本没戏。需要区分的是两种不同的引导模型UEFI GPT固件直接加载 FAT 分区中的 .efi 文件安全、支持 Secure Boot、支持大容量磁盘。Legacy BIOS MBR固件把控制权交给磁盘 0 扇区的主引导记录再靠引导代码接力加载系统。所以当你看到磁盘布局不受 UEFI 支持时要么把手头的 MBR 磁盘无损转换成 GPTWindows 自带 mbr2gpt 工具要么进 BIOS 开启 CSM 走传统引导二选一。网上很多问答让用户关掉 UEFI 只开 Legacy这确实能装上系统但代价是放弃 Secure Boot、放弃 GPT新电脑上非常不建议。3.2 无损转换 MBR 到 GPT 的正确姿势如果你确定要留在 UEFI 模式最稳的做法是用 Windows 自带的 mbr2gpt 做无损转换。在 Windows PE 命令行里执行mbr2gpt /validate /disk:0 mbr2gpt /convert /disk:0/validate 先验证磁盘是否符合转换条件分区数量、是否有足够空间创建 ESP、系统分区是否正常。转换成功后再进 BIOS 把启动模式设为纯 UEFI。这里要注意mbr2gpt 对 BIOS 固件和磁盘分区表有一些隐式要求验证不通过时不能强转否则会出现您所选的分区表可能不正确的安装报错。至于您所选的分区表可能不正确它通常出现在 Windows 安装程序里安装程序检测到当前固件是 UEFI而你选择安装的目标磁盘是 MBR。安装程序不给你下一步的机会就是不想让你装出一个UEFI 固件 MBR 磁盘 无引导的残缺系统。3.3 CSM、Secure Boot 和第一代 UEFI CPU 的尴尬CSM 是 UEFI 固件里用来兼容传统 BIOS 启动的模块。开启 CSM 后固件会在需要的时候加载传统 OptionROM从而支持 MBR 磁盘启动。很多玩家的一贯做法是装不上就开 CSM但从 UEFI Driver 的视角看这是让固件同时运行两套驱动体系兼容性是好了安全和速度都打了折扣。Win11 强制要求 Secure Boot 和 TPM 2.0这又牵扯到第一代 UEFI CPU的尴尬。早期的 UEFI 主板大约是 2011-2015 年那批虽然号称支持 UEFI但 Secure Boot 实现不完整TPM 版本也可能停留在 1.2甚至有些板子根本没有 TPM 插座。这类老平台想升 Win11硬件检查那关就过不去。开启 TPM 的位置通常在 BIOS 的 Security 菜单下项名可能是 Intel Platform Trust TechnologyIntel PTT、AMD fTPM或者独立的 Trusted Computing 设置开启后还要确认设备管理器里能看到受信任的平台模块 2.0。提醒Win11 的硬件要求检查里有一个常见误判是当前计算机启动方式为 uefi却仍然不满足要求。这种多半是磁盘还是 MBR或者 Secure Boot 没有真正打开。先去 BIOS 确认关闭 CSM、启用 Secure Boot再检查磁盘是否为 GPT顺序不要弄反。4. Win11 引导修复里藏着的 UEFI Driver 逻辑4.1 引导链路上每一个环节都是 .efi 应用很多教程教人修复 Win11 UEFI 引导张嘴就是执行 bootrec /fixmbr但你要真在 UEFI 环境下这么干会发现大概率没用。原因在于UEFI 引导 Windows 的链路跟传统 BIOS 完全不同它没有主引导记录的概念固件是通过 FAT 分区的文件路径直接加载引导应用。一条完整的链路是这样的UEFI 固件 → ESP 分区 EFI\Microsoft\Boot\bootmgfw.efi → Boot Managerbootmgr → EFI\Microsoft\Boot\memtest.efi / winload.efi → Windows 内核bootmgfw.efi 本身就是一个 UEFI Application它里面实现了 Windows Boot Manager 的界面和启动项逻辑。UEFI Driver 在这里扮演的角色是提供磁盘驱动、文件系统支持FAT 驱动以及键鼠、显示等基础设备的驱动。任何一环出了毛病症状都是找不到操作系统或者蓝屏 0xc000000e。4.2 一套可靠的手动修复流程进 WinREWindows 恢复环境后我最常用的修复流程是这样diskpart list disk sel disk 0 list vol先看清楚 ESP 分区是哪个卷、盘符是什么。ESP 通常只有 100MB 到 500MB文件系统 FAT32。然后给它分配一个盘符sel vol 2 assign letterS exit接下来手动重建引导文件bcdboot C:\Windows /s S: /f UEFI这条命令的核心作用是把 bootmgfw.efi、BCD 存储等必要文件复制到 ESP并建立启动项。比 bootrec /rebuildbcd 更直接尤其是系统分区还在、只是 ESP 文件丢失或损坏的场景。如果 BCD 本身坏了可以再配合bootrec /scanos bootrec /rebuildbcd但请注意bootrec /fixmbr 和 bootrec /fixboot 在 UEFI 模式下意义不大。我曾经见过不少新手用网上淘来的传统修复命令在 UEFI 系统上把 ESP 分区标志改乱了最后只能重装。UEFI 引导修复的正确思路是先确认 ESP 存在且文件完整再重建引导文件最后用 bcdedit 检查启动项的 device 和 osdevice 路径。4.3 启动方式确认与一些隐蔽故障当前计算机启动方式为 uefi这个判断可以用几个命令交叉确认msinfo32看BIOS 模式如果显示UEFI就是 UEFI 启动。再看bcdedit /enum {current}确认 path 指向的是 \Windows\system32\winload.efiUEFI还是 winload.exeLegacy。还有一招在 diskpart 里 list diskGPT 磁盘会带一个星号。实际修复中我踩过一个隐蔽的坑ESP 分区存在、文件也完整但就是引导失败。查到最后是固件 NVRAM 里的 BootOrder 被清掉了UEFI 固件不知道该从哪个文件启动。这时候在 UEFI Shell 里手动运行fs0:\EFI\Microsoft\Boot\bootmgfw.efi如果能进系统说明只是启动项丢失可以用 bcdboot 或者主板的启动项管理把路径重新加回来。这类问题不算驱动损坏但和驱动加载属于同一层级的固件状态管理属于容易误判的一类故障。5. 虚拟机里的 UEFIVMware 装 Rocky 为何选不了 UEFI5.1 虚拟机的固件是怎么一回事热搜里还有一条VMware 17.6 安装 Rocky 9.8 系统不能选择 UEFI 模式。虚拟机的 VMM 层提供给 Guest 的 UEFI 固件和物理主板上的固件没有本质区别也是一个完整的 OVMF 风格固件包含 DXE 驱动、BDS 阶段、ACPI 表、NVRAM 变量区。但 VMware Workstation 在创建虚拟机时的固件选择和物理机不太一样它通过 vmx 配置文件里的 firmware 参数决定虚拟机用传统 BIOS 还是 UEFI。你在创建向导里如果选了传统 BIOS作为固件装完系统之后想要切到 UEFI事情就麻烦了。不是改一下 vmx 参数就能解决的因为客户机系统里安装引导程序的方式已经按 BIOS 模式来了。强行改成 firmware efi虚拟固件找不到 Legacy 引导记录直接开不了机。这个热搜场景的正确做法是在创建虚拟机的第一步、分配系统镜像之前就把固件类型选成 UEFI。VMware Workstation 17 的创建向导里在选择固件类型页面可以选 UEFI 和启用安全引导。要注意的是这个选项在某些情况下是灰色的常见原因是虚拟机的兼容性版本太老或者创建向导已经选择了包含 Legacy 依赖的客户机操作系统类型。5.2 Rocky 9 对 UEFI 的选择几乎不是选择Rocky Linux 9 延续了 RHEL 9 的设计默认安装镜像完全支持 UEFI 引导而且推荐在 UEFI GPT 环境下安装。问题往往出在先选了 Legacy BIOS 又想让系统以 UEFI 启动这种顺序颠倒上。解决方式有两种新建虚拟机时直接选 UEFI安装时确认 /boot/efi 分区自动创建。虚拟机已经建好但固件是 BIOS就去克隆或迁移配置必要时重建引导配置。如果你在 VMware 里发现安装程序无法选择 UEFI 模式先检查兼容性把虚拟硬件版本提高到 Workstation 17.x 支持的最高版本再检查 vmx 文件里是否已经有 firmware efi。修改 vmx 之前务必备份因为对这个文件动刀等同于你在物理机上重刷固件风险是一样的。5.3 虚拟设备驱动的特殊性虚拟机的 UEFI 固件里也有一堆虚拟 OptionROM。VMware 虚拟显卡SVGA、虚拟磁盘控制器LSI Logic / PVSCSI、虚拟网卡e1000 / vmxnet3都有对应的 UEFI Driver。装系统时能不能从 ISO 引导、装完驱动能不能加载、PXE 能不能启动全看这些虚拟驱动是否正常绑定。常见的问题是装完 Rocky 后在 UEFI 模式下系统找不到根文件系统报错 dracut 超时。这通常不是引导问题而是虚拟磁盘控制器驱动没进 initramfs或者 vmx 里磁盘控制器类型和驱动不匹配。解决办法是在安装时确保磁盘走 virtio 或 PVSCSI并让 initramfs 把驱动包含进去。这一层和物理机里 NVMe 硬盘需要 DXE 驱动才能被固件识别是同一个道理只是虚拟化场景容易被人忽略。6. 想自己写一个 UEFI Driver开发环境与第一步6.1 开发环境搭建EDK2 才是主战场如果你读到这里开始手痒想真的写一个 UEFI Driver那需要进入 EDK2 的世界。EDK2 是 Intel 维护的 UEFI 固件开发框架几乎所有的 UEFI 固件、驱动、工具都基于它。开发环境我用的是 Windows VS2019 的方式简单列一下准备项Python 3.xVisual Studio 2019C 工具链NASM 汇编器一份 EDK2 源码用 git 克隆后切稳定分支可选的 OVMF用于在 QEMU 里测试驱动避免物理机反复刷固件配置环境时最容易翻车的点是 NASM 路径和 VS 环境变量。EDK2 的 build 脚本会去找 nasm.exe如果路径没加对编译会在汇编阶段直接报错。首次执行 edksetup.bat 后还要编辑 Conf\target.txt 里 TARGET_ARCH、TOOL_CHAIN_TAG 这些参数。6.2 一个最小的 DXE Driver 骨架UEFI Driver 和普通 C 程序最大的不同是没有 main 函数、没有 libc、字符串是 UCS-2、内存管理走 AllocatePool。下面是一个最简单的 DXE 驱动入口它的作用只是在加载时往串口打一行日志#include Uefi.h #include Library/UefiDriverEntryPoint.h #include Library/DebugLib.h EFI_STATUS EFIAPI UefiEntry ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { DEBUG ((EFI_D_INFO, MyFirstDriver: Hello from DXE!\n)); return EFI_SUCCESS; }注意这里没有 Unload 函数这个驱动一旦加载就会留在内存里无法卸载。凡是实现了 EFI_DRIVER_BINDING_PROTOCOL 的 UEFI Driver Model 驱动才会有 Supported、Start、Stop 三个回调系统才能动态判断这块设备该不该归这个驱动管。写 UEFI Driver 和写 Linux 内核模块完全是两回事。Linux 模块可以直接调用内核导出的符号而 UEFI 驱动只能通过 EFI_BOOT_SERVICES 和协议接口来干活自己需要什么功能就 OpenProtocol 拿什么。第一次写的时候最容易懵的是搞不清该用哪个协议要访问 PCI 配置空间先拿到 EFI_PCI_IO_PROTOCOL要控制显示输出找 EFI_GRAPHICS_OUTPUT_PROTOCOL要读写磁盘得从 EFI_BLOCK_IO_PROTOCOL 开始。6.3 编译、加载与调试的日常编译命令通常是build -a X64 -t VS2019 -p MyDriverPkg/MyDriverPkg.dsc产出文件一般是 .efi把它复制到 U 盘或者 OVMF 的 FAT 镜像里。调试时可以在 QEMU 里加载 OVMF配合串口输出查看 DEBUG 日志。如果你物理机有 EFI Shell也可以把 .efi 放 ESP 分区里手动加载load fs0:\MyDriver.efi driversdrivers 命令会列出这个驱动的句柄和状态。如果驱动实现了 Driver Binding Protocol还能看到它绑定了哪些设备。我在开发调试中最常用的就是这组命令比在黑盒环境里瞎猜高效得多。调试建议UEFI 环境没有断点调试器可选最接地气的调试方式就是串口日志。建议驱动里所有关键路径都打 DEBUG等级用 EFI_D_INFO 和 EFI_D_ERROR 区分。OEM 的很多固件默认不输出串口日志QEMU OVMF 是最好用的调试环境没有之一。写 UEFI Driver 带来的最大收获是能把很多玄学启动问题归结为某个驱动在某阶段加载失败。比如你写一个简单的 GOP 驱动去替代主板固件自带的驱动马上就能理解为什么某些显示器在开机阶段黑屏、进系统后却正常——因为操作系统接管显示输出之后UEFI 驱动已经完成了它的使命退了。我个人在实际操作中的体会是UEFI Driver 真的不神秘它就是一个跑在特殊环境里的小程序只是这个环境没有进程、没有虚拟内存、没有动态链接所有资源都要靠协议接口来要。好比你在一个只提供水电管线租赁的临时建筑里干活所有家具都得自己搬进去搬不进去就用不了。理解了这一点再看那些刷 GP UEFI引导修复虚拟机固件选择的问题就都是在同一个框架下反复出现的变体而已。最后再分享一个小技巧拿到任何一台新电脑想快速了解它的固件和驱动状态先按电源键狂按 F2/Del 进 BIOS看 CSM 和 Secure Boot 的设置再用 U 盘启动一个 EFI Shell跑一下 drivers 和 devtree这台机器的 UEFI Driver 家底就全在你面前了。这比在操作系统里翻半天日志都快。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进