UEFI源码解析之PROTOCOL&HANDLE

UEFI源码解析之PROTOCOL&HANDLE,第1张

UEFI源码解析之PROTOCOL&HANDLE

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;

}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5721964.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存