1.UEFI中的Protocol引入了面向对象的思想:
--用struct来模拟class
--用函数指针(Protocol的成员变量)模拟成员函数,此种函数的第一个参数必须指向Protocol的指针,用来模拟this。
(通常,计算机中有很多的块设备,每个块设备都有一个EFI_BLOCK_IO_PROTOCOL的实例,This指针就是指向这个实例,用于告诉成员函数我们正在操作哪个设备。This指针是Protocol成员函数的一个重要特征。)
2.Protocol在UEFI内核中的表示:
使用Protocol之前,我们需要知道Protocol位于什么地方。首先,我们要来认识一下EFI_HANDLE
typedef VOID * EFI_HANDLE;
EFI_HANDLE是指向某种对象的指针,UEFI用它来指向某个对象。UEFI扫描总线后,会为总线上的每个设备创立一个Controller对象,用于控制设备,所有该设备的驱动以protocol的形式安装到这个Controller中,这个Controller就是一个EFI_HANDLE对象。当我们将一个.efi文件加载到内存中时,UEFI也会为该文件创建一个image对象。在UEFI内部,EFI_HANDLE被理解为IHANDLE,IHANDLE的数据结构代码如下所示:
typedef struct{
UINTN Signature;//表明Handle的类别
LIST_ENTRY AllHandles;//所有Handle组成的链表
LIST_ENTRY Protocols;//此Handle的Protocols链表
UINTN LocateRequest;
UINT64 Key;
}IHANDLE;
每个IHANDLE都有一个protocols链表(双向链表),存放属于自己的protocol。所有的IHANDLE通过AllHandles连接起来。
3.如何使用protocol
Boot Services提供了对Protocol进行操作的services,如OpenProtocol()、HandleProtocol()、LocateProtocol()三种服务用于找出指定的protocol:OpenProtocol()用于打开指定句柄上的Protocol;HandleProtocol()是OpenProtocol()的简化版;LocateProtocol()用于找出指定protocol在系统中的第一个实例。使用完Protocol后还要通过CloseProtocol()关闭打开的protocol,否则可能造成内存泄露,由于HandleProtocol和OpenProtocol没有指定AgentHandle,所以无法关闭,如果一定要关闭,需要调用OpenProtocolInformation()获得AgentHandle和ControllerHandle,然后关闭它。
除了打开和关闭protocol,有时候还有能找出支持某个Protocol的所有设备。例如要找出支持BlockIos的所有设备(即找出所有块设备),这时候就要使用LocateHandleBuffer()服务;如果想知道某个Protocol被哪些设备打开了,那么可以使用OpenProtocolInformation()服务;ProtocolPerHandle()用于获得指定设备所支持的所有Protocol。