PEI阶段扩展——PEIM PPI HOB

2 篇文章 2 订阅

OVERVIEW

本篇补充相关PEI到DXE阶段的一写知识
在PEI阶段,PEIM 、PPI、 HOB组成了PEI阶段的最重要的部分,PEI阶段的module也可以理解为Driver就是PEIM,PEI阶段就是由一个一个的PEIM组成的;PPI是PEIM之间互相调用的接口,由惟一的GUID引导,内部也包含一些接口,HOB相当于信件在PEI阶段创建,会记载当前系统的信息,可以自定义HOB,然后在DXE阶段读取。框图如下:
在这里插入图片描述
简单解读:
PEI Core主要包括Core Services和Core Dispatcher。

  • Core Services包括PEI及后面phase要用到的各种Services, 比如Status Code, HOBs,Memory Services,Boot Mode Services等。在PEi阶段get当前计算机启动的boot Mode是有直接定义好的PEI Service函数,在DXE以及后面的阶段要通过HOB方式,通过get HOB LIST然后拆解信息进行get启动的boot Mode。
  • Core Dispatcher负责派发各PEIMs,意思是将PEIM按照既定的顺序Load并执行。这里的既定顺序即Dependency顺序,就是inf文件里面的depx,只有满足条件才会执行。
  • 各PEIM Entry可能使用其它PEIM的PPI, 也可能使用自己的PPI。
  • PEI Core最后会找到DXE IPL PPI,(IPL是一个很重要的知识点)进入下一阶段DXE。
  • DXE获得之前phase Data的是从HOB里拿,PEI Core会创建HOB,PEI和DXE都可以使用HOB的Data。

PEIM

PEIM(PEI Module), 会被编译成efi binary,在一套完整的BIOS code编译完之后进入到build目录就可以找到这个PEIM具体的efi,.inf + .c +.h >build> .efi是为了硬件相关的初始化,PEIM 也提供各自提供接口(interface)给别的PEIM使用
在这里插入图片描述

PPI

PPIs (PEIM-to-PEIM Interfaces)

  • PEIMs被调用是通过PPI,Interface。Interface是UEFI重要的概念,会经常出现。简单来说,PPI只是一个接口,接口里面有成员函数,想调用某个函数必须通过该接口。
  • PPI的名字:GUID (128-bits value)
  • PPIs被定义成结构体的形式,在code里看PPI就是一个Struct,其中可能包括功能、数据,或者两者的混合。
  • PEIM会把它的PPI注册到PEI Foundation,PEI Foundation管理着庞大的PPI数据库

USE PPI

几个重要的PPI Services

  • InstallPpi() 安装PPI到PEI foundation,protocol install完后是放到Handle Datebase里面
  • LocatePpi() 根据PPI名字GUID从PEI foundation找Interface
  • NotifyPpi() PPI里的function不会在派发时就执行,会有一个判定条件,通知系统这个PPI会在某个PPI被安装时才执行。

Install PPI

 /**

  Install PPI services. It is implementation of EFI_PEI_SERVICE.InstallPpi.
  这是个service,PEI foundation提供的。 通过GUID安装。目的是让别人调用。
  @param PeiServices                An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
  标准格式,入口第一人参数是铁定的EFI_PEI_SERVICES指针
  @param PpiList                    Pointer to PPI array that want to be installed.
  第二个参数是PPI List, LIST里包括Flag、GUID和函数 参考.h里的EFI_PEI_PPI_DESCRIPTOR定义

  @retval EFI_SUCCESS               if all PPIs in PpiList are successfully installed.
  @retval EFI_INVALID_PARAMETER     if PpiList is NULL pointer
                                    if any PPI in PpiList is not valid
  @retval EFI_OUT_OF_RESOURCES      if there is no more memory resource to install PPI

**/
EFI_STATUS
EFIAPI
PeiInstallPpi (
  IN CONST EFI_PEI_SERVICES        **PeiServices,
  IN CONST EFI_PEI_PPI_DESCRIPTOR  *PpiList
  );
 

实例:
以下面的PPI为例,一个给Capsule服务的PPI,里面有三个成员 CapsuleCoalesce, CheckCapsuleUpdate, CreateState。

CONST EFI_PEI_CAPSULE_PPI        mCapsulePpi = {
  CapsuleCoalesce,
  CheckCapsuleUpdate,
  CreateState
};

给InstallPPI传递的第二个参数:*PpiList。Descriptor有三个值,第一个为属性,第二个为绑定的GUID用于后面locate调用,第三个参数放入struct接口,这样就定义好了ppiList。
在这里插入图片描述
安装PpiList, 通常代码会用Library封装(*PeiServices)->InstallPpi 成PeiServicesInstallPpi
在这里插入图片描述

PeiServicesInstallPpi原型函数,还是那个标准的InstallPpi,传了两个参数This指针和PpiList
在这里插入图片描述

EFI_PEI_PPI_DESCRIPTOR

//
// PEI Ppi Services List Descriptors
//
#define EFI_PEI_PPI_DESCRIPTOR_PIC              0x00000001
#define EFI_PEI_PPI_DESCRIPTOR_PPI              0x00000010
#define EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK  0x00000020
#define EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH  0x00000040
#define EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES     0x00000060
#define EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST   0x80000000
///
/// The data structure through which a PEIM describes available services to the PEI Foundation.
///
typedef struct {
  ///
  /// This field is a set of flags describing the characteristics of this imported table entry.
  /// All flags are defined as EFI_PEI_PPI_DESCRIPTOR_***, which can also be combined into one.
  /// 上面描述的属性。
  UINTN     Flags;
  ///
  /// The address of the EFI_GUID that names the interface.
  /// 所绑定的GUID
  EFI_GUID  *Guid;
  ///
  /// A pointer to the PPI. It contains the information necessary to install a service.
  /// 所需要install的PPI
  VOID      *Ppi;
} EFI_PEI_PPI_DESCRIPTOR;

LocatePPI()

/**
  Locate a given named PPI.
  用GUID从Database中找想要的PPI

  @param PeiServices     An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
  @param Guid            Pointer to GUID of the PPI.
  @param Instance        Instance Number to discover.
  @param PpiDescriptor   Pointer to reference the found descriptor. If not NULL,
                         returns a pointer to the descriptor (includes flags, etc)
  @param Ppi             Pointer to reference the found PPI
  
  @retval EFI_SUCCESS   if the PPI is in the database
  @retval EFI_NOT_FOUND if the PPI is not in the database
  
**/
EFI_STATUS
EFIAPI
PeiLocatePpi (
  IN CONST EFI_PEI_SERVICES      **PeiServices,
  IN CONST EFI_GUID              *Guid,
  IN UINTN                       Instance,
  IN OUT EFI_PEI_PPI_DESCRIPTOR  **PpiDescriptor,
  IN OUT VOID                    **Ppi
  );
//第一个参数是固定的EFI_PEI_SERVICES第二个参数为GUID,第三个参数通常为0,第四个参数为NULL最重要是拿到第五个参数,通过这个指针可以得到Interface。

实例:
以Capsule为例:Guid为gEfiPeiCapsulePpiGuid,通过这个GUID从Database中找想要的PPI, 想要的PPI都在这个Capsule指针里,Locate之后就可以调用PPI里的函数实现CheckCapsuleUpdate功能
在这里插入图片描述
这也是封装过的LocatePpi,原型函数是下面这样,标准的LocatePpi,当然直接用PeiService->也是可以的
在这里插入图片描述

Notifyppi()

/**

  Install a notification for a given PPI.
  注册一个notification服务,当给定的那个PPI被安装或者再安装时,执行notify里的函数。
  
  @param PeiServices            An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
  @param NotifyList             Pointer to list of Descriptors to notify upon.

  @retval EFI_SUCCESS           if successful
  @retval EFI_OUT_OF_RESOURCES  if no space in the database
  @retval EFI_INVALID_PARAMETER if not a good descriptor
  NotifyList里包括Flag,GUID和Notify Routine

**/
EFI_STATUS
EFIAPI
PeiNotifyPpi (
  IN CONST EFI_PEI_SERVICES           **PeiServices,
  IN CONST EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyList
  );

实例:当这个gEfiEndOfPeiSignalPpiGuid指向的PPI被安装时才会触发S3EndOfPeiNotify()
在这里插入图片描述
1->首先将要做的事情写到这个函数中,
2->定义好Notify Descriptor :FLAG 、所需加载的PPI GUID、需要执行的函数
3->调用封装后的PeiServiceNotifyPpi => (*PeiServices)->NotifyPpi(PeiServices,NotifyList);
注:在自定义的函数中在确定的点运行相关ppi最好自己写一个Ppi作为触发条件,否则在使用code中定义好的Ppi时需确保不会被其他函数影响或影响其它函数
在这里插入图片描述

HOB

HOB (Hand-Off Blocks )传输信息的载体,相比于其他Phase之间的联系,Pei到DXE之间联系比较薄弱,PEI一些初始化硬件、内存的数据等,DXE需要知道,HOB便作为桥梁应运而生。

  • HOB producer phase (PEI phase)
  • HOB consumer phase (PEI & DXE phase) (如getbootmodehob就是在PEI阶段调用的,但DXE阶段是不能产生HOB的)

HOB实际上就是一个链表,当我们找到一个hoblist的头,那么整个链表的数据都能get到,比如说GetHobList(),会直接获取hoblist的指针,而且第一个HOB总是为PHIT == Phase Handoff Information Table,里面是boot mode
其它HOB可能出现在List任意位置, 最重要的是System Memory HOB & Firmware Volumes, HOB列表总是会以END_OF_HOB_LIST结束
在这里插入图片描述
所以判定是否是HOBlist的最后一个一般都是while (!END_OF_HOB_LIST (Hob))。
在这里插入图片描述

下图中没有显示的另一个HOB类型是GUID HOB,它允许PEIM将私有数据传递给DXE驱动程序。
在这里插入图片描述
HOB TYPE
在这里插入图片描述
GUID类型的HOB是自定义HOB时候会用到的类型,通常用于自己写一些HOB信息。

HOB的使用

/**
  Add a new HOB to the HOB List.

  @param PeiServices        An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
  @param Type               Type of the new HOB.
  @param Length             Length of the new HOB to allocate.
  @param Hob                Pointer to the new HOB.

  @return  EFI_SUCCESS           Success to create HOB.
  @retval  EFI_INVALID_PARAMETER if Hob is NULL
  @retval  EFI_NOT_AVAILABLE_YET if HobList is still not available.
  @retval  EFI_OUT_OF_RESOURCES  if there is no more memory to grow the Hoblist.

**/
EFI_STATUS
EFIAPI
PeiCreateHob (
  IN CONST EFI_PEI_SERVICES  **PeiServices,
  IN UINT16            Type, //对于自定义的HOB 一般使用EFI_HOB_GUID_TYPE
  IN UINT16            Length,
  IN OUT VOID          **Hob
  );

在这里插入图片描述
GetHobList()返回整个HOB列表中匹配GUID HOB的第一个实例
由于阶段不一样,PEI直接拿到HOB List Pointer, DXE通过System Configuration Table (gST)拿。

在这里插入图片描述

传入的参数第一个为Hob的GUID,所有的UEFI元素都有自己的GUID,传入得到的返回结果就是HOBlist ,通过的是configration table去抓的(属于systemtable的成员),每个DXE Driver的entrypoint都有两个参数imaginehandle 和systemtable,故而可以通过systemtable可以访问整个系统的资源。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 15
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值