开发 UEFI 驱动

服务型驱动的特点:
1)在 Image 的入口函数中执行安装;
2)服务型驱动不需要驱动特定硬件,可以安装到任意控制器上;
3)没有提供卸载函数。

一个设备 / 总线驱动程序在安装时首先要找到对应的硬件设备(在 UEFI 中是要找到对应的控制器),然后执行安装操作,将驱动程序安装到硬件设备的控制器上。有时,还需要卸载驱动更新驱动(先卸载旧的驱动,然后安装新的驱动)。有时,安装操作可能需要执行多次,例如,第一次安装时发现设备没有准备好,或者所依赖的某个Protocol没有安装,就需要退出安装,执行其他操作,然后进行第二次安装。

一个完整的驱动程序框架需要三个部分:
1)Findout():找出对应的硬件设备;
2)Install / Start():安装驱动到指定的硬件设备;
3)Uninstall / Stop():从硬件设备中卸载驱动。

另外,系统中支持该驱动的设备可能不止一个,因而框架必须支持多次安装。通常服务型驱动是不能多次安装的(仅在模块入口函数中执行安装)。

UEFI 驱动模型

UEFI 驱动模型的核心是通过 EFI Driver Binding Protocol 管理驱动程序。
一个完整的驱动程序包含两个核心部分:EFI Driver Binding Protocol 以及驱动服务本身。作为一个用户友好的驱动程序,通常它还要包含一个EFI Component Name Protocol

EFI Driver Binding Protocol 的构成

在 UEFI 驱动的入口函数中,安装 EFI Driver Binding Protocol (EDBP) 到某个 Handle(大部分情况下是自身,即 ImageHandle,有时也会安装到其他Handle上),这个EBDP实例会常驻内存,用于驱动的安装和卸载。
使用EBDP可以多次操作(查找设备,安装卸载)驱动。
在这里插入图片描述
EDBP 有 3 个成员函数和3个成员变量。
成员变量ImageHandle是生成EDBP的映像文件句柄。DriverBindingHandle是安装了EDBPHandle。通常这个Handle 就是 driverImageHandle,但并非绝对

EDBP的核心是SupportedStartStop这3个成员函数:
1)Supported 函数用于检测一个设备是否支持该驱动。
2)Start 用于将驱动安装到设备上。
3)Stop用于将驱动从设备上卸载。

Version 是驱动的版本号。在所有支持同一个控制器的 EDBP 中,版本号高的具有较高的优先级,优先被安装到设备上。0x0~0xOF0xFFFFFFF0~0xFFFFFFFF 保留给平台和 OEM 驱动。0x10~0xFFFFFFEF 保留给 IHV 驱动。

Supported 函数
Supported 函数用于检查一个设备控制器是否支持该驱动。如果控制器支持该驱动,则该函数返EFI_SUCCESS,否则返回EFI_UNSUPPORTEDEFI_ACCESS_DENIEDEFI_ALREADY_STARTED等。
在这里插入图片描述

Start 函数
Start 函数用来将驱动安装到设备上并启动硬件设备,在函数中最重要的事情是调用InstallProtocolInterface()或者 InstallMultipleProtocolInterfaces()ControllerHandle上安装驱动 Protocol
在这里插入图片描述

Stop 函数
Stop 函数用于停止硬件设备并卸载驱动(调用 UninstallProtocolInterface()UninstallMultipleProtocolInterfaces()ControllerHandle 卸载驱动协议)。
在这里插入图片描述
对设备驱动来讲,NumberOfChildren0ChildHandleBufferNULL。对Bus Driver来讲,如果 NumberOfChildren不为0,那么ChildHandleBuffer 中的子节点都要被释放。

UEFI 驱动程序框架工作:
在这里插入图片描述

SortedDriverBindingProtocols[]数组存放了所有的EDBP实例,并且数组中的Protocol按优先级排序,前面的EDBP被优先测试和安装。从前至后遍历SortedDriverBindingProtocols[]中的EDBP,找到支持该控制器的驱动并安装该驱动,直到没有任何驱动支持这个设备后才退出while 循环。

CoreConnectSingleController 用于为指定的设备控制器安装驱动,它是gBS->Connect-Controller 服务的核心。
在这里插入图片描述
如果 ContextDriverlmageHandles为空,则遍历系统中的所有DriverBindingProtocol,否则就只遍历指定的 DriverBindingProtocolSortedDriverBindingProtocols[]存放了需要测试的 DriverBindingProtocol,对于每一个需要测试的DriverBindingProtocol,首先调用DriverBinding->Supported(...)测试该 DriverBindingProtocol是否支持ControllerHandle,如果Supported 函数返回 EFI_SUCCESS,则调用 DriverBinding->Start(...)ControllerHandle 安装驱动,启动设备。

在这里插入图片描述
CoreDisconnectController对应于gBS->DisconnectController 服务。若DriverImageHandle为空,则卸载 ControllerHandle上的所有驱动。

加载驱动的整个过程:
  1. 在 Shell 中使用命令 Load 将驱动文件加载到内存,加载后 UEFI 会调用 gBS->StartImage(...) 执行 DriverImage 的入口函数;
  2. 在入口函数里,Driver Binding Protocol 被加载到 Handle 上(Driver Image handle 或者其他的 Controller Handle),然后 UEFI 会遍历所有的控制器,为每个控制器调用 CoreConnectSingleController 函数;
  3. CoreConnectSingleController 中会调用 EDBPSupported 函数测试这个驱动是否支持该控制器,如果支持,则调用 Start() 安装驱动。

EFI Component Name Protocol 的作用和构成

通常每个驱动都还有一个可打印的名字,便于向用户显示驱动的信息。这个可打印名字是出 EFI Component Name Protocol (ECNP)EFI Component Name2 Protocol (ECN2P) 提供的。ECNPECN2P不是驱动必需的Protocol

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
SupportedLanguages 是此Protocol所支持的语言列表。这是一个由ISO 639-2语言代码组成的 ASCII 字符串。例如,"zho;eng"表示 ECNP 支持中文和英文;
GetDriverName用于取得驱动程序的名字;
GetControllerName 用于取得控制器或子控制器的名字。若在参数列表中指定了子控制器,则输出参数ControllerName返回子控制器的名字,否则返回控制器ControllerHande的名字。如果对应的驱动是设备驱动,则子控制器ChildHandle 一定为 Null。如果对应的驱动是总线驱动,则该驱动可以有子控制器。

ECNP 使用ISO639-2语言代码,ECNP2 使用RFC4646语言代码,区别仅仅在于语言代码格式不同。

编写设备驱动的步骤

驱动分为两部分,一部分是硬件相关的部分,这部分是驱动的内容,用于驱动硬件设备,为用户提供服务,以协议的形式出现,如DiskloBlocklo
另一部分是驱动的框架部分,需要实现 Driver Binding Protocol,主要是其三个接口(SupportedStartStop),这部分用于驱动的安装与卸载。

(1) Supported 函数要点

  • 1)忽略参数 RemainingDevicePath
  • 2)使用函数 OpenProtocol() 打开所有需要的 Protocol。标准的驱动要用 EFI_OPEN_PROTOCOL_BY_DRIVER 属性打开 Protocol。如果要独占某个 Protocol,首先要关闭所有使用该 Protocol 的其他驱动,然后用属性 EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE 打开 Protocol
  • 3)如果 2)中 OpenProtocol() 返回错误,则调用 CloseProtocol() 关闭所有打开的 Protocol 并返回错误代码;
  • 4)所需的所有 Protocol 成功打开后,测试这个 Driver 是否支持此 Controller。有时使用这些 Protocol 足以完成测试,有时还需要此 Controller 的其他特征。如果任一项测试失败,则用 CloseProtocol() 关闭所有打开的 Protocol,返回 EFI_UNSUPPORTED
  • 5)测试成功,调用 CloseProtocol() 关闭已经打开的 Protocol
  • 6)返回 EFI_SUCCESS

(2)Start 函数要点

  • 1)忽略参数 RemainingDevicePath
  • 2)使用函数 OpenProtocol() 打开所有需要的Protocol。标准的驱动要用 EFI_OPEN_PROTOCOL_BY_DRIVER 属性打开 Protocol。如果要独占某个Protocol,首先要关闭所有使用该Protocol的其他驱动,然后用属性EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE 打开 Protocol
  • 3)如果 2)中 OpenProtocol()返回错误,则调用CloseProtocol()关闭所有已经打开的Protocol并返回错误代码;
  • 4)初始化 ControllerHandle 所指定的设备。如果有错误,则关闭所有已打开的 Protocol 并返回 EFI_DEVICE_ERROR
  • 5)分配并初始化要用到的数据结构,这些数据结构包括驱动Protocol及其他相关的私有数据结构。如果分配资源时发生错误,则关闭所有已打开的Protocol,释放已经得到的资源,返回 EFI_OUT_OF_RESOURCES
  • 6)用 InstallMultipleProtocolInterfaces() 安装驱动协议到ControllerHandle。如果有错误发生,则关闭所有已打开的 Protocol,并返回错误代码。
  • 7)返回 EFI_SUCCESS

(3)Stop 函数要点

  • 1)用 UninstallMultipleProtocolInterfaces() 载所安装的 Protocol
  • 2)关闭所有已打开的 Protocol
  • 3)释放所有已申请的资源。

PCI 设备驱动基础

每个 PCI 设备都有三种地址空间:配置空间IO 空间内存空间

系统初始化时系统会初始化每个 PCI 设备的配置空间寄存器。配置地址空间大小为256字节,前64字节是标准的,后面的寄存器由设备自定义用途。

在这里插入图片描述

PCI 设备中的 IO 和内存空间被划分为1~6个互不重叠的子空间,每个子空间用于完成一组相对独立的子功能。BaseAddress0 ~ BaseAddress5表示子空间的基地址(物理地址)。对设备的操作主要是通过对子空间的读写来实现的。

UEFI 提供了EFI_PCI_IO_PROTOCOL(简称PciIo)来操作 PCI 设备:
在这里插入图片描述

Pci服务用于读写配置空间:
在这里插入图片描述

Pci 服务的Read函数用于读取 PCI 配置空间内从偏移Offset处开始的Count个寄存器,每个寄存器的大小为 Width,读取的总字节数为Count x WidthWrite 函数用于写PCI配置空间内从偏移 Offset处开始的Count个寄存器,每个寄存器的大小为 Width,写入的总字节数为Count x WidthWidth 必须是EFI_PCI_IO_PROTOCOL_WIDTH中的某一个,其枚举如下:

在这里插入图片描述

如果由OffsetWidthCount指定的地址不被控制器接受,那么Read 函数和 Write 函数将返回 EFI_UNSUPPORTED 错误值。

IO 服务用于读写 PCI 设备的 IO 空间上的寄存器:
在这里插入图片描述

内容来源于《UEFI 原理与编程》。。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/63524.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java时间处理SimpleDateFormat详解

文章目录 常用构造函数日期格式模式常见用法1. 格式化日期2. 解析日期字符串 注意事项示例扩展:指定区域和时区 SimpleDateFormat 是 Java 中用于日期和时间格式化的类,属于 java.text 包。它允许开发者将日期对象格式化为字符串,或者将字符…

夜莺运维指南之故障自愈

注意: 夜莺v7版本已内置故障自愈, 只需要更给n9e下的config.yaml 文件有关ibex配置即可 所谓的告警自愈,典型手段是在告警触发时自动回调某个 webhook 地址,在这个 webhook 里写告警自愈的逻辑,夜莺默认支持这种方式。另外,夜莺还…

LDR6500:音频双C支持,数字与模拟的完美结合

在当今数字化快速发展的时代,音频设备的兼容性和性能成为了用户关注的重点。LDR6500,作为乐得瑞科技精心研发的USB Power Delivery(PD)协议芯片,凭借其卓越的性能和广泛的应用兼容性,为音频设备领域带来了新…

python rstrip 的迷惑行为

在项目中,我需要把字符串末尾的一部分去掉,类似截断,我用ide的随笔提示,发现了rstrip这个方法,然后我试了下,满足我的需求,但在测试过程中,我发现了rstrip的一些行为很让我迷惑。 开…

计算机网络编程(Linux):I/O多路转接之 select,poll

I/O多路复用(I/O Multiplexing)是一种高效的网络编程技术,允许一个线程同时监控多个文件描述符的状态,当某个文件描述符就绪时进行相应处理。这种技术在高并发服务器中广泛使用。本文将介绍I/O多路复用的核心概念及在Linux中的实现…

【原生js案例】webApp实现鼠标移入移出相册放大缩小动画

图片相册这种动画效果也很常见,在我们的网站上。鼠标滑入放大图片,滑出就恢复原来的大小。现在我们使用运动定时器来实现这种滑动效果。 感兴趣的可以关注下我的系列课程【webApp之h5端实战】,里面有大量的css3动画效果制作原生知识分析&…

Spring Boot助力,一键解锁招聘全流程信息精细化管理

2系统相关技术 2.1 Java语言介绍 Java是由SUN公司推出,该公司于2010年被oracle公司收购。Java本是印度尼西亚的一个叫做爪洼岛的英文名称,也因此得来java是一杯正冒着热气咖啡的标识。Java语言在移动互联网的大背景下具备了显著的优势和广阔的前景&#…

Day28两个数组的交集

给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的 交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 class Solution{public int[] intersection(int[] nums1, int[] nums2) {Set<Integer> set new HashSet<>();for (int i :…

VRRP的知识点总结及实验

1、VRRP VRRP(Virtual Router Redundancy Protocol&#xff0c;虚拟路由器冗余协议)既能够实现网关的备份&#xff0c;又能解决多个网关之间互相冲突的问题&#xff0c;从而提高网络可靠性。 2、VRRP技术概述&#xff1a; 通过把几台路由设备联合组成一台虚拟的“路由设备”…

DP协议:概括

来了来了&#xff01;&#xff01;&#xff01; 开始之前扯点概念&#xff0c;知道DP好在哪里&#xff0c;以及看到它的发展趋势&#xff0c;才知道我们为什么有学习的必要。 DP的优势 DisplayPort&#xff08;DP&#xff09;协议作为一种专为数字音频和视频传输设计的高速串行…

Ant Design Vue 中 Tree 组件复选框修改样式

一、问题 最近需要实现一个业务需求&#xff0c;要修改勾选框中的颜色&#xff0c;默认勾选框的颜色是蓝色&#xff0c;现在需要变成绿色。 1、官网示例&#xff1a; 2、业务需求&#xff1a; 3、具体实现&#xff1a; HTML 部分代码 <template><div class"s…

【JavaWeb后端学习笔记】登录校验(JWT令牌技术、Interceptor拦截器、Filter过滤器)

登录校验 1、JWT令牌技术1.1 JWT令牌介绍1.2 Java代码生成与校验JWT令牌 2、Filter过滤器2.1 Filter过滤器的简单实现2.2 配置拦截路径2.3 Filter接口中的三个方法&#xff1a;2.4 Filter过滤器登录校验2.5 过滤器链 3、Interceptor拦截器3.1 拦截器(Interceptor)的简单实现3.2…

Linux系统下常用资源查看

一、查看CPU使用率 top 命令 top命令可以看到总体的系统运行状态和cpu的使用率 。 %us&#xff1a;表示用户空间程序的cpu使用率&#xff08;没有通过nice调度&#xff09; %sy&#xff1a;表示系统空间的cpu使用率&#xff0c;主要是内核程序。 %ni&#xff1a;表示用户空间且…

Flutter提示错误:无效的源发行版17

错误描述 Flutter从3.10.1 升级到3.19.4&#xff0c;在3.10.1的时候一切运行正常&#xff0c;但是当我将Flutter版本升级到3.19.4后&#xff0c;出现了下方的错误 FAILURE: Build failed with an exception.* What went wrong: Execution failed for task :device_info_plus:…

java+ssm+mysql学生信息管理系统

项目介绍&#xff1a; 使用javassmmysql开发的学生信息管理系统&#xff0c;系统包含超级管理员&#xff0c;系统管理员、教师、学生角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理&#xff08;可以新增管理员&#xff09;&#xff1b;专业管理&…

PCB设计规范

过孔设计 过孔盖油工艺&#xff08;也成为连塞带印&#xff09;&#xff1a;常规工艺、免费工艺&#xff0c;无特殊情况也建议使用此工艺。过孔大小建议直径在0.3mm-0.5mm之间。最省钱&#xff0c;效果最好。 非金属化槽孔 PCB制造商在加工非金属化槽孔时通常采用锣刀加工。最…

【C语言】42道大厂笔试题目(选择题)

本篇博客给大家带来的是一些大厂笔试题目&#xff0c;题目难度&#xff1a;简单&#xff0c;适合小白快速入手C语言部分的大厂笔试难度。 &#x1f41f;&#x1f41f;文章专栏&#xff1a;C语言 &#x1f680;&#x1f680;若有问题评论区下讨论&#xff0c;我会及时回答 ❤❤欢…

设置笔记本同时连接内外网

原理&#xff1a;通过笔记本和手机相连&#xff0c;实现双网卡功能能。笔记本连接内网wifi、同时手机端开启usb网络共享&#xff0c;笔记本就有了两个网&#xff0c;然配置那个访问外网&#xff0c;那个访问内网。 1.笔记本wifi连接内网wifi 2.手机端共享网络。 手机打开 -【…

JVM类加载三步解读: 双亲委派模型如何维护Java生态

欢迎浏览高耳机的博客 希望我们彼此都有更好的收获 感谢三连支持! &#x1f649;Java是面向对象编程&#xff0c;一切皆对象。这些对象是如何从一堆代码变成程序中的一部分&#xff1f;Java虚拟机&#xff08;JVM&#xff09;在这个过程中扮演了至关重要的角色。当你的代码通…

青海摇摇了3天,技术退步明显.......

最近快手上的青海摇招聘活动非常火热&#xff0c;我已经在思考是否备战张诗尧的秋招活动。开个玩笑正片开始&#xff1a; 先说一下自己的情况&#xff0c;大专生&#xff0c;20年通过校招进入杭州某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c…