UEFI中的Protocol

一、Protocol是什么

Protocol是服务器端和客户端之间的一种约定,在软件编程上称为接口,服务器端和客户端通过这个约定信息的互通。服务器端和客户端在UEFI中都是可执行的二进制文件,为了实现这些二进制文件之间的互通,C/S双方共同作出的让步,使用Protocol进行双方的交互。

二、Protocol是干什么的,为什么要有Protocol

UEFI的中文含义是“可扩展固件接口”,所谓可扩展的含义就是可以在系统完成后(编译为binary)之后,再次为系统增加新的功能,而不用重新rebuild整个系统。为了支持不同二进制组件运行时相互通信,不同组件可以相互调用之间的功能,同时各个组件相互之间调用时的统一编程接口以便方便组件厂商对于组件的开发等要求。Protocol用以实现这些功能的同时满足服务器端和客户端之间的通信。而通信至少要具备以下几种功能:

(1)互操作。A组件自由可以调用B组件实现的函数。反过来也一样。

(2)数据传递。双方可以通过某种方法(sharedmemory, pipes and etc)互相交换数据。

(3)可探测。某组件必须具备探测另一个组件是否存在的能力。

(4)组件的开发必须是独立的。开发A组件不需要B组件的源代码,反之亦然。

三、Protocol的组成

Protocol其实就是一个大的结构类型,它包含有很多数据信息。最主要的是GUID,每一个Protocol都有一个定义好的、唯一的标识符,这个标识符用GUID来表达。这样程序员可以方便的通过指明不同的GUID来得到不同的Protocol。其次是一个指向GUID的全局指针变量,比如EFI_BLOCK_IO_PROTOCOL,就有一个gEfiBlockIoProtocolGuid的全局指针,他是EFI_GUID *结构的。这样做事实上完全是为了方便,他的变量名的命名规则是统一的,即g + Efi + Protocol 名称 + ProtocolGuid。这样一来,程序员就不需记住相应GUID具体的值,而只在需要GUID作为参数的时候,使用这个全局变量就行了。如果要在应用程序或者驱动中使用这个GUID(如gEfiBlockIoProtocolGuid),那么必须要在.inf文件的[Protocols]中什么以便预处理时将其包含在生成的AutoGen.c中供全局使用。以下是以块设备的Protocol为例描述protocol的数据结构中的成员变量,通过这个Protocol可以控制块设备。

struct _EFI_BLOCK_IO_PROTOCOL {
 UINT64              Revision;  //必须保证向后兼容的Protocol版本号,若木有向后兼容的话就必须给未来的版本号定义一个新的GUID,相当于定义了一个新的Protocol
  EFI_BLOCK_IO_MEDIA  *Media; //指针指向这个设备
  EFI_BLOCK_RESET     Reset;  //重置复位信号
  EFI_BLOCK_READ      ReadBlocks;  //读Protocol服务
  EFI_BLOCK_WRITE     WriteBlocks;  //写Protocol服务
  EFI_BLOCK_FLUSH     FlushBlocks;  //清除缓存服务
};
extern EFI_GUID gEfiBlockIoProtocolGuid;  //导出该Protocol

四、Protocol在内核中的表示

了解Protocol在什么位置之前我们要先了解下EFI_HANDLE。

typedef    VOID      *EFI_HANDLE;  //相关接口的一个集合

这个EFI_HANDLE是指向某种对象的指针,UEFI用其来表示某个对象的。UEFI通过扫描总线,为每一个设备建立一个Controller对象,用于控制各个设备,所有该设备的驱动都是以Protocol的形式安装在这个Controller中的,这个Controller就是一个EFI_HANDLE指针指向的对象。 当我们将一个.efi文件加载到内存中,UEFI也会为该文件建立一个Image对象,这个Image对象也是一个EFI_HANDLE对象。 在UEFI内部,EFI_HANDLE被理解为IHANDLE,这个IHANDLE包含了Protocols的链表,存放属于自己的Protocol,然后ALLHANDLE将所有的IHANDLE连接起来。

五、Protocol服务的使用

要使用Protocol服务,首先要根据GUID找到Protocol对象,Boot Service中提供了几种Protocol服务,如下表所示:

表1 Boot Service中提供的Protocol服务

OpenProtocol

打开Protocol

HandleProtocol

打开Protocol,PenProtocol的简化版本

LocateProtocol

找出系统中指定Protocol的第一个实例

LocateHandleBuffer

找出支持指定Protocol的左右Handle。系统负责分配内存,调用者负责释放内存

LocateHandle

找出支持指定Protocol的左右Handle,调用者负责分配和释放内存

OpenProtocolInformation

返回指定Protocol的打开信息

ProtocolsPerHandle

找出指定Handle上安装的所有Protocol

CloseProtocol

关闭Protocol

介绍完了上述几种Protocol服务,接下来我们了解一下使用Protocol服务的几个操作步骤,使用protocol服务的一般有以下三步:

第一步:通过gBS->OpenProtocol(或者HandleProtocol、LocateProtocol)找出Protocol的对象。

第二步:使用这个Protocol提供的服务。

第三步:通过gBS->CloseProtocol关闭打开的Protocol。

1、OpenProtocol服务

OpenProtocol用于查询指定的Handle中是否支持指定的Protocol,如果支持的话就打开,不支持的话就返回错误的代码。OpenProtocol服务的函数原型如下所示:

EFI_STATUS (EFIAPI*EFI_OPEN_PROTOCOL)(

IN  EFI_HANDLE       Handle,  //指定的Handle,将查询和打开此Handle中安装的Protocol

IN  EFI_GUID           *Protocol,  //这个是要打开的Protocol对象(指向Protocol GUID)

OUT VOID               **Interface, OPTIONAL,  //返回打开的Protocol对象

IN  EFI_HANDLE       AgentHandle,  //打开此Protocol的Image

IN  EFI_HANDLE       ControllerHandle,  //使用此Protocol的控制器

IN  UINT32              Attributes //打开Protocol的方式

);

Handle是Protocol的提供者,Handle是Protocol的提供者,如果Handle的Protocols链表中有该Potocol,Protocol对象的指针写到*Interface,并返回EFI_SUCCESS;否则 返回EFI_UNSUPPORTED。
    如果在驱动中调用OpenProtocol(),就是请求使用Protocol的控制器ControllerHandle。AgentHandle是拥有负责驱动安装和卸载的EFI_DRIVER_BINDING_PROTOCOL对象的Handle。如果调用OpenProtocol的是应用程序,那么AgentHandle是该应用对应的Handle,也就main函数的第一个参数,ControllerHandle此时可以忽略。

对于Attributes可以取以下5种值,即有五种打开Protocol的方式:

#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  //若Protocol已经打开,则再次打开就会失败

2、HandleProtocol服务

这也是一个打开Protocol的服务,只是这是一个简化版本的OpenProtocol,它只含有三个参数,木有提供AgentHandle、ControllerHandle和Attributes,在调用的时候AgentHandle使用gDxeCoreImageHandle,ControllerHandle使用NULL值,Attribute使用EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL。以下是HandleProtocol的服务的函数原型:

EFI_STATUS EFIAPI CoreHandleProtocol (
  IN EFI_HANDLE       UserHandle,//查询该Handle是否支持Protocol
  IN EFI_GUID         *Protocol,  //带查询的Protocol
  OUT VOID            **Interface  //返回带查询的Protocol
  )

3、LocateProtocol服务

这个服务是从内核中找出指定Protocol的第一个实例,它会按顺序搜索HANDLE链表,返回找到的第一个该Protocol的实例。以下是LocateProtocol的服务的函数原型:

Typedef EFI_STATUS LocateProtocol (

IN EFI_GUID *Protocol,  //带查询的Protocol
IN VOID       *Registration OPTIONAL, //可选参数,从RegisterProtocolNotify中获得的Key
OUT VOID     **Interface  //返回系统中第一个匹配到的Protocol实例
);

4、LocateHandleBuffer服务

这个服务的功能是找出支持某个Protocol的所有设备。该服务的函数原型如下:

typedef  EFI_STATUS LocateHandleBuffer (
IN EFI_LOCATE_SEARCH_TYPE SearchType, //查找方法
IN EFI_GUID                        *Protocol OPTIONAL,  //指定的Protocol
IN VOID *SearchKey OPTIONAL, //PROTOCOL_NOTIFY类型
IN OUT UINTN                      *NoHandles,  //返回找到的Handle数量
OUT EFI_HANDLE                  **Buffer  //分配Handle数组并返回
);

上述的SearchType有三种:AllHandles(查找系统中所有HANDLE), ByRegisterNotify(从RegisterProtocolNotify中找出匹配SearchKey的Handle), ByProtocol(从系统Handle数据库中查找支持指定Protocol的HANDLE)。NoHandles是找到的HANDLE的数量, Buffer数组由UEFI复杂分配,由用户负责释放。

5、LocateHandle服务

这个服务的功能是找出支持某个Protocol的所有设备,它的作用于上述的LocateHandleBuffer提供的服务是一样的,两者之间最大的区别在于LocateHandle需有调用者负责管理Buffer数组占用的内存。该服务的函数原型如下:

typedef  EFI_STATUS LocateHandleBuffer (
IN EFI_LOCATE_SEARCH_TYPE SearchType, //查找方法
IN EFI_GUID                        *Protocol OPTIONAL,  //指定的Protocol
IN VOID *SearchKey OPTIONAL, //PROTOCOL_NOTIFY类型
IN OUT UINTN                      *Buffersize, //返回找到的Handle的Buffer大小
OUT EFI_HANDLE                  **Buffer  //返回找到的Handle
);

6、其他使用Protocol的服务

(1)、ProtocolsPerHandle服务

这个服务是用于获得指定设备所支持的所有Protocol。这些Protocol的GUID通过ProtocolBuffer返回给调用者,UEFI负责分配内存给ProtocolBuffer,调用者负责释放该内存。其函数原型如下:

Typedef EFI_STATUS ProtocolsPerHandle (
IN EFI_HANDLE Handle,  //找出这个Handle上所有的Protocol
OUT EFI_GUID  ***ProtocolBuffer,  //返回Protocol GUID的数组
OUT UINTN      *ProtocolBufferCount  //返回Protocol的数目
);

(2)、OpenProtocolInformation服务

这个服务用于获得指定设备上指定Protocol的打开信息,其函数原型如下:

Typedef  EFI_STATUS(EFIAPI *EFI_OPEN_PROTOCOL_INFORMATION) (
IN EFI_HANDLE Handle,  //设备句柄
IN EFI_GUID    *Protocol,  //带查询的protocol
OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer,  //打开信息通过此数组返回
OUT UINTN     *EntryCount //EntryBuffer数组元素个数
);

7、Close Protocol服务

这个服务的作用是关闭打开的Protocol。通过HandleProtocol和LocateHandle打开的Protocol因为没有指定AgentHandle,所以无法关闭。若一定要关闭,则要调用OpenProtocolInformation获得AgentHandle和ControllerHandle,然后才能进行关闭。它的函数原型如下:

Typedef  EFI_STATUS(EFIAPI *EFI_CLOSE_PROTOCOL) (
IN EFI_HANDLE Handle,  //设备句柄
IN EFI_GUID *Protocol,  //这个是要关闭的Protocol对象
IN EFI_HANDLE AgentHandle,  //关闭此Protocol的Image
IN EFI_HANDLE ControllerHandle //使用此protocol的控制器
);

UEFI中的Protocol浅谈相关推荐

  1. mysql innodb4大特征_MYSQL中InnoDB特性浅谈

    许久没有更新博客,上周末放假把网易大牛姜sir的著作MYSQL技术内幕InnoDB存储引擎又翻阅了一番,对当前工作的InnoDB特性有了一些新的认识,下面谈谈自己的读后感. 1. InnoDB的体系架 ...

  2. 计算机在小学教育教学中的优劣,浅谈计算机教学在小学教育中的作用

    浅谈计算机教学在小学教育中的作用 浅谈计算机教学在小学教育中的作用 随着科技日新月异的发展,现代教育理念的改革.深化,对国民教育,特别是基础教育提出了更明确的要求,教育的根本任务就是使学习者学会如何学 ...

  3. java执行jar中的main_浅谈java 执行jar包中的main方法

    浅谈java 执行jar包中的main方法 通过 OneJar 或 Maven 打包后 jar 文件,用命令: java -jar ****.jar 执行后总是运行指定的主方法,如果 jar 中有多个 ...

  4. linux中sh+$0,浅谈linux中shell变量$#,$@,$0,$1,$2的含义解释

    摘抄自:ABS_GUIDE 下载地址:http://www.tldp.org/LDP/abs/abs-guide.pdf linux中shell变量$#,$@,$0,$1,$2的含义解释: 变量说明: ...

  5. 计算机基础中怎么评价,浅谈职校计算机基础教学中的教学评价

    浅谈职校计算机基础教学中的教学评价 在我们具体实施任务驱动法的教学过程中,教学评价是非常重要的环节.教学评价是计算机课 (本文共2页) 阅读全文>> 随着时代的发展,人们对高等教育发展的关 ...

  6. 计算机在财务核算中的应用,浅谈计算机在财务核算和财务管理工作中的辅助应用...

    浅谈计算机在财务核算和财务管理工作中的辅助应用 计算机在财务管理中的应用日益广泛,已成为企业财务管理的必要手段.计算机的应用改善了企业财务管理环境,提高了财 (本文共1页) 阅读全文>> ...

  7. 工作中应用计算机,浅谈计算机在我国计工作中的应用与发展.doc

    浅谈计算机在我国计工作中的应用与发展 <计算机的过去现在与未来>课程论文 浅谈计算机在我国会计工作中的 应用与发展 姓名学号学院会计学院日期2010-10-30 评分页 项目权重实际分数选 ...

  8. 任务驱动在计算机教学中的应用,浅谈任务驱动法在《计算机应用基础》教学中的应用_优秀论文...

    <浅谈任务驱动法在<计算机应用基础>教学中的应用_优秀论文>由会员分享,可在线阅读,更多相关<浅谈任务驱动法在<计算机应用基础>教学中的应用_优秀论文(8页珍 ...

  9. 计算机网络环境中学科教学,浅谈基于计算机网络环境下的农村小学的科学学科教育...

    浅谈基于计算机网络环境下的农村小学的科学学科教育 [内容摘要] <国家中长期教育改革和发展规划纲要(2010-2020年)>明确提出:加快教育信息化进程.重点加强农村学校信息基础建设,缩小 ...

最新文章

  1. c语言课程设计的摘要,投票程序设计-C语言课程设计摘要.doc
  2. 《Swift编程语言教程》中文翻译及读书笔记page21
  3. PyQt5 技术篇-QSpinBox选值框值改变触发事件实例演示,获取QSpinBox组件的值,选值框的边界值设置方法
  4. 【DIY】可能是最实用最便宜的 arduino 温湿度计方案,200615整合家用声控温湿度计完整方案...
  5. Hadoop RPC protocol description--转
  6. spring security 核心过滤器
  7. JVM-运行时数据区
  8. 打印并输出 log/日志到文件(C++)
  9. {ubuntu}不能挂载windows
  10. qq音乐的歌词接口中例如#58,#46的特殊符号编码使用js进行转义
  11. PCB制作仿真、自制51板测试及性能改进
  12. SpringBoot集成微信支付(二维码支付)
  13. Springboot 整合Rabbit MQ
  14. PMP-计算题汇总(PV、EV、AC、BAC、EAC、ETC、)
  15. Composure获取子层级图像:使用变换通道
  16. 免费天气查询工具类源码,开箱即用,根据中国气象局API编写。高效稳定
  17. Pb数字变成英文字母金额
  18. Vue.js学习笔记—shop-bus:实战:利用计算属性、指令等知识开发购物车
  19. QT6在线安装下载速度慢的解决办法,QT6,QT5.15.1,QT5.15.0及旧版本都支持
  20. tomcat--catalina

热门文章

  1. onRequestPermissionsResult 请求权限结果 (中文翻译小组)
  2. 关于MediaCoder使用过程问题整理
  3. 行政执法“三项制度”不用愁,您的城市“大管家”已上线
  4. error LNK2005: int dir (?dir@@3HA) already defined in GameStart.obj
  5. MySQL——触发器的创建和使用总结
  6. java读写orc文件_java读取hive的orc文件
  7. string.h函数库详解
  8. 车载GPS导航错误原因解析
  9. 贴近司机,感知生活:智能语音助手在滴滴车主端的设计与实践
  10. 只有一种人不会成为直销难民