UEFI开发探索42 – Protocol的使用1
(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365)
虽然一直使用各种Protocol来实现需要的程序功能,但对其背后的原理、实现方法,一直都比较模糊。我奉行的是“先用再说”的实用主义,正好周末有点闲暇,探究一下对Protocol理解模糊的地方。
图1 Protocol的构成
如图为Protocol的结构图,摘自于UEFI Spec 2.8 page 45。
我想弄清楚的问题如下:
1) 如何使用Protocol服务?
2) Protocol这种机制在UEFI中是如何实现的?
3) 如何实现一个Protocol?
1 函数学习
与Protocol处理有关的函数,在Spec中给出了列表:
图2 相关的函数
如果只是使用Protocol,上述的很多函数都不需要关注。简单描述下需要用到的几个函数:
1-1 OpenProtocol()
typedef EFI_STATUS (EFIAPI *EFI_OPEN_PROTOCOL) (
IN EFI_HANDLE Handle, //指定要打开此Handle安装的Protocol接口
IN EFI_GUID *Protocol, //要打开的Protocol(指向该Protocol GUID的指针)
OUT VOID **Interface OPTIONAL, //返回打开的Protocol对象,如果没有则返回NULL
IN EFI_HANDLE AgentHandle, //打开此Protocol的Image(对UEFI Application)
IN EFI_HANDLE ControllerHandle, //如果打开的Protocol是符合UEFI Driver Model的driver,则
此参数为控制Protocol接口的控制器,否则为可选的,并且可能为NULL
IN UINT32 Attributes //打开Protocol的参数
);
函数描述:
上述的几个参数,Handle是UEFI中设备的对象,它是Protocol的提供者。如果Handle的Protocol链表中有该Protocol,则Protocol对象的指针将写到*Interface中(注意,Interface是个指向指针的指针)。
在驱动中调用OpenProtocol(),则ControllerHandle是拥有该驱动的控制器,即请求使用这个Protocol的控制器; AgentHandle是拥有该EFI_DRIVER_BINGDING_PROTOCOL对象的Handle。如果打开的是应用程序(UEFI Application),则AgentHandle是该程序的Handle,即UefiMain函数的第一个参数,ControllerHandle可以忽略。
该函数如果返回错误,有很多种可能性。具体可以参考Spec(UEFI spec 2.8 page 187)。
Attributes有6个值可以使用:
#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001
#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002
#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004
#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008
#define EFI_OPEN_PROTOCOL_BY_DRIVER 0x00000010
#define EFI_OPEN_PROTOCOL_EXCLUSIVE 0x00000020
可根据实际情况自由选择上述参数。
1-2 HandleProtocol()
typedef EFI_STATUS (EFIAPI *EFI_HANDLE_PROTOCOL) (
IN EFI_HANDLE Handle, //需要查询的Handle,看是否支持指定的Protocol
IN EFI_GUID *Protocol, //发布的唯一Protocol标志,也即指向有效Protocol GUID的指针
OUT VOID **Interface //返回待查询的Protocol
);
函数描述:
它是OpenProtocol()的简化版,不需要指定AgentHandle、ControllerHandle和Attributes的值(OpenProtocol()中的三个参数)。实际上,在函数内部中还是使用了OpenProtocol(),AgentHandle为gDxeCoreImageHandle,ControllerHandle使用NULL值,Attributes则使用EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL。
1-3 LocateHandleBuffer()
typedef EFI_STATUS (EFIAPI *EFI_LOCATE_HANDLE_BUFFER) (
IN EFI_LOCATE_SEARCH_TYPE SearchType, //指定哪种handle返回,即设定查找方式
IN EFI_GUID *Protocol OPTIONAL, //指定的Protocol(GUID),此参数只有在SearchType为
ByProtocol时才有效
IN VOID *SearchKey OPTIONAL, //依SearchType不同,提供搜索的关键字
IN OUT UINTN *NoHandles, //返回找到的Handle数量
OUT EFI_HANDLE **Buffer //分配Handle数组并返回
);
函数描述:
此函数返回一个或多个Handle,以匹配SeatchType中规定的请求。参数Buffer所需要的内存,由函数使用EFI_BOOT_SERVICES.AllocatePool()分配,使用完后,调用者必须调用FreePool()将其释放。
SearchType有三种类型:
AllHandles: 参数Protocol和SearchKey会被忽略,返回系统中的所有Handle;
ByRegisterNotify: 从RegisterProcotolNotify中找出匹配SearchKey的Handle,Protocol参数会被忽略;
ByProtocol: 从系统Handle数据库中找出支持指定Protocol的Handle,SearchKey参数会被忽略。
1-4 LocateProcotrol()
typedef EFI_STATUS (EFIAPI *EFI_LOCATE_PROTOCOL) (
IN EFI_GUID *Protocol, //待查询的Protocol
IN VOID *Registration OPTIONAL, //可选参数,从RegisterPtotocolNotify()获得注册Key
OUT VOID **Interface //返回系统中第一个匹配到的Protocol接口
);
函数描述:
此函数找到第一个支持Protocol的设备Handle,并返回其Protocol接口(Protocol Interface)。调用时不用指定Handle,相比较OpenProtocol()和HandleProtocol(),更为简便。
1-5 OpenProtocolInformation()
typedef EFI_STATUS (EFIAPI *EFI_OPEN_PROTOCOL_INFORMATION) (
IN EFI_HANDLE Handle, //已经查询到的Protocol的设备句柄
IN EFI_GUID *Protocol, //待查询的Protocol(GUID)
OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer, //查询到的信息从此参数返
回
OUT UINTN *EntryCount //EntryBuffer数组元素个数
);
函数描述:
此函数用于获得指定设备上指定Protocol的打开信息。它会为EntryBuffer分配内存,并将返回的信息存入其中,内存的释放由调用者完成。EntryBuffer的数据结构如下:
typedef struct {
EFI_HANDLE AgentHandle;
EFI_HANDLE ControllerHandle;
UINT32 Attributes;
UINT32 OpenCount;
} EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
返回的信息包括AgentHandle、ControllerHandle、打开的属性和打开个数。很多时候,这个函数获取的信息用来关闭打开的Protocol。
1-6 CloseProtocol()
typedef EFI_STATUS (EFIAPI *EFI_CLOSE_PROTOCOL) (
IN EFI_HANDLE Handle, //之前已经打开的Protocol接口的设备句柄,准备关闭
IN EFI_GUID *Protocol, //发布的唯一Protocol标志,也即指向有效Protocol GUID的指针
IN EFI_HANDLE AgentHandle, //打开此Protocol的Image(对UEFI Application)
IN EFI_HANDLE ControllerHandle, //如果打开的Protocol是符合UEFI Driver Model的driver,则
此参数为控制Protocol接口的控制器,否则为可选的,并且可能为NULL
);
函数描述:
Protocol使用完毕后要通过此函数来关闭。通过HandleProtocol()和LocateProtocol()打开的Protocol没有指定AgentHandle,没法直接关闭。需要调用OpenProtocolInformation()获得AgentHandle和ControllerHandle,然后再关闭。
其他的一些函数不一一列举了,需要的时候再去读Spec,可在Spec 7.3 Protocol Handler Services中找到相应的内容。
2 使用Protocol
为了熟悉Protocol的使用,写了一个小程序,用来判断Protocol是否存在。
实际上,在使用各种Protocol的过程中,其中最重要的一点,就是UEFI下要提供相应的支持。如同之前在Legacy BIOS下的开发一样,比如鼠标,如果BIOS对鼠标的中断不支持,那希望在自己的代码中支持鼠标,工作量太大了。
为了方便显示,我把之前编写的汉字显示代码(探索系列博客18)移植到了UefiMain为入口的代码中。期间也遇到点小问题,在系列博客相关的问题集中也描述过,这里不再赘述。
代码比较简单。实际上,读过上面函数的说明,代码也就不难编写了。
我主要的目的,对传入的Protocol GUID进行定位,看系统中是否存在相应的Protocol,以及相关的Handle的数目。
具体来说,以串口为例,也就是找SerialProtocol是否存在,以及存在多少个串口。实际代码都在本章例子TryProtocol.c的函数ListProtocolMsg()中,如下:
图3 Protocol信息枚举
另外,在平常的使用中,我处理Protocol的代码都在Common.c中。需要注意的是,代码中的一些细节还没有处理好,比如内存的释放、Protocol使用之后的关闭等。
商用化的时候再处理吧。
3 演示
我用上面的函数来检查串口和随机数生成器的Protocol,编译之后,显示如下:
图4 程序演示
在TianCore的模拟环境中,有两个串口、没有提供随机数生成器的Protocol,一如测试结果所示。
对于其他函数的使用,网上也有大量的例子可供参考,我也没精力一个个试验了。准备进入下一个问题,如何生成Protocol了。
Gitee地址:https://gitee.com/luobing4365/uefi-exolorer
项目代码位于:/FF RobinPkg/ RobinPkg /Applications/ TryProtocol 下
UEFI开发探索42 – Protocol的使用1相关推荐
- UEFI开发探索97 – EDK2模拟器搭建网络环境
(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365) EDK2模拟器搭建网络环境 1 搭建EDK2开发环境 1)工具安装 2)下载代码库 3)更新子模 ...
- UEFI开发探索99 – UEFI Shell下截屏工具
(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365) UEFI Shell下截屏工具 1 PrintScreenLogger的代码结构 1)Print ...
- UEFI开发探索QA – 问题辑录(持续更新)
最近正在尝试在Unbutu16上搭建开发和调试环境,其中过程一言难尽,到现在也没完成到符合我要求的程度. 正是因为遇到障碍,我今天早上回到Win10+UDK2018的环境下,想重新编译下AppPkg, ...
- UEFI开发探索95 – 弹跳小游戏
(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365) UEFI下的弹跳小游戏 1 Bounce游戏 1.1 游戏架构 1.2 移植和编写代码 1)编写 ...
- UEFI开发探索85- YIE002USB开发板(08 制作HID设备)
(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365) YIE002USB开发板之制作HID设备-编程 1 YIE002-STM32的USB编程 2 调 ...
- UEFI开发探索94 – 迷宫小游戏
(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365) UEFI下的迷宫小游戏 1 Maze程序结构分析 1)定义全局变量 2)设置迷宫 3) 游戏控制 ...
- UEFI开发探索100 – 《UEFI编程实践》发布啦
(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365) <UEFI编程实践>发布 1 内容简介 第一部分 UEFI环境搭建及UEFI应用构建 ...
- UEFI开发探索02 – 环境搭建1
(请保留->作者:罗冰 ) 开发初期的目的就是做出可以在pci rom上跑的Oprom,当然是在uefi bios下.我的计划大致如下: 1 搭建完整的编译环境,了解使用哪些库进行编译: 2 我 ...
- UEFI开发探索81- YIE002USB开发板(04 制作HID设备)
(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365) YIE002USB开发板之制作HID设备-USB系统概述 1 USB规范简介 2 软件工程师眼中 ...
- UEFI开发探索74- YIE002USB开发板(03 Windows编程)
(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365) YIE002USB开发板之Windows编程 1 添加库文件 2 枚举HID设备 2.1 Set ...
最新文章
- 博问问题内容页面的前端优化
- SAP SD基础知识之凭证流(Document Flow)
- python中change是什么意思_Change是什么意思?
- 极客Python进阶训练学习手册
- 云计算时代,数据中心架构三层到大二层的演变
- 服务器维修天长,台达精密空调服务天长市供电局
- java ui自动化测试脚本,如何用Airtest编写UI自动化脚本(示例代码)
- Verilog HDL常用循环语句类型
- python爬虫ppt_完全零基础 轻松学Python:数据类型:数字类型、空类型、布尔类型...
- azure db 设置时区_在Azure Cosmos DB中应用字段运算符和对象
- Winsock传输数据
- 现代通信原理9.2:数字基带传输系统模型
- Webstorm全版本汉化包
- 外汇会计-概念-升水(Premium)
- typora 浏览器预览_Gitbook+Typora创建技术文档
- 如何通俗易懂地讲解牛顿迭代法?
- 怎么调整图片dpi大小?如何修改分辨率?
- 排球分组循环交叉编排_请问一下排球是怎么样编排的啊
- 概率算法-均匀分布产生正态分布
- 计算机网络和因特网大二暑假
热门文章
- 驻点(稳定点,临界点,要求平滑) 极值点 拐点 保号性及证明
- 用友软件计算机时间格式,如何正确设置系统日期格式?_速达软件_用友,速达,管家婆,微软,金蝶,方正,博世通,数据博士,进销存,财务软件-飞鸿软件帮助中心 -...
- Scrapy--下载器中间件(Downloader Middleware)
- 行星月球科学探索成绩斐然 桌面实验或可理解黑洞性质
- 可汗学院公开课:统计学笔记——中心极限定理、置信区间
- PHP从入门到接到外包合同,再到放弃
- 【EXLIBRIS】猝不及史成
- vue+element 下载or批量下载.mp3文件
- 【Nodejs】使用request批量下载MP3,文件数量内容都没问题
- Mstar的Monitor方案OSD 菜单制作(三)——添加字符串文字