Protocol用于UEFI在DXE及之后各阶段中各模块之间的通信,作用与PI阶段的PPI类似;Protocol与Handle一起使用,实现了C++中的面向对象的编程方式,且能达到类似数组或map中的访问方式,通过一个输入数值Handle/GUID等获取数据结构信息或 *** 作接口等;
以下介绍Protocol/Handle在UEFI内核中的实现以及各接口的使用;主要代码在MdeModulePkgCoreDxeHandHandle.c中,DxeMain阶段的mBootDevice中指向了各与Protocol/Handle相关的接口。
几个重要的全局变量,用于保存Protocol/Handle的全貌;
//整个系统所有Protocol构成的链表
LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase);
//整个系统所有Handle构成的链表
LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList);
// Protocol/Handle *** 作的互斥保护锁
EFI_LOCK gProtocolDatabaseLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
UINT64 gHandleDatabaseKey = 0;
重要的数据结构及相互之间的连接关系:
Protocol对应一个PROTOCOL_ENTRY,通过AllEntries连入mProtocolDatabase全局链表中;
通过给定的Protocol GUID可以在链表中找到该Entry:
PROTOCOL_ENTRY *CoreFindProtocolEntry (IN EFI_GUID *Protocol, IN BOOLEAN Create)
{
//遍历mProtocolDatabase的节点,节点的guid与输入guid一直则认为找到
ProtEntry = NULL;
for (link = mProtocolDatabase.Forwardlink; link != &mProtocolDatabase;
link = link->Forwardlink) {
Item = CR(link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);
if (CompareGuid (&Item->ProtocolID, Protocol)) {
ProtEntry = Item;
break;
}
}
// 没有找到guid对应的protocol entry,且指定了新建标志,则新建entry
if ((ProtEntry == NULL) && Create) {
ProtEntry = AllocatePool (sizeof(PROTOCOL_ENTRY));
CopyGuid ((VOID *)&ProtEntry->ProtocolID, Protocol); //初始化guid
InitializeListHead (&ProtEntry->Protocols); //连接该protocol相关的Interface
InitializeListHead (&ProtEntry->Notify); //连接该protocol相关的Notify
InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries); //全局管理
}
}
return ProtEntry;
}
所有安装在Handle上的Protocol中实际内容用PROTOCOL_INTERFACE表示,
typedef struct {
UINTN Signature;
LIST_ENTRY link;
IHANDLE *Handle;
LIST_ENTRY ByProtocol;
PROTOCOL_ENTRY *Protocol;
VOID *Interface;
LIST_ENTRY OpenList;
UINTN OpenListCount;
} PROTOCOL_INTERFACE;
Handle的表示,通过AllHandles连接到gHandleList全局链表中;通过判断给定的handle是否在链表gHandleLIst中可以判别该handle是否有效:
Core Validate Handle(EFI_HANDLE UserHandle)
{
}
typedef VOID *EFI_HANDLE //无类型指针
typedef struct {
UINTN Signature;
LIST_ENTRY AllHandles;
LIST_ENTRY Protocols;
UINTN LocateRequest;
UINT64 Key;
} IHANDLE;
Protocol/Handle的结构关系图,protocol/handle的每个 *** 作都能通过该关系图找到执行流程;
各接口的实现分析:protocol当作传参时指的是protocol的guid
安装protocol到对应的handle上,handle不存在则新建handle并返回handle;
CoreInstallProtocolInterface (
IN OUT EFI_HANDLE *UserHandle,
IN EFI_GUID *Protocol,
IN EFI_INTERFACE_TYPE InterfaceType,
IN VOID *Interface
)
{
return CoreInstallProtocolInterfaceNotify (
UserHandle,
Protocol,
InterfaceType,
Interface,
TRUE //是否唤醒该protocol下的notify链表
);
}
---->
CoreInstallProtocolInterfaceNotify (UserHandle,Protocol,InterfaceType,
Interface,TRUE );
{
// 查询该handle是否支持待安装的Protocol,不支持则返回参数异常
Status = CoreHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface);
// 查找protocol对应的Protocol entry
ProtEntry = CoreFindProtocolEntry (Protocol, TRUE);
//分配新的Protocol Interface
Prot = AllocateZeroPool (sizeof(PROTOCOL_INTERFACE));
//Handle 输入不存在则分配新的Ihandle并初始化,加入gHandleList全局链表
//每个interface都是唯一的,如果重复安装则异常
ASSERT (CoreFindProtocolInterface (Handle, Protocol, Interface) == NULL);
// 初始化填充分配的Protocol Interface
Prot->Handle = Handle;
Prot->Protocol = ProtEntry;
Prot->Interface = Interface;
InitializeListHead (&Prot->OpenList); //打开该Protocol的统计
Prot->OpenListCount = 0;
// 将protocol interface加入到handle支持的protocol链表中
InsertHeadList (&Handle->Protocols, &Prot->link);
//将protocol interface加入到entry支持的protocol链表中
InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);
if (Notify) { //唤醒Protocol Entry上的所有Event
CoreNotifyProtocolEntry (ProtEntry);
}
*UserHandle = Handle;
}
---->
CoreNotifyProtocolEntry (IN PROTOCOL_ENTRY *ProtEntry)
{
}
//
查询指定的Handle中是否支持指定的Protocol,返回Handle实际的内容Interface;
gBs->HandleProtocol : CoreHandleProtocol //即根据handle找Protocol
gBs->OpenProtocol : CoreOpenProtocol
CoreOpenProtocol (
IN EFI_HANDLE UserHandle,
IN EFI_GUID *Protocol,
OUT VOID **Interface OPTIONAL,
IN EFI_HANDLE ImageHandle, //当前打开了该protocol的image句柄
IN EFI_HANDLE ControllerHandle, //需要protocol interface的控制器
IN UINT32 Attributes //打开方式
)
{
OPEN_PROTOCOL_DATA *OpenData;
// 检车UserHandle是否已存在
Status = CorevalidateHandle (UserHandle);
//根据不同的打开方式判断受否需要检查ImageHandle/ControllerHandle
Status = CorevalidateHandle (ImageHandle);
Status = CorevalidateHandle (ControllerHandle);
// 获取相应的Interface:handle-->interface-->entry-->guid判断
Prot = CoreGetProtocolInterface (UserHandle, Protocol);
// 如果open信息统计列表不为空,表示已有别的方式打开了该Protocol,做相应的处理:
1. 是否已经被驱动打开ByDriver,是否独占方式打开打开Exclusive, 是否被同样handle打开ExactMatch;
2. 如果已被driver或独占方式打开,则此次不能打开;
3. 如果已被驱动打开,这次被独占方式打开,断开相应的驱动连接,独占方式最牛逼;
// 保存当前的打开信息用于下一次打开时做判断
//返回实际需要的Interface信息(接口函数指针或数据)
*Interface = Prot->Interface;
}
//
从UEFI内核环境查找指定Protocol的Handle实列,即根据Protocol找Handle,与Open相反;
gBds->LocateHandle : CoreLocateHandle // 返回满足的Handles,调用者管理内存;
gBds->LocateHandleBuffer : CoreLocateHandleBuffer // 返回所有的handle及个数,接口自己管理内存;
Handle搜索方式:
typedef enum {
AllHandles, //返回所有的handles
ByRegisterNotify, //从RegisterProtocolNotify中返回匹配SearchKey的Handle
ByProtocol // 返回所有满足protocol的handles
} EFI_LOCATE_SEARCH_TYPE;
CoreLocateHandle ( //调用者负责内存管理
IN EFI_LOCATE_SEARCH_TYPE SearchType,
IN EFI_GUID *Protocol OPTIONAL,
IN VOID *SearchKey OPTIONAL, //ByRegisterNotify时不能为空
IN OUT UINTN *BufferSize,
OUT EFI_HANDLE *Buffer
)
{
Case: AllHandles
CoreGetNextLocateAllHandles() //将gHandleList元素依次返回
Case: ByRegisterNotify
CoreGetNextLocateByRegisterNotify (*Position, **Interface) //查找下一个Handle
{
ProtNotify = Position->SearchKey;
}
Case: ByProtocol
// 查找链:Guid--->entry--->interface--->Handle
Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
Position.Position = &Position.ProtEntry->Protocols;
CoreGetNextLocateByProtocol (*Position, **Interface)
{
For(;;)
{
link = Position->Position->Forwardlink;
Position->Position = link;
Prot = CR(link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
Handle = Prot->Handle;
*Interface = Prot->Interface;
// 检查和设置标记确认当前的handle受否被之前的请求访问过,访问过则返回限一个handle
}
return handle;
}
Handle = GetNext (&Position, &Interface);
*BufferSize = ResultSize;
// ByRegisterNotify 时调整Notify指针指向下一个;
if (SearchType == ByRegisterNotify && !EFI_ERROR(Status)) {
ProtNotify = SearchKey;
ProtNotify->Position = ProtNotify->Position->Forwardlink;
}
}
CoreLocateHandleBuffer() //函数内部负责内存管理
{ //第一次调用获取bufferSize
//分配内存
//第二次获取handles
}
//
根据ProtocolGuid查找Protocol Interface
gBds->LocateProtocol:CoreLocateProtocol // 返回满足的第一个满足guid的protocol interface
CoreLocateProtocol (
IN EFI_GUID *Protocol,
IN VOID *Registration OPTIONAL,
OUT VOID **Interface
)
{
}
gBs->RegisterProtocolNotify: 新增一个Protocol Notify到Protocol Entry中,Notify在Install Protocol的时候signal对应的Event,详见Protocol Install和Event Signal;
CoreRegisterProtocolNotify (
IN EFI_GUID *Protocol,
IN EFI_EVENT Event,
OUT VOID **Registration
)
{
// 查找对应的Protocol Entry
ProtEntry = CoreFindProtocolEntry (Protocol, TRUE);
if (ProtEntry != NULL) {
// 分配Notify空间并初始化,
ProtNotify = AllocatePool (sizeof(PROTOCOL_NOTIFY));
if (ProtNotify != NULL) {
((IEVENT *)Event)->ExFlag |= EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION;
ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE;
ProtNotify->Protocol = ProtEntry;
ProtNotify->Event = Event;
ProtNotify->Position = &ProtEntry->Protocols;
// 接入Entry中Notify链表
InsertTailList (&ProtEntry->Notify, &ProtNotify->link);
}
}
*Registration = ProtNotify;
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)