惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
V
Visual Studio Blog
The GitHub Blog
The GitHub Blog
Apple Machine Learning Research
Apple Machine Learning Research
J
Java Code Geeks
T
Tailwind CSS Blog
大猫的无限游戏
大猫的无限游戏
Jina AI
Jina AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Hugging Face - Blog
Hugging Face - Blog
WordPress大学
WordPress大学
宝玉的分享
宝玉的分享
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
罗磊的独立博客
人人都是产品经理
人人都是产品经理
H
Heimdal Security Blog
Last Week in AI
Last Week in AI
博客园 - 【当耐特】
Cyberwarzone
Cyberwarzone
Google DeepMind News
Google DeepMind News
雷峰网
雷峰网
Hacker News: Ask HN
Hacker News: Ask HN
Webroot Blog
Webroot Blog
Microsoft Azure Blog
Microsoft Azure Blog
MyScale Blog
MyScale Blog
A
About on SuperTechFans
V2EX - 技术
V2EX - 技术
小众软件
小众软件
博客园 - Franky
博客园 - 司徒正美
P
Privacy International News Feed
爱范儿
爱范儿
U
Unit 42
博客园 - 叶小钗
The Hacker News
The Hacker News
C
Check Point Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Simon Willison's Weblog
Simon Willison's Weblog
N
News and Events Feed by Topic
D
Docker
T
Threatpost
MongoDB | Blog
MongoDB | Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
H
Help Net Security
L
LINUX DO - 最新话题
Security Latest
Security Latest
T
The Exploit Database - CXSecurity.com
S
SegmentFault 最新的问题
A
Arctic Wolf
Spread Privacy
Spread Privacy

博客园_首页

Linux实操--组管理、权限管理和定时任务 Java + EasyExcel 实现单个接口导出多个Excel Mem0 源码解析系列(二):提示词工程的深度剖析 Openclaw TaskFlow究竟是什么?和普通Skill技能有什么区别 博文阅读密码验证 - 博客园 嘉立创开源:应该是全网MicroPython教程最多的开发板 Hermes Agent 集成实践:从协议到生产 2026年AI编程工具横评:Cursor、Codex、Claude Code、Zed、Windsurf Java程序员必看的RAG入门教程 2026 AI效率神器:Superpowers + Claude Code 保姆级教程 本地大模型部署全攻略:从 0 到 1 玩转 Ollama 【从0到1构建一个ClaudeAgent】内存管理-上下文压缩 .NET 高级开发 | 设计、实现一个事件总线框架 电子小白入门之NE555 3. WorkBuddy:隐藏玩法,一键召唤专家,让 AI 以"专家身份"给你干活 和AI一起搞事情#3:Claude Teammate 游戏开发翻车实录 【OpenClaw】通过 Nanobot 源码学习架构---(7)Memory C# .NET 周刊|2026年3月3期 我在 Debian 11 上把 K8s 单机搭起来了,过程没你想的那么顺(/opt 目录版) 深度学习进阶(七)Data-efficient Image Transformer CLI+Skill搭建浏览器AI自动化框架,告别一切重复枯燥任务 告别Token账单无底洞:OpenClaw本地部署,重塑企业数据主权的唯一解 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! SBTI 爆火后,我做了个程序员版的 CBTI。。已开源 + 附开发过程 多模态检索开始进入工程期:用 Sentence Transformers 搭建可落地的 Multimodal RAG 100多行代码实现一个最简单的Agent(用ReAct) Claude Code 通关手册(八):推荐 5 个 Hooks,代码质量提升 3 倍 老板:“有人截图了!”。安全部门:“收到,马上查暗水印!” - why技术 技术之外,皆是人间 C#/.NET/.NET Core技术前沿周刊 | 第 69 期(2026年4.01-4.12) Snack JSONPath 项目架构分析 Claude Code Buddy 小析:一个非核心功能,如何体现产品的细节完成度 AI新时代下的图床管理方案-Cloudflare图床+MCP+Skills方案指南 化繁为简:顺丰速运App如何通过 HarmonyOS SDK实现专业级空间测量 从零实现富文本编辑器#13-React非编辑节点的内容渲染 AI开发-python-langchain框架(3-23-OpenAI Functions风格Tool Calling智能助手) .NET + AI 进阶实战:基于类的技能开发 - 打造可治理的 Agent 能力模块 【从0到1构建一个ClaudeAgent】规划与协调-技能 上周热点回顾(4.6-4.12) 电子小白的工具三件套:面包板、杜邦线、万能板 单表五亿数据的查询优化 | Mysql、StarRocks 2. WorkBuddy:从“我是谁”到“帮我干活” C# 如何减少代码运行时间:7 个实战技巧 基于HelixToolkit.SharpDX 渲染3D模型 - 笺上知微 从零开始的双臂具身VLA起源及现阶段发展综述 - SkyXZ 记对 xonsh shell 的使用, 脚本编写, 迁移及调优 - pluvium27 受够了Vibe Coding的失控?换个起点,让AI事半功倍 从开始配置漏洞环境到漏洞复现流程 - 難しい 关于10年工作经验的程序员对OpenClaw的实战经验分享以及看法 - 虚无境 Any metadata 的内存布局 C# .NET 周刊|2026年3月2期 - InCerry 我帮你测过了,测试圈排名第二的 Skill 依然很牛逼 Skill Discovery | 无监督技能发现的经典工作总结 - MoonOut PbootCMS 网站内容数量多导致访问慢?这些实用优化方案帮你提速! - 家兴网络技术工作室 上下文工程是什么?过时了么?一文讲明白! - 一枫说码 网站漏洞怎么发现并修复?一篇实用指南(附完整流程) - 家兴网络技术工作室 开了 TUN 模式还是直连?90% 的人都踩过这个坑 Github日报|2026年04月12日 - AI一族 AScript扩展多种脚本语言 - rockey627 AI 学习笔记:Agent 的记忆机制 你能被装进一个文件里吗?——7 万人把同事"蒸馏"成了 AI - 我没有三颗心脏 Claude Code 通关手册(七):给 AI 装上技能包——Skills 完全指南 - 暮色之狐 在浏览器中快速编辑代码:VSCode Web 集成实践 - Newbe36524 蒸馏自己 skill?基于 Deepseek 的蒸馏器,丐版蒸馏方式,简单便捷 - To_Carpe_Diem Spring AI Aliababa和AgentScope,哪个更好? - 苏三说技术 Etsy 把 1000 个 MySQL 分片迁进 Vitess:425TB 数据背后的真正问题不是性能,而是运维规模 MicroPython LVGL基础知识和概念:底层渲染与性能优化 - FreakStudio 数据库草图算法 Python 潮流周刊#146:CPython 引入 Rust 的进展 - 豌豆花下猫 最小生成树 - mofei1116 红日靶场七:从外网入口、容器逃逸到 AD 接管的完整利用链复盘 - YouDiscovered1t 分享四款开源且实用的 Kafka 管理工具 - 追逐时光者 vLLM 权重加载机制全解析:从挑战到理想架构 LCT 学习笔记 - ACehomoxue Avalonia UI 12.0.0 正式发布:架构演进和性能飞跃 - 张善友 当 AI Agent 把调用链拉长,延迟开始成为一门生意 conhost.exe 无法显示 U+2717 - 145a 太秀了,我把自己蒸馏成了 Skill!已开源 - 程序员鱼皮 ASP.NET Core 内存缓存实战:一篇搞懂该怎么配、怎么避坑 基于 Ghostty 带有分割标签页和为 Claude 编程设计的通知终端 - BugShare AI 焊死入口:教育的“操作系统级”重塑 - 郝hai 初级Java开发工程师使用sql脚本编写代码的过程是简单而且不糊涂 - CoderOilStation Claude Code通关手册(六):MCP协议完全指南 - 暮色之狐 边框灯光环绕动画特效实现指南 - Newbe36524 开源:子木蒸馏版的 SEO 审计工具 seo-audit-skill v1.0 我所理解的Python元模型 【从0到1构建一个ClaudeAgent】规划与协调-TodoWrite - 程序员Seven Claude 和 Codex 在审计 Skill 上性能差异探究 - ACai_sec AScript如何实现中文脚本引擎 - rockey627 【渗透测试】HTB Season10 Garfield 全过程wp - dynasty_chenzi Android 开发者为什么必须掌握 AI 能力?端侧视角下的技术变革 树状数组正确性证明 - AC-wyr 你的 AI 焦虑,可能比 AI 本身更危险——ATM 机没有消灭银行柜员,但恐慌消灭了你的判断力 - 我没有三颗心脏 一个拉胯的分库分表方案有多绝望?整个部门都在救火! - 冰河团队 动态规划入门必学之走方格问题 - Ofnoname PostgREST 与 PostgreSQL 角色权限配置全解析(生产级实践) - SheepDog1998 使用 UEFI 图形输出协议 GOP 在屏幕上显示图像的方法 - 阿源- Claude Code通关手册(五):组建你的AI专家团队,子代理系统 - 暮色之狐 一个程序员到架构师的催婚路之感悟(整整10年后的催婚相亲感悟) - MisterLip 用 Agent Skill 自动生成工作周报 - 赵康
UEFI Driver 程序框架
阿源- · 2026-04-22 · via 博客园_首页

一、前言

前面几节着重介绍了 UEFI 应用程序的编写。在之前的介绍中 UEFI Application 通常在 UEFI Shell 中运行,特点是执行完即退出,不常驻系统且不提供服务,而是查找并使用系统中的 Protocol 服务。本节简单介绍一下 UEFI 的另一种重要的程序类型,即 UEFI Driver。有过 Linux 开发经验的朋友可以很容易理解这种设计思想,即类比于 Linux 的应用层和驱动层分离的设计思想。应用程序不能直接访问硬件,而是基于驱动程序提供的服务访问硬件数据,以实现特定功能。具体来说,UEFI Application 查找和使用 Protocol,而 UEFI Driver 定义和安装 Protocol。

二、驱动框架

在 UEFI 中,驱动的编写和使用一般遵循如下的主线框架:

Driver: Driver加载->识别设备->绑定设备->创建Handle->安装Protocol->
Application: 查找 Protocol 并使用

大多数情况下,驱动对应的是某个硬件设备,其作用是让本来是“死”的设备“活起来”,使得软件层面上能够使用该设备的功能。这个很容易理解。那么如何让我们的驱动程序与硬件设备关联起来呢,这是理解 UEFI 驱动设计思想的关键。

为了实现 Driver 与设备的绑定,UEFI 中的每个 Driver 必须实现一个核心接口:

typedef struct _EFI_DRIVER_BINDING_PROTOCOL {
    EFI_DRIVER_BINDING_SUPPORTED  Supported;
    EFI_DRIVER_BINDING_START      Start;
    EFI_DRIVER_BINDING_STOP       Stop;
    UINT32                        Version;				// 驱动版本号
    EFI_HANDLE                    ImageHandle;			// 产生此驱动绑定协议实例的驱动镜像句柄
    EFI_HANDLE                    DriverBindingHandle;	// 安装此驱动绑定协议实例的句柄,通常=ImageHandle
    								// 后两个参数写为 NULL,可以使用系统填写
} EFI_DRIVER_BINDING_PROTOCOL;

其中前三个是函数指针,这三个函数都需要我们在驱动中去一一实现。

  • Supported():用于判断当前驱动是否支持某个设备(传入设备抽象的 Handle)。当驱动加载的时候,UEFI 系统会遍历所有的设备 Handle,调用该函数,以找到该驱动支持的设备。
  • Start(): 当 Supported() 函数匹配成功后,会调用此函数。Start 函数的作用是在驱动与设备匹配成功之后利用设备 Protocol 对设备进行一系列初始化,并且可以在此为这个设备 Handle 安装新的我们自己实现的 Protocol。需要注意的是,在该驱动调用前,设备 Handle 上一般会有其他基本的 Protocol。
  • Stop(): 其作用是当卸载驱动时,对驱动使用的资源进行释放,并且卸载我们自定义的 Protocol。

*在刚开始学习的时候,很容易认为 Handle 一定对应的是具体的设备。实际上 Handle 有好多种,除了设备之外,每个驱动程序,应用程序本身,还有服务本身,都有自己的 Handle。但是驱动程序的编写一般只针对设备 Handle。

1. Supported 函数

EFI_STATUS
EFIAPI
MyDriverBindingSupported (
    IN EFI_DRIVER_BINDING_PROTOCOL *This,
    IN EFI_HANDLE                  Controller,
    IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
);
  • This: 驱动绑定协议实例指针,指向自己所属的 EFI_DRIVER_BINDING_PROTOCOL 实例,类似于 C++ 的 this 指针。
  • Controller: 待检测的设备/控制器句柄,需要判断这个控制器是否被当前驱动支持。
  • RemainingDevicePath: 剩余设备路径(可选)。用于部分驱动(如总线驱动)的子设备枚举。

示例实现:

以 PCI 设备为例:

该函数用于检查控制器是否为该驱动所支持的 PCI 设备,是则返回成功,否则返回不支持,且不留下协议占用。

EFI_STATUS
EFIAPI
MyDriverBindingSupported (
    IN EFI_DRIVER_BINDING_PROTOCOL *This,
    IN EFI_HANDLE                  Controller,
    IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
)
{
    EFI_STATUS Status;
    EFI_PCI_IO_PROTOCOL *PciIo;
    
    // 1. 如果需要处理 RemainingDevicePath(部分驱动场景)
    if (RemainingDevicePath != NULL && 
        !IsDevicePathValid(RemainingDevicePath, -1)) {
        return EFI_UNSUPPORTED;
    }
    
    // 2. 尝试打开控制器上的 PCI IO 协议
    Status = gBS->OpenProtocol(
        Controller,
        &gEfiPciIoProtocolGuid,
        (VOID **)&PciIo,
        This->DriverBindingHandle,  // 驱动镜像句柄
        Controller,
        EFI_OPEN_PROTOCOL_BY_DRIVER
    );
    
    if (EFI_ERROR(Status)) {
        return EFI_UNSUPPORTED;  // 没有 PCI IO,不支持
    }
    
    // 3. 进一步检查 PCI 配置空间(如 Vendor ID/Device ID)
    PCI_TYPE00 PciConfig;
    Status = PciIo->Pci.Read(
        PciIo,
        EfiPciIoWidthUint32,
        0,  // 偏移 0
        sizeof(PciConfig) / sizeof(UINT32),
        &PciConfig
    );
    
    if (EFI_ERROR(Status)) {
        goto CloseProtocol;
    }
    
    // 检查 VID/DID 是否匹配我的设备
    if (PciConfig.Hdr.VendorId == MY_VENDOR_ID && 
        PciConfig.Hdr.DeviceId == MY_DEVICE_ID) {
        Status = EFI_SUCCESS;
    } else {
        Status = EFI_UNSUPPORTED;
    }
    
CloseProtocol:
    // 必须关闭协议(只检查,不占用)
    gBS->CloseProtocol(
        Controller,
        &gEfiPciIoProtocolGuid,
        This->DriverBindingHandle,
        Controller
    );
    
    return Status;
}

设备启动后,驱动的调用流程:

系统启动 / 设备插入
    ↓
gBS->ConnectController(ControllerHandle)
    ↓
遍历所有已安装的 EFI_DRIVER_BINDING_PROTOCOL
    ↓
按 Version 排序(高版本优先)
    ↓
依次调用 Supported() 函数
    ↓
第一个返回 EFI_SUCCESS 的驱动
    ↓
调用该驱动的 Start() 函数

2. Start 函数

EFI_STATUS
EFIAPI
MyDriverBindingStart (
    IN EFI_DRIVER_BINDING_PROTOCOL *This,
    IN EFI_HANDLE                  Controller,
    IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
);

示例实现:

该函数负责正式接管并初始化一个已被 Supported 验证通过的设备。主要的任务是 OpenProtocol 获得硬件访问能力,然后利用该能力初始化设备,随后安装自定义服务接口,暴露给上层应用。

EFI_STATUS
EFIAPI
MyDriverBindingStart (
    IN EFI_DRIVER_BINDING_PROTOCOL *This,
    IN EFI_HANDLE                  Controller,
    IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
)
{
    EFI_STATUS Status;
    EFI_PCI_IO_PROTOCOL *PciIo;
    MY_DEVICE_PRIVATE_DATA *Private;
    
    // 1. 打开控制器上的 PCI I/O 协议(获得访问硬件的权限)
    Status = gBS->OpenProtocol(
        Controller,
        &gEfiPciIoProtocolGuid,
        (VOID **)&PciIo,
        This->DriverBindingHandle,
        Controller,
        EFI_OPEN_PROTOCOL_BY_DRIVER  // 驱动独占访问
    );
    if (EFI_ERROR(Status)) {
        return Status;
    }
    
    // 2. 为设备分配私有数据结构
    Private = (MY_DEVICE_PRIVATE_DATA *)AllocateZeroPool(
        sizeof(MY_DEVICE_PRIVATE_DATA)
    );
    if (!Private) {
        Status = EFI_OUT_OF_RESOURCES;
        goto CloseProtocol;
    }
    
    // 3. 初始化私有数据
    Private->Signature = MY_DEVICE_SIGNATURE;
    Private->PciIo = PciIo;
    Private->ControllerHandle = Controller;
    Private->DriverBindingHandle = This->DriverBindingHandle;
    
    // 4. 初始化设备硬件(通过 PciIo)
    Status = InitializeHardware(PciIo);
    if (EFI_ERROR(Status)) {
        goto FreePrivate;
    }
    
    // 5. 创建 I/O 抽象协议(供上层使用)
    Status = gBS->InstallMultipleProtocolInterfaces(
        &Controller,
        &gMyDriverIoProtocolGuid, &Private->IoProtocol,
        NULL
    );
    if (EFI_ERROR(Status)) {
        goto FreeHardware;
    }
    
    // 6. 可选:创建设备路径子节点(如果有子设备)
    if (RemainingDevicePath != NULL) {
        // 创建子控制器的逻辑
        CreateChildControllers(Controller, RemainingDevicePath);
    }
    
    return EFI_SUCCESS;
    
FreeHardware:
    // 清理硬件初始化
    CleanupHardware(PciIo);
    
FreePrivate:
    gBS->FreePool(Private);
    
CloseProtocol:
    gBS->CloseProtocol(
        Controller,
        &gEfiPciIoProtocolGuid,
        This->DriverBindingHandle,
        Controller
    );
    
    return Status;
}

3. Stop 函数

EFI_STATUS
EFIAPI
MyDriverBindingStop (
    IN  EFI_DRIVER_BINDING_PROTOCOL *This,
    IN  EFI_HANDLE                  Controller,
    IN  UINTN                       NumberOfChildren,
    IN  EFI_HANDLE                  *ChildHandleBuffer OPTIONAL
);
  • NumberOfChildren: 子控制器的数量。
  • ChildHandleBuffer: 子控制器句柄数组(可选)。

示例实现:

该函数负责停止驱动对控制器的管理并释放所有已分配的资源。一般情况下它与 Start 函数完全对称,执行对应的清理流程。示例函数分类讨论了完全卸载整个设备驱动和保留部分子控制器两种情况。

EFI_STATUS
EFIAPI
MyDriverBindingStop (
    IN  EFI_DRIVER_BINDING_PROTOCOL *This,
    IN  EFI_HANDLE                  Controller,
    IN  UINTN                       NumberOfChildren,
    IN  EFI_HANDLE                  *ChildHandleBuffer OPTIONAL
)
{
    EFI_STATUS Status;
    MY_DEVICE_PRIVATE_DATA *DevicePrivate;
    
    // 1. 获取设备私有数据(之前 Start 中安装的)
    Status = gBS->OpenProtocol(
        Controller,
        &gMyDriverDevicePrivateGuid,
        (VOID **)&DevicePrivate,
        This->DriverBindingHandle,
        Controller,
        EFI_OPEN_PROTOCOL_GET_PROTOCOL  // 只获取,不打开
    );
    if (EFI_ERROR(Status)) {
        return EFI_DEVICE_ERROR;
    }
    
    // 2. 根据是否有子控制器,执行不同逻辑
    if (NumberOfChildren == 0) {
        // 模式1:完全停止主控制器
        
        // 2.1 先停止并销毁所有子控制器
        while (DevicePrivate->ChildCount > 0) {
            gBS->StopController(
                DevicePrivate->ChildHandles[0],
                This->DriverBindingHandle,
                NULL  // 停止所有子控制器的子设备
            );
        }
        
        // 2.2 关闭在 Controller 上打开的所有协议
        gBS->CloseProtocol(
            Controller,
            &gEfiPciIoProtocolGuid,
            This->DriverBindingHandle,
            Controller
        );
        
        // 2.3 释放设备私有数据
        gBS->FreePool(DevicePrivate);
        
        // 2.4 从 Controller 上卸载私有数据协议(可选)
        gBS->UninstallMultipleProtocolInterfaces(
            Controller,
            &gMyDriverDevicePrivateGuid, DevicePrivate,
            NULL
        );
        
    } else {
        // 模式2:选择性停止指定的子控制器
        
        for (UINTN Index = 0; Index < NumberOfChildren; Index++) {
            EFI_HANDLE ChildHandle = ChildHandleBuffer[Index];
            MY_CHILD_PRIVATE_DATA *ChildPrivate;
            
            // 2.1 获取子设备私有数据
            Status = gBS->OpenProtocol(
                ChildHandle,
                &gMyDriverChildPrivateGuid,
                (VOID **)&ChildPrivate,
                This->DriverBindingHandle,
                Controller,
                EFI_OPEN_PROTOCOL_GET_PROTOCOL
            );
            if (EFI_ERROR(Status)) {
                continue;
            }
            
            // 2.2 清理子设备资源
            if (ChildPrivate->TimerEvent) {
                gBS->CloseEvent(ChildPrivate->TimerEvent);
            }
            
            // 2.3 关闭子设备上的协议
            gBS->CloseProtocol(
                ChildHandle,
                &gEfiDevicePathProtocolGuid,
                This->DriverBindingHandle,
                Controller
            );
            
            // 2.4 从子设备卸载私有数据
            gBS->UninstallMultipleProtocolInterfaces(
                ChildHandle,
                &gMyDriverChildPrivateGuid, ChildPrivate,
                NULL
            );
            
            // 2.5 释放子设备私有数据
            gBS->FreePool(ChildPrivate);
            
            // 2.6 从父设备的子控制器列表中移除
            RemoveChildFromList(DevicePrivate, ChildHandle);
        }
    }
    
    return EFI_SUCCESS;
}

Stop 函数与 Start 函数的对应关系:

Start() 执行的操作              Stop() 必须执行的反向操作
OpenProtocol()          →     CloseProtocol()
AllocatePool()          →     FreePool()
CreateEvent()           →     CloseEvent()
InstallProtocol()       →     UninstallProtocol()
CreateChildHandle()     →     DestroyChildHandle()  // 通过 DisconnectController

4. 入口函数

我们前面介绍了驱动绑定协议,入口函数在驱动被加载时由固件调用,主要任务是注册我们定义好的驱动绑定协议,也就是通过 InstallMultipleProtocolInterfaces 将驱动绑定协议安装到该驱动的 ImageHandle 句柄上,使 UEFI 驱动模型能够识别并调用该驱动的 Supported/Start/Stop 接口。

// 驱动全局变量
EFI_DRIVER_BINDING_PROTOCOL gMyDriverBinding = {
    MyDriverBindingSupported,
    MyDriverBindingStart,
    MyDriverBindingStop,
    0x10,                          // 驱动版本
    NULL,                          // 可选的镜像句柄
    NULL                           // 可选的驱动绑定句柄
};

// 驱动入口函数
EFI_STATUS
EFIAPI
MyDriverEntryPoint (
    IN EFI_HANDLE           ImageHandle,
    IN EFI_SYSTEM_TABLE     *SystemTable
)
{
    EFI_STATUS  Status;
    
    // 1. 保存系统表指针(供驱动其他地方使用)
    gST = SystemTable;
    gBS = SystemTable->BootServices;
    gImageHandle = ImageHandle;
    
    // 2. 初始化驱动绑定协议
    gMyDriverBinding.ImageHandle = ImageHandle;
    gMyDriverBinding.DriverBindingHandle = ImageHandle;
    
    // 3. 安装驱动绑定协议到镜像句柄
    Status = gBS->InstallMultipleProtocolInterfaces(
        &gMyDriverBinding.DriverBindingHandle,
        &gEfiDriverBindingProtocolGuid, &gMyDriverBinding,
        NULL
    );
    
    if (EFI_ERROR(Status)) {
        DEBUG((EFI_D_ERROR, "Failed to install Driver Binding Protocol: %r\n", Status));
        return Status;
    }
    
    // 4. 可选:安装组件名称协议(用于显示驱动名称)
    Status = gBS->InstallMultipleProtocolInterfaces(
        &gMyDriverBinding.DriverBindingHandle,
        &gEfiComponentNameProtocolGuid,  &gMyComponentName,
        &gEfiComponentName2ProtocolGuid, &gMyComponentName2,
        NULL
    );
    
    if (EFI_ERROR(Status)) {
        DEBUG((EFI_D_WARN, "Failed to install Component Name Protocol: %r\n", Status));
        // 不致命,继续执行
    }
    
    // 5. 驱动加载成功
    DEBUG((EFI_D_INFO, "MyDriver loaded successfully\n"));
    
    return EFI_SUCCESS;
}

三、示例程序

此示例是一个简化的 UEFI DXE 阶段 USB 设备驱动示例程序,它遵循 UEFI 驱动模型标准,通过实现驱动绑定协议中的 SupportedStartStop 三个核心函数来管理 USB 设备。程序从 SimpleUsbDriverEntryPoint 入口函数开始执行,首先将包含这三个函数指针的 EFI_DRIVER_BINDING_PROTOCOL 实例安装到当前驱动的镜像句柄上,从而向 UEFI 固件注册该驱动。当系统枚举到新的 USB 设备时,固件会调用 SimpleUsbDriverSupported 函数,该函数通过尝试以 BY_DRIVER 方式打开控制器上的 EFI_USB_IO_PROTOCOL 来验证设备是否为 USB 设备,检查完毕后立即关闭协议以避免占用。一旦确认支持,固件随即调用 SimpleUsbDriverStart 函数正式接管设备,在此阶段驱动会分配并初始化设备私有上下文结构体 SIMPLE_USB_DEVICE,长期打开 EFI_USB_IO_PROTOCOL 以获得硬件访问权,并通过该协议读取 USB 设备描述符,将设备的厂商标识、产品标识及类别等信息打印到调试输出中。最后,当驱动需要被卸载或设备被移除时,SimpleUsbDriverStop 函数会被触发,负责关闭已打开的 USB I/O 协议并释放之前分配的所有内存资源,完成整个驱动的退出流程。

/** @file
 最简单的DXE阶段USB驱动示例
 演示如何绑定USB设备并安装协议
**/

#include <Uefi.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>

// USB相关协议头文件
#include <Protocol/UsbIo.h>
#include <Protocol/DevicePath.h>

// 驱动私有上下文结构
typedef struct {
    EFI_HANDLE              ControllerHandle;    // 绑定的USB控制器句柄
    EFI_USB_IO_PROTOCOL     *UsbIo;              // USB I/O协议指针
    EFI_DEVICE_PATH_PROTOCOL *DevicePath;        // 设备路径
} SIMPLE_USB_DEVICE;

// 全局变量:驱动绑定协议实例
EFI_DRIVER_BINDING_PROTOCOL gSimpleUsbDriverBinding = {
    SimpleUsbDriverSupported,
    SimpleUsbDriverStart,
    SimpleUsbDriverStop,
    0x10,        // 驱动版本号
    NULL,        // 不需要ImageHandle
    NULL         // 不需要DeviceHandle
};

/**
  检查驱动是否支持该USB设备
**/
EFI_STATUS
EFIAPI
SimpleUsbDriverSupported (
    IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    IN EFI_HANDLE                   Controller,
    IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
    )
{
    EFI_STATUS          Status;
    EFI_USB_IO_PROTOCOL *UsbIo;
    
    DEBUG((DEBUG_INFO, "[SimpleUSB] Supported() called for Controller: %p\n", Controller));
    
    // 1. 尝试打开USB I/O协议
    Status = gBS->OpenProtocol(
        Controller,
        &gEfiUsbIoProtocolGuid,
        (VOID **)&UsbIo,
        This->DriverBindingHandle,
        Controller,
        EFI_OPEN_PROTOCOL_BY_DRIVER
    );
    
    if (EFI_ERROR(Status)) {
        DEBUG((DEBUG_ERROR, "[SimpleUSB] No USB I/O protocol, Status: %r\n", Status));
        return Status;
    }
    
    // 2. 可以进一步检查USB设备类型(Class/SubClass/Protocol)
    // 这里简化处理:只要有USB I/O协议就认为支持
    
    // 3. 关闭协议(Supported()不能占用协议)
    gBS->CloseProtocol(
        Controller,
        &gEfiUsbIoProtocolGuid,
        This->DriverBindingHandle,
        Controller
    );
    
    DEBUG((DEBUG_INFO, "[SimpleUSB] Device is supported!\n"));
    return EFI_SUCCESS;
}

/**
  启动驱动,初始化USB设备
**/
EFI_STATUS
EFIAPI
SimpleUsbDriverStart (
    IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    IN EFI_HANDLE                   Controller,
    IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
    )
{
    EFI_STATUS               Status;
    SIMPLE_USB_DEVICE        *Device;
    EFI_USB_IO_PROTOCOL      *UsbIo;
    EFI_DEVICE_PATH_PROTOCOL *DevicePath;
    EFI_USB_DEVICE_DESCRIPTOR UsbDeviceDesc;
    
    DEBUG((DEBUG_INFO, "[SimpleUSB] Start() called for Controller: %p\n", Controller));
    
    // 1. 分配设备私有数据结构
    Device = AllocateZeroPool(sizeof(SIMPLE_USB_DEVICE));
    if (Device == NULL) {
        DEBUG((DEBUG_ERROR, "[SimpleUSB] Failed to allocate device context\n"));
        return EFI_OUT_OF_RESOURCES;
    }
    
    // 2. 打开USB I/O协议
    Status = gBS->OpenProtocol(
        Controller,
        &gEfiUsbIoProtocolGuid,
        (VOID **)&UsbIo,
        This->DriverBindingHandle,
        Controller,
        EFI_OPEN_PROTOCOL_BY_DRIVER
    );
    
    if (EFI_ERROR(Status)) {
        DEBUG((DEBUG_ERROR, "[SimpleUSB] Failed to open USB I/O, Status: %r\n", Status));
        goto ErrorFreeDevice;
    }
    
    // 3. 获取设备路径
    Status = gBS->OpenProtocol(
        Controller,
        &gEfiDevicePathProtocolGuid,
        (VOID **)&DevicePath,
        This->DriverBindingHandle,
        Controller,
        EFI_OPEN_PROTOCOL_GET_PROTOCOL
    );
    
    if (EFI_ERROR(Status)) {
        DEBUG((DEBUG_ERROR, "[SimpleUSB] Failed to get device path, Status: %r\n", Status));
        goto ErrorCloseProtocol;
    }
    
    // 4. 读取USB设备描述符(标准USB操作示例)
    Status = UsbIo->UsbGetDeviceDescriptor(UsbIo, &UsbDeviceDesc);
    if (EFI_ERROR(Status)) {
        DEBUG((DEBUG_ERROR, "[SimpleUSB] Failed to get device descriptor, Status: %r\n", Status));
        goto ErrorCloseProtocol;
    }
    
    // 5. 打印设备信息
    DEBUG((DEBUG_INFO, "[SimpleUSB] USB Device Info:\n"));
    DEBUG((DEBUG_INFO, "  Vendor ID  : 0x%04X\n", UsbDeviceDesc.IdVendor));
    DEBUG((DEBUG_INFO, "  Product ID : 0x%04X\n", UsbDeviceDesc.IdProduct));
    DEBUG((DEBUG_INFO, "  Class      : 0x%02X\n", UsbDeviceDesc.DeviceClass));
    DEBUG((DEBUG_INFO, "  SubClass   : 0x%02X\n", UsbDeviceDesc.DeviceSubClass));
    DEBUG((DEBUG_INFO, "  Protocol   : 0x%02X\n", UsbDeviceDesc.DeviceProtocol));
    DEBUG((DEBUG_INFO, "  MaxPacket0 : %d\n", UsbDeviceDesc.MaxPacketSize0));
    
    // 6. 保存设备上下文
    Device->ControllerHandle = Controller;
    Device->UsbIo = UsbIo;
    Device->DevicePath = DevicePath;
    
    // 7. 安装自定义协议(表示驱动已成功启动)
    // 注意:你需要先定义自己的协议GUID
    // Status = gBS->InstallProtocolInterface(
    //     &Controller,
    //     &gSimpleUsbDeviceProtocolGuid,
    //     EFI_NATIVE_INTERFACE,
    //     Device
    // );
    
    DEBUG((DEBUG_INFO, "[SimpleUSB] Driver started successfully!\n"));
    return EFI_SUCCESS;
    
ErrorCloseProtocol:
    gBS->CloseProtocol(
        Controller,
        &gEfiUsbIoProtocolGuid,
        This->DriverBindingHandle,
        Controller
    );
    
ErrorFreeDevice:
    FreePool(Device);
    return Status;
}

/**
  停止驱动,清理资源
**/
EFI_STATUS
EFIAPI
SimpleUsbDriverStop (
    IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    IN EFI_HANDLE                   Controller,
    IN UINTN                        NumberOfChildren,
    IN EFI_HANDLE                   *ChildHandleBuffer
    )
{
    EFI_STATUS Status;
    SIMPLE_USB_DEVICE *Device = NULL;
    
    DEBUG((DEBUG_INFO, "[SimpleUSB] Stop() called for Controller: %p\n", Controller));
    
    // 1. 获取设备私有数据(如果你安装了自定义协议)
    // Status = gBS->OpenProtocol(
    //     Controller,
    //     &gSimpleUsbDeviceProtocolGuid,
    //     (VOID **)&Device,
    //     This->DriverBindingHandle,
    //     Controller,
    //     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    // );
    
    // 2. 关闭USB I/O协议
    Status = gBS->CloseProtocol(
        Controller,
        &gEfiUsbIoProtocolGuid,
        This->DriverBindingHandle,
        Controller
    );
    
    // 3. 释放设备上下文
    if (Device != NULL) {
        FreePool(Device);
    }
    
    DEBUG((DEBUG_INFO, "[SimpleUSB] Driver stopped\n"));
    return EFI_SUCCESS;
}

/**
  驱动入口点
**/
EFI_STATUS
EFIAPI
SimpleUsbDriverEntryPoint (
    IN EFI_HANDLE        ImageHandle,
    IN EFI_SYSTEM_TABLE  *SystemTable
    )
{
    EFI_STATUS Status;
    
    DEBUG((DEBUG_INFO, "[SimpleUSB] Driver Entry Point\n"));
    
    // 1. 设置驱动绑定协议的句柄
    gSimpleUsbDriverBinding.DriverBindingHandle = ImageHandle;
    gSimpleUsbDriverBinding.ImageHandle = ImageHandle;
    
    // 2. 安装驱动绑定协议到ImageHandle
    Status = gBS->InstallMultipleProtocolInterfaces(
        &ImageHandle,
        &gEfiDriverBindingProtocolGuid,
        &gSimpleUsbDriverBinding,
        NULL
    );
    
    if (EFI_ERROR(Status)) {
        DEBUG((DEBUG_ERROR, "[SimpleUSB] Failed to install Driver Binding Protocol, Status: %r\n", Status));
        return Status;
    }
    
    DEBUG((DEBUG_INFO, "[SimpleUSB] Driver Binding Protocol installed successfully\n"));
    DEBUG((DEBUG_INFO, "[SimpleUSB] Waiting for USB devices...\n"));
    
    return EFI_SUCCESS;
}

示例代码 AI 生成后整理。


Steady Progress!