UEFI --- 欣赏

一 : 标准Application的加载过程
在这里插入图片描述
二 : HANDLE 维护的Protocol链表
在这里插入图片描述
在加载Application的时候 有重新安装了Protocol:EFI_LOADED_IMAGE_PROTOCOL
且这个Protocol很强大:
Can be used on any image handle to obtain information about the loaded image.
在这里插入图片描述
好,下面看一下 打开一个 PROTOCOL的通路是什么样子的,能否有更好的实现方式
下面画了一个开始-结果的图
在这里插入图片描述

/*Handle持有的PROTOCOL的链表中根据 GUID 来找到该PROTOCOL
	
	GUID唯一的标识,这样的策略随处可见了 如:
	
	optee:
	OPTEE中使用UUID来标识一个TA,把UUID通过RPC机制传递到REE,根据它来选择要加载的TA
	
	linux kernel:
	Linux Kernel中通过PID来标识一个Task(暂不考虑其他), 使用pid来访问Task : find_task_by_pid_ns()
    
    唯一太重要了,不仅仅在software中, 身份证号是唯一的  它重要吧,
    但是我越来越认为 身份证号码的设计:暴露地域和生日 是不合理的 哈哈 扯远了😄 

	param:
		@UserHandle  
		HANDLEProtocol的提供者, 它的原型是 IHANDLE,表示某一个对象 如一个ImageController等
		属于它自己的Protocol都挂接在它维护的链表上(参见上图), 当需要的时候,就到该链表上找吧
		这也是Linux Kernel 思想的体现
		@Protocol
		刚说过 弱水三千 只取你这一瓢
*/
PROTOCOL_INTERFACE  *CoreGetProtocolInterface (
  IN  EFI_HANDLE                UserHandle,
  IN  EFI_GUID                  *Protocol
  )
{
  /*
  	好,开始遍历吧
  */  
  for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
    Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
    /*
    	拿到 Protocol 实例
    */
    ProtEntry = Prot->Protocol;
    /*
    	开始比较GUID,然后返回, 
    */
    if (CompareGuid (&ProtEntry->ProtocolID, Protocol)) {
      return Prot;
    }
  }
}

在这里插入图片描述

EFI_STATUS
EFIAPI
CoreOpenProtocol (...)
{
  /*
  	Linux Kernel 的思想又再一次迸发出强大的虹吸效应 ! 
  	看下面
  	    1 : 分配内存空间
  	    2 : 赋值初始化
  	    3 : 添加到链表上

	这种思想是每个操作系统必备的基础设施 !
	无论是在 伟大的 Linux Kernel 中 还是 非常优秀的 Security OS : OPTEE
	其身影无处不在 !
  */
  /*
  	分配内存空间吧 (小块的内存空间)
  */	
  OpenData = AllocatePool (sizeof(OPEN_PROTOCOL_DATA));
  if (OpenData == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
  } else {
  	/*
  	    各种属性填充上去
  	*/
    OpenData->Signature         = OPEN_PROTOCOL_DATA_SIGNATURE;
    OpenData->AgentHandle       = ImageHandle;
    OpenData->ControllerHandle  = ControllerHandle;
    OpenData->Attributes        = Attributes;
    OpenData->OpenCount         = 1;
	/*
		添加到 OpenList链表中
		Protocol被成功打开一次 OpenList被更新一次.
	*/
    InsertTailList (&Prot->OpenList, &OpenData->Link);
	/*
		引用计数 +1 
		当然, 在 CoreCloseProtocol()中会将该值 -1
	*/
    Prot->OpenListCount++;
    Status = EFI_SUCCESS;
  }
}
/*
	ProtocolsPerHandle 用于获得指定设备所支持的所有 Protocols
	下面是将这些protocol的GUID放入到buffer中返回
*/
EFI_STATUS EFIAPI CoreProtocolsPerHandle (...)
{
  EFI_GUID    **Buffer;
  
  ....
  /*
  	分配内存空间
  	调用者别忘了释放该内存
  */
  Buffer = AllocatePool (sizeof (EFI_GUID *) * ProtocolCount);
  ....
  
  *ProtocolBuffer = Buffer;
  /*
  	遍历 HANDLE 持有的PROTOCOL链表
  */
  for ( Link = Handle->Protocols.ForwardLink, ProtocolCount = 0;
        Link != &Handle->Protocols;
        Link = Link->ForwardLink, ProtocolCount++) {
    /*
    	获取PROTOCOL
    */    
    Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
    /*
    	将该PROTOCOLGUID放入到 ProtocolBuffer 返回
    */
    Buffer[ProtocolCount] = &(Prot->Protocol->ProtocolID);
  }
}

/*
	调用者赋值释放存放GUID的内存空间
*/
Status = gBS->ProtocolsPerHandle(TheHandle, &ProtocolBuffer, &ProtocolCount);
if (EFI_ERROR (Status))
  return 0;
  
FreePool (ProtocolBuffer);
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值