一、Handle
Handle Database是由Handle和Protocol组成。Handle(句柄)是一个或多个协议的集合,Protocol(协议)是由GUID命名的数据结构。
在平台初始化过程中,系统固件、UEFI兼容驱动程序和UEFI应用程序创建句柄,并将一个或多个协议附加到句柄上。
句柄数据库是UEFI句柄的列表,是维护基于UEFI固件的对象的中央存储库。每个由唯一句柄号标识的UEFI句柄由系统固件维护。句柄号为句柄数据库中的条目提供数据库“键”。句柄数据库中的每个条目都是一个或多个协议的集合。由GUID命名的协议类型附加到UEFI句柄并确定句柄类型。
UEFI句柄可以表示以下组件:
1) 可执行映像(如UEFI驱动程序和UEFI应用程序)
2) 设备(如网络控制器和硬盘分区)
3) 作为驱动程序访问的UEFI服务(如EFI解压缩和EBC解释器)
如上图所示,只有一个Handle Database,所有的Handle 都在其中。值得注意的是Handle database并不区分Hanble的类型。Handle是由相关联的Protocol类型区分的。
使用协议的GUID名称在句柄数据库中注册协议服务,通过使用与协议关联的GUID名称在句柄数据库中查找协议来发现协议服务,以执行查找操作。
二、Protocol
2.1 Protocold的概念
UEFI的可扩展性很大程度上是围绕Protocol建立的。Protocol能够在独立的模块(包括驱动)之间进行通信。
驱动程序创建由两部分组成的protocol。Protocol的主体是一种C风格的数据结构,称为“协议接口结构”,简称为“接口”。接口通常包含一组相关的函数指针和数据结构。每个协议都有一个GUID,GUID作为协议名称,同样可以指示协议的数据结构。但是GUID不是数据结构的一部分。
下图是一个Protocol示例,包含两个函数和一个数据
协议被收集到一个数据库中,数据库将协议分为很多组,每组称为作为一个Handle,Handle也可以看成组的数据类型。句柄是动态分配的,即Handle不是启动时预先分配好的,而是需要的时候由UEFI固件动态创建的。每个句柄中不能有两个相同的GUID的Protocol。
2.2 Protocol的产生与消耗
Protocol用于模块之间的通信。为了建立这种通信吗,其中一个模块需要produce Protocol,而另外一个模块需要consume Protocol。
使用Protocol一般分为三个步骤:
1、通过启动服务找到protocol实例
2、使用这个protocol提供的服务
3、关闭打开的protocol
常用过的Protocol接口函数如下所示:
一般来说,生产者需要利用InstallProtocolInterface()或InstallMutipleProtocolInterface()在设备句柄上安装protocol接口,如果没有这个句柄,将创建这个句柄并添加到系统句柄列表中。InstallMutipleProtocolInterface()会执行更多的检查工作。调用者需要利用LocateProcotol\HandleProtocol\OpenProtocol找到协议实例。但是三者的使用是由区别的。
LocateProcotol():返回第一个与Protocol匹配的Protocol接口的指针,这个函数会查找第一个支持Protocol的设备句柄,并返回该协议的指针。
typedef
EFI_STATUS
(EFIAPI *EFI_LOCATE_PROTOCOL)(
IN EFI_GUID *Protocol, //协议的GUID
IN VOID *Registration OPTIONAL, //RegisterProtocolNotify()返回的注册码
OUT VOID **Interface //On return, a pointer to the first interface that matches Protocol and Registration.输出参数,指向第一个与协议匹配的protocol接口,如果接口没有实例,接口为NULL
);
HandleProtocol():查询Handle是否支持指定的Protocol,如果支持返回指向protocol 接口的指针。在使用这个函数的时候可以先利用LocateHandle()返回支持指定协议的handle,再去寻找Protocol接口。
typedef
EFI_STATUS
(EFIAPI *EFI_HANDLE_PROTOCOL)(
IN EFI_HANDLE Handle, //要查询的句柄
IN EFI_GUID *Protocol, //要查询的protocol的GUID
OUT VOID **Interface //输出参数,指向与protocol匹配的接口的指针
);
OpenProtocol():会查询句柄是否支持指定的protocol。如果支持将会代替调用者打开protocol。它是HandleProtocol的扩展版本,区别在于OpenProtocol打开protocol interface的代理在EFI的句柄数据库中被跟踪。UEFI驱动模型使用跟踪功能,也用于确定卸载或重新安装协议接口是否安全。
typedef
EFI_STATUS
(EFIAPI *EFI_OPEN_PROTOCOL)(
IN EFI_HANDLE Handle, //要查询的句柄
IN EFI_GUID *Protocol, //指定的协议
OUT VOID **Interface OPTIONAL,//输出参数,指向protocol
IN EFI_HANDLE AgentHandle,
IN EFI_HANDLE ControllerHandle,
IN UINT32 Attributes
);
Protocol的简单使用见博客UEFI——Protocol的简单使用