UEFI Driver Binding Protocol 实战:3步实现自定义驱动与协议安装 UEFI Driver Binding Protocol 实战3步实现自定义驱动与协议安装在UEFI固件开发领域驱动模型的实现一直是工程师面临的核心挑战。本文将深入探讨如何通过EFI_DRIVER_BINDING_PROTOCOL实现一个完整的UEFI驱动并安装自定义协议到控制器句柄。不同于理论讲解我们将聚焦于可编译的实战代码涵盖从GUID定义到协议安装的完整流程。1. 环境准备与基础架构开发UEFI驱动首先需要配置合适的开发环境。EDK II作为官方开发套件提供了完整的工具链和库支持。以下是基础环境配置步骤# 克隆EDK II仓库 git clone https://github.com/tianocore/edk2.git cd edk2 git submodule update --init # 编译基础工具 make -C BaseTools关键开发组件MdePkg包含UEFI基础类型定义MdeModulePkg提供驱动模型实现参考UefiDriverEntryPoint驱动入口点库开发自定义驱动时需要创建以下文件结构MyDriver/ ├── MyDriver.c # 驱动主逻辑 ├── MyDriver.h # 头文件 ├── MyDriver.inf # 构建描述文件 └── MyDriver.uni # 多语言支持2. 驱动框架实现2.1 定义协议GUID每个UEFI协议都需要唯一的GUID标识。使用UUID生成工具创建后在头文件中定义// MyDriver.h #define MY_PROTOCOL_GUID \ {0xaabbccdd,0x1234,0x4321,{0xaa,0xbb,0xcc,0xdd,0xee,0xff,0x11,0x22}} typedef struct _MY_PROTOCOL { EFI_STATUS (EFIAPI *Function1)(IN UINT32 Param); EFI_STATUS (EFIAPI *Function2)(OUT VOID **Buffer); } MY_PROTOCOL; extern EFI_GUID gMyProtocolGuid;在C文件中实例化GUID// MyDriver.c EFI_GUID gMyProtocolGuid MY_PROTOCOL_GUID;2.2 实现驱动绑定协议EFI_DRIVER_BINDING_PROTOCOL是UEFI驱动模型的核心包含三个关键函数EFI_DRIVER_BINDING_PROTOCOL gMyDriverBinding { MyDriverSupported, MyDriverStart, MyDriverStop, 0x10, // 驱动版本 NULL, // 由系统填充 NULL // 由系统填充 };Supported函数检测设备兼容性EFI_STATUS EFIAPI MyDriverSupported( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { EFI_STATUS Status; // 检查控制器是否支持所需协议 Status gBS-OpenProtocol( ControllerHandle, gEfiRequiredProtocolGuid, NULL, This-DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_TEST ); return Status; }3. 协议安装与使用3.1 Start函数实现当系统检测到兼容设备时Start函数被调用进行实际初始化EFI_STATUS EFIAPI MyDriverStart( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { EFI_STATUS Status; MY_PROTOCOL *MyProtocol; // 分配协议实例内存 Status gBS-AllocatePool( EfiBootServicesData, sizeof(MY_PROTOCOL), (VOID**)MyProtocol ); if (EFI_ERROR(Status)) return Status; // 初始化协议成员函数 MyProtocol-Function1 MyFunction1Impl; MyProtocol-Function2 MyFunction2Impl; // 安装协议到控制器句柄 Status gBS-InstallProtocolInterface( ControllerHandle, gMyProtocolGuid, EFI_NATIVE_INTERFACE, MyProtocol ); return Status; }3.2 协议调用示例安装后的协议可通过标准UEFI接口访问EFI_STATUS AccessMyProtocol(EFI_HANDLE Handle) { MY_PROTOCOL *MyProtocol; EFI_STATUS Status gBS-HandleProtocol( Handle, gMyProtocolGuid, (VOID**)MyProtocol ); if (!EFI_ERROR(Status)) { MyProtocol-Function1(0x1234); } return Status; }4. 完整驱动示例以下是整合后的驱动入口实现EFI_STATUS EFIAPI MyDriverEntryPoint( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; // 安装驱动绑定协议 Status EfiLibInstallDriverBindingComponentName2( ImageHandle, SystemTable, gMyDriverBinding, ImageHandle, NULL, NULL ); DEBUG((DEBUG_INFO, MyDriver installed with status %r\n, Status)); return Status; }对应的INF文件关键配置[Defines] INF_VERSION 0x00010005 BASE_NAME MyDriver FILE_GUID 11223344-5566-7788-9900-AABBCCDDEEFF MODULE_TYPE UEFI_DRIVER VERSION_STRING 1.0 ENTRY_POINT MyDriverEntryPoint [Sources] MyDriver.c [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec [Protocols] gEfiDriverBindingProtocolGuid gMyProtocolGuid5. 测试与调试使用UEFI Shell测试驱动# 加载驱动 load fs0:\MyDriver.efi # 连接控制器 connect -r # 查找已安装协议 protocols -l MY_PROTOCOL调试技巧使用DEBUG宏输出日志通过dmpstore -d查看协议数据库利用QEMUGDB进行单步调试实际开发中遇到过的一个典型问题当驱动卸载后未正确清理协议实例时会导致内存泄漏。解决方案是在Stop函数中确保执行EFI_STATUS EFIAPI MyDriverStop( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer ) { MY_PROTOCOL *MyProtocol; // 获取协议实例 gBS-OpenProtocol( ControllerHandle, gMyProtocolGuid, (VOID**)MyProtocol, This-DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); // 卸载协议 gBS-UninstallProtocolInterface( ControllerHandle, gMyProtocolGuid, MyProtocol ); // 释放内存 gBS-FreePool(MyProtocol); return EFI_SUCCESS; }