UEFI中Handle和Protocol的关系

       Protocol的设计类似于C++中的类,只不过在UEFI中是用struct代替class,用函数指针模拟成员函数,并且函数指针的第一个参数必须是指向Protocol的指针——用来模拟this指针。这里只简单描述一下Protocol的概念,其他具体的不多说。

       而Handle和Protocol都是软件上的概念,个人认为把软件的概念和具体的硬件相结合更容易理解Handle与Protocol的关系。
那Handle怎么与具体的硬件相结合呢?这就需要了解EFI_HANDLE。

       EFI_HANDLE在EDKII代码中的定义是:typedef VOID *EFI_HANDLE

       UEFI扫描总线后,会为每个设备建立一个Controller,这个Controller就是一个EFI_HANDLE对象。当我们将一个.efi文件加载到内存中时,UEFI也会为该文件建立一个Image对象,这个Image对象也是一个EFI_HANDLE对象。在UEFI内部,EFI_HANDLE被理解为IHANDLE(以下把IHANDLE定义的简称为Handle,在EDKII源码中Handle的类型也是IHANDLE)。

       EDKII中IHANDLE的定义为:

/// IHANDLE - contains a list of protocol handles
///
typedef struct {
  UINTN               Signature;       //表明Handle的类别
  /// All handles list of IHANDLE
  LIST_ENTRY          AllHandles;      //所有IHANDLE组成的链表
  /// List of PROTOCOL_INTERFACE's for this handle
  LIST_ENTRY          Protocols;      //此Handel的列表,(是一个双向链表),链表的每一个成员指向PROTOCOL_INTERFACE结构体
  UINTN               LocateRequest;
  /// The Handle Database Key value when this handle was last created or modified
  UINT64              Key;
} IHANDLE;

       由第二个成员LIST_ENTRY AllHandles;可知,所有的Handle都有在一个链表中,由 LIST_ENTRY Protocols;可知,每一个Handle中的Protocol都在一个链表中。链表类型LIST_ENTRY的定义为:

struct _LIST_ENTRY {
  LIST_ENTRY  *ForwardLink;
  LIST_ENTRY  *BackLink;
};

       此链表是一个双向链表,链表中的每个成员是PROTOCOL_INTERFACE结构:

typedef struct {
  UINTN                       Signature;
  /// Link on IHANDLE.Protocols
  LIST_ENTRY                  Link;   
  /// Back pointer
  IHANDLE                     *Handle;  
  /// Link on PROTOCOL_ENTRY.Protocols
  LIST_ENTRY                  ByProtocol; 
  /// The protocol ID
  PROTOCOL_ENTRY              *Protocol;  
  /// The interface value
  VOID                        *Interface; 
  /// OPEN_PROTOCOL_DATA list
  LIST_ENTRY                  OpenList;       
  UINTN                       OpenListCount;

} PROTOCOL_INTERFACE;

       通过PROTOCOL_INTERFACE中的成员PROTOCOL_ENTRY *Protocol; 可以指向这个Protocol的实例,PROTOCOL_ENTRY的定义为:

/// PROTOCOL_ENTRY - each different protocol has 1 entry in the protocol
/// database.  Each handler that supports this protocol is listed, along
/// with a list of registered notifies.
///
typedef struct {
  UINTN               Signature;
  /// Link Entry inserted to mProtocolDatabase
  LIST_ENTRY          AllEntries;  
  /// ID of the protocol
  EFI_GUID            ProtocolID;  
  /// All protocol interfaces
  LIST_ENTRY          Protocols;     
  /// Registerd notification handlers
  LIST_ENTRY          Notify;                 
} PROTOCOL_ENTRY;

       而通过PROTOCOL_INTERFACE中的成员EFI_GUID ProtocolID;就可以通过接口调用Protocol的功能(OpenProtocol、HandleProtocol和LocateProtocol都需要GUID来找Protocol)。

       Handlel的链表和每个Handle中Protocol的链表关系可以看下图:
       下图展示了一部分的Handle数据库,除了handles和protocols以外,每个potocol还有一个对象的列表,这个列表用来跟踪哪些agents正在使用哪些protocols。
在这里插入图片描述
       纵向来看,Handle都连在一个链表中,横向来看,每个Handle下都挂了多个Protocol(用GUID来代表Protocol,有的Handle下可能只有一个Protocol)。这些Handle和Protocol组成了Handle Database,在UEFI初始化阶段,system firmware(系统固件),UEFI driver(UEFI驱动)和UEFI application(UEFI应用)创建Handle,并将一个或protocol附加到Handle中,Handle Database中的信息时全局的,可以被任何可执行的UEFI image访问。
       Handle也有不同的类型,如Agent Handle和Controller Handle等。Handle Database中的不同类型Handle如下图(所有的handle都存在于同一个handle数据库中,每个handle类型的区别由handle下面的protocol的类型决定):
在这里插入图片描述

       本文参考:
       《UEFI原理与编程》
       《Beyond_BIOS:Developing with the Unified Extensible Firmware Interface》2nd Edition

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值