Handle&Protocol

        初入UEFI,学习到了Protocol这一节,发现里面的内容很多,记下笔记供后期翻阅。本人水平有限,若有讲述不对的地方请及时指正,谢谢!!!

        参考书籍为:《UEFI编程与原理》、《UEFI编程实践》。

        本文将从两个方面分别是Handle和Protocol讲述,先讲述Handle,书中有一段很重要的话如下:

        EFI_HANDLE是指向某种对象的指针,UEFI用它来表示某个对象。UEFI扫描总线后,会为每个设备建立一个Controller对象,用于控制设备,所有该设备的驱动以Protocol的形式安装到这个Controller中,这个Controller对象就是一个EFI_HANDLE对象。当我们将一个.efi文件加载到内存中时,UEFI也会为改文件建立一个Image对象,这个Image对象也是一个EFI_HANDLE对象。在UEFI内部,EFI_HANDLE被理解为IHANDLE。上面这段话可以用结构图1和结构图2表示,这样更易看懂。

   图1 结构图1

图2 结构图2

        如上图2所示,EIF_HANDLE是一个VOID*类型的指针,指针指向某一个内存就是所谓的对象。根据源码分析,这个对象是图2中红色的部分,指向的是IHANLD,由于UEFI使用结构体的形式来实现面向对象的概念,因此IHANDLE *Handle相当于IHANDLE对象实例化的意思,即handle的实质也是IHANDLE结构体。那IHANDLE这个结构体到底是什么嘞?IHANDLE结构体为图3所示。

图3 IHANDLE结构体

        由图3所示,图中共有五个成员,其中第五个成员key为每一个handle的唯一标识,是查找、区分的标志。除此之外有两个LIST_ENTRY结构体成员,先看第一个LIST_ENTRY   AllHandles,LIST_ENTRY也是一个结构体,如图4所示。明显可以看出这个是个双向链表的结构,成员分别是指向前面的指针和后面的指针。

图4 LIST_ENTRY

       由于每一个IHANDLE结构体,都有这个LIST_ENTRY  ALLHandles成员,如果将所有的IHANDLE结构体通过其成员LIST_ENTRY    ALLHandles连接在一块,此时就形成了一个链表(以AllHandles为成员,IHandle为节点的链表),我自己将其命名为第一条链表。到此有一个问题:链表的初始化和插入的方式是什么样的?相应的问题由源码回答如图5所示,此为源码初始化的一种方式,可以等同于图6初始化,前后指针都指向头节点。 

图5 源码

图6 初始化

        插入方式的源代码如下图7所示。

图7 源代码

链表1:

        由上图7所示,这条链表其实是一个双向循环链表,每次来一个IHANDLE都会插入到头节点之后。此时有人会问,什么时候会有一个IHANDLE插入这个链表之中嘞?上面其实已经说了,例如每当.efi文件加载时候,UEFI会为这个文件创建一个EFI_HANDLE指向的对象。有人又会问,我们用这个链表可以干什么?目前不太清楚,但既然是链表,遍历肯定不可少,我们可以通过AllHandles遍历IHANDLE实例。(注意:使用        通过结构体实例的成员访问到实例的本身)。这条链表目前先研究到这里,后续如果有细节再添加进来。

链表2:

        上面讲述了图三中IHANDLE的LIST_ENTYR     AllHandles成员,接下来讲图3中的LIST_ENTYR  Protocols成员,根据图中的解释List  of  PROTOCOL_INTERFACE 's  for  this handle,表明Protocols为这个handle的PROTOCOL_INTERFACE链表,即多个PROTOCOL_INTERFACE结构体,可以通过其中某个成员进行连接形成链表,该链表的头节点为IHADNLE.Protocols,具体是哪一个成员,则需要分析PROTOCOL_INTERFACE。该结构体如下图8所示。

图8 PROTOCOL_INTERFACE

        根据图8中的第二个参数LIST_ENTRY  Link的注释,该成员连接在IHANDLE.Protocols链表上,这个成员就是刚才说的PROTOCOL_INTERFACE中充当节点的成员。

        因此这个就是第二条链表,向Handle->Protocols为头结点的链表中插入新的节点Prot->Link,调用的是一个与之前不同的函数InsertHeadList(在最后一个节点后面插入)

链表3:

        继续分析PROTOCOL_INTERFACE结构体,其中IHANDLE *Handle和 PROTOCOL_ENTRY *Protocol成员为两个指针,分别指向自己所在的IHANDE和指向自己所在的PROTOCOL_ENTRY结构体(这个结构体后面再讲),因此可以通过这两个成员使PROTOCOL_INTERFACE与IHANDLE和PROTCOL_ENTRY结构体产生联系。VOID   *Interface这个指针连接的是有效的Protocol实例,说明白点,就是我们自己定义的、可以调取使用的Protocol。到此图8 PROTOCOL_INTERFACE结构体中的单向指针分析完了,接下来还剩两个LIST_ENTRY类型的成员,分别是LIST_ENTY  ByProtocol和LIST_ENTRY   OpenList。

        先看LIST_ENTY  ByProtocol,代码注释中说明了这个成员函数是和LIST_ENTRY结构体的Protocols成员相连接的。这样我们就能够得到一个以PROTOCOL_ENTRY.Protocols为头结点PROTOCOL_INTERFACE.ByProtocol为节点的双向链表,这个是第三条链表。我们可以通过LIST_ENTY  ByProtocol来建立PROTOCOL_INTERFACE和PROTOCOL_ENTRY之间的关系。PROTOCOL_ENTRY结构体如下图9所示。

图9        

链表4:

        图8 PROTOCOL_INTERFACE还剩最后一个成员LIST_ENTRY   OpenList,根据注释 LIST_ENTRY OpenList连接的是OPEN_PROTOCOL_DATA结构体,该结构体如下图10所示。

图10

       形成的链表为: 头结点PROTOCOL_INTERFACE.OpenList,节点OPEN_PROTOCOL_DATA.Link,采用的是InsertTailList的插入方法。至此PROTOCOL_INTERFACE结构体已分析完。

链表5:

        我们在分析PROTOCOL_INTERFACE结构体成员的时候,中间引入了PROTOCOL_ENTRY,如上图9所示,为了便于观看,我们粘贴过来,PROTOCOL_ENTRY 如图10所示。

图10 PROTOCOL_ENTRY

        我们知道Protocol的唯一标识符为GUID,在PROTOCOL_ENTRY中的EFI_GUID ProtocolID即为GUID,所以Protocol一定包含这个结构体。        PROTOCOL_ENTRY结构体中有三个LIST_ENTRY类型的结构体成员,先看第一个AllEntries,根据注释我们知道PROTOCOL_ENTRY结构体中的AllEntries能够相互连接,形成一个环形的链表将PROTOCOL_ENTRY以某种方式连接起来,连接起来形成的链表的头节点为mProtocolDatabase。该链表和第一个链表类似,插入方式也是插入到头节点之后。PROTOCOL_ENTRY的LIST_ENTRY Protocols前面已经讲了,是连接了所有的PROTOCOL_INTERFACE,此处不再重复赘述。

链表6:     

        PROTOCOL_ENTRY还剩最后一个成员LIST_ENTRY  Notify,这个成员形成的链表是PROTOCOL_NOTIFY结构体,该结构体如下图11所示。

图11

        LIST_ENTRY Notify与PROTOCOL_NOTIFY的成员LIST_ENTRY Link会形成一个双向的链表,这个链表最重要的作用就是PROTOCOL_NOTIFY中的 EFI_GUID ProtocolID对应的protocol安装时,该链表上所有的Event都会触发。

总结:

        以上是目前接触的六条链表,由于刚接触,里面的内容需要不断完善,待日后学习到相应的地方,再补充细节。由于链表之间有某种连接关系,以及每个链表中有一些比较关键的成员,为了更好的理解上述内容,本人画了两张简易流程图供日后参考(基本上和上述内容一致),以及贴出一张在网上找到了链表关系图便于日后分析。分别如下图12、13、14所示。

图12 简易流程图1

图13 简易流程图2

图14 链表关系图

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值