手记

UEFI 原理与编程实战 - 深入理解 Protocol

欢迎关注全是干货的技术号 JavaEdge

1 UEFI 内核下的 Protocol

1.1 EFI_HANDLE

指向某种对象的指针,UEFI用其表示某个对象。

  • UefiBaseType.h
// 相关接口的集合.
typedef VOID                      *EFI_HANDLE;

UEFI 扫描总线后,为每个设备建立一个Controller对象,来控制该设备,
所有该设备的驱动以Protocol的形式安装到该Controller上,这个Controller就是一个EFI_HANDLE对象。

在UEFI内部,EFI_HANDLE被理解为IHANDLE,其结构如下:

  • edk2/MdeModulePkg/Core/Dxe/Hand/Handle.h
// IHANDLE -包含Protocol handle 链表
typedef struct {
  UINTN               Signature;
  // 所有IHandle组成的链表
  LIST_ENTRY          AllHandles;
  // List of PROTOCOL_INTERFACE's for this handle 该Handle下的Protocol链表
  LIST_ENTRY          Protocols;
  UINTN               LocateRequest;
  // The Handle Database Key value when this handle was last created or modified
  // 上次创建或修改此handle 时的Handle Database Key值
  UINT64              Key;
} IHANDLE;

在该结构体中,重要的为

1.2 LIST_ENTRY

  • edk2/MdePkg/Include/Base.h
// LIST_ENTRY 结构定义.
typedef struct _LIST_ENTRY LIST_ENTRY;

// _LIST_ENTRY 结构定义.
struct _LIST_ENTRY {
  LIST_ENTRY  *ForwardLink;
  LIST_ENTRY  *BackLink;
};

由此可见 IHANDLE 包含两个双向链表

  • 一条用于串联所有 IHANDLE 实例,因为串联的是两个 IHANDLE 结构体中 AllHandles 成员变量,因此会利用到 _CR
    宏主要利用成员在结构体中的偏移量得到结构体的基地址
    具体实现在./BaseTools/Source/C/Include/Common/BaseTypes.h
  • 另外一条用于串联该handle所有的 PROTOCOL_INTERFACE

1.3 PROTOCOL_INTERFACE

edk2/MdeModulePkg/Core/Dxe/Hand/Handle.h

// PROTOCOL_INTERFACE - 使用该结构跟踪安装在 handle 上的每个 protocol 
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_ENTRY的定义,在同文件内可以看到定义

// PROTOCOL_ENTRY - Each handler that supports this protocol is listed, along with a list of registered notifies.
// 每个不同的 protocol 在 protocol 数据库中都有1个 entry
// 列出了支持该 protocol 的每个处理程序以及已注册通知的链表
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的 GUID

GUID的三种形式
一:3a738b36-b9c5-4763-abbd-6cbd4b25f9ff
二:{ 0x36, 0x8b, 0x73, 0x3a, 0xc5, 0xb9, 0x63, 0x47, 0xab, 0xbd, 0x6c, 0xbd, 0x4b, 0x25, 0xf9, 0xff }
三:{ 0x368b733a, 0xc5b9, 0x630x47, { 0xab, 0xbd, 0x6c, 0xbd, 0x4b, 0x25, 0xf9, 0xff } }
生成GUID的网站
https://www.guidgen.com

1.4 小结

IHANDLE内的Protocol组织图

总体来说主要由三条链表将这些数据结构串在一起

  • 一条为所有Handle串成的链表Handle Database
  • 一条为Protocol串起的Protocol Database
  • 第三条为PROTOCOL_INTERFACE串起的链表
    如下图

参考

0人推荐
随时随地看视频
慕课网APP