如何理解UEFI中handle和protocol的概念

UEFI中到处都会出现Handle和Protocol这两个概念,这个对于理解UEFI的设计思路还是很重要的,但是翻遍了UEFI spec,并没有给出很清晰的概念。后来干脆去翻源码的定义,立马有种拨云见日的感觉。

 

基本上,protocol代表的是一种用定义好了的数据结构,每个protocol都有唯一的ID(128bit的GUID,也可以理解为protocl的名字),可以通过这个GUID去locate到相应的protocol。这样protocol的生产者和使用者之间就能够通过GUID建立起连接,使用者只要知道protocol的数据结构及相应的GUID就可以去locate并使用这个protocol。每个protocol包含两部分,即一个PROTOCOL_ENTRY和N个PROTOCOL_INTERFACE,这N个PROTOCOL_INTERFACE有点类似于C++中的类实例(如下图所示)。

 

handle的概念就有点虚了,经常会看到driver handle,device handle, image handle等等。可以将handle理解为一个逻辑的设备,这个逻辑设备将N个有关联的protocol interface组合到一起,方便于UEFI管理。一般如果我们说driver/device/image handle指的是这个handle是某个driver/device/image的一个抽象.


handle和protocol的关系如下,首先UEFI会用一个链表将所以的handle连接起来,一个handle下面可以挂N个protocol,同一个protocol可以install到多个handle上。如果在install protocol的时候没有指定handle,则会创建一个新的handle。


HandleProtocol的关系图如下所示


 

首先系统中有两个大的双向链表:

  1. gHandleList为表头的链表,链表中每个EntryIHANDLE结构体,将系统中所有的handle链接到一起;
  2. mProtocolDatabase为表头的链表,链表中每个EntryPROTOCOL_ENTRY结构体,用于将系统中所有的protocol链接到一起。

 

首先每个handle用一个IHANDLE结构体表示,IHANDLE中的Protocols指向一个双向链表(红色箭头表示),用于将所有install到该handle的所有protocol链接到一起,每一个installprotocol都由一个对应的PROTOCOL_INTERFACE结构体来表示。

其次,每个protocol由一个PROTOCOL_ENTRY来表示,一个protocol可能被install到多个handle中,所以每个HANDLE_ENTRY中的Protocols都由可能会由多个PROTOCOL_INTERFACE实例,并且这些PROTOCOL_INTERFACE实例也被链表链接起来(绿色箭头表示)。


Handle和Protocol的定义如下代码所示:

#define EFI_HANDLE_SIGNATURE            SIGNATURE_32('h','n','d','l')

///
/// IHANDLE - contains a list of protocol handles
///
typedef struct {
  UINTN               Signature;
  /// All handles list of IHANDLE
  LIST_ENTRY          AllHandles;
  /// List of PROTOCOL_INTERFACE's for this handle
  LIST_ENTRY          Protocols;      
  UINTN               LocateRequest;
  /// The Handle Database Key value when this handle was last created or modified
  UINT64              Key;
} IHANDLE;

#define ASSERT_IS_HANDLE(a)  ASSERT((a)->Signature == EFI_HANDLE_SIGNATURE)

#define PROTOCOL_ENTRY_SIGNATURE        SIGNATURE_32('p','r','t','e')

///
/// 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;


#define PROTOCOL_INTERFACE_SIGNATURE  SIGNATURE_32('p','i','f','c')

///
/// PROTOCOL_INTERFACE - each protocol installed on a handle is tracked
/// with a protocol interface structure
///
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;

总的来说,Handle和protocol的概念大大提升了UEFI设计的模块化和扩展性,因为handle和protocol可以被动态地加载和删除,每个UEFI模块只需要去locate它所需要的protocol,并且可以install相应的protocol让其他模块使用,这个跟很多软件的模块化设计思想很类似。


猜你喜欢

转载自blog.csdn.net/lindahui2008/article/details/78796550