EFI基本概念之PPI

本文介绍了EFI中的PPI(Producer-Producer Interface)基本概念,包括PPI描述符结构、PPI的安装与定位过程。通过示例解析了如何在EFI中使用PeiServicesInstallPpi和PeiServicesLocatePpi进行PPI操作,详细阐述了这两个关键服务函数的工作流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 基本概念及用法

PPI是一个PEIM和另一个PEIM沟通的桥梁,它通过PPI描述符来描述其特性。PPI描述符是一个数据结构。

 

这个数据结构定义如下:

typedef struct {

  UINTN    Flags;

  EFI_GUID *Guid;

  VOID     *Ppi;

}EFI_PEI_PPI_DESCRIPTOR;

    Flags描述了PPI的特征。

    Guid是这个PPI的名字。

    Ppi是service的实体,这个是PPI的真正意义。

   

    既然称其为桥梁,那么就有桥梁的两端。桥梁两端的作用是,一端作为生产者,Install PPI,另一端作为消费者,使用Locate PPI,并且使用它。下面来看一个实例:

1.1  生产者

在UDK2014\MyWorkSpace\MdeModulePkg\Core\DxeIplPeim\DxeLoad.c

EFI_STATUS

EFIAPI

PeimInitializeDxeIpl (

  IN       EFI_PEI_FILE_HANDLE  FileHandle,

  IN CONSTEFI_PEI_SERVICES     **PeiServices

  )

{

   

    Status =PeiServicesInstallPpi (mPpiList);

   

}

分析:PeimInitializeDxeIpl是Dxeload Pei模块的入口,在此函数中PeiServicesInstallPpi(mPpiList)将mPpiList中所有PPI描述符注册到PPIdatabase中。

mPpiList定义如下:

CONSTEFI_PEI_PPI_DESCRIPTOR mPpiList[] = {

  {

    EFI_PEI_PPI_DESCRIPTOR_PPI,

    &gEfiDxeIplPpiGuid,

    (VOID *) &mDxeIplPpi

  },

  {

    (EFI_PEI_PPI_DESCRIPTOR_PPI |EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),

    &gEfiPeiDecompressPpiGuid,

    (VOID *) &mDecompressPpi

  }

};

这个mPpiList数组包含两个PPI描述符。其中第一个Ppi描述符是加载Dxe core用的。

其定义为:

CONST EFI_DXE_IPL_PPImDxeIplPpi = {

  DxeLoadCore

};

1.2  消费者

在UDK2014\MyWorkSpace\MdeModulePkg\Core\Pei\PeiMain\PeiMain.c

Status = PeiServicesLocatePpi (

             &gEfiDxeIplPpiGuid,

             0,

             NULL,

             (VOID **)&TempPtr.DxeIpl

        );

通过此,可找到mDxeIplPpi,然后调用DxeLoadCore进而进入了DXE阶段。

 

2. PPI服务函数

    PeiServicesInstallPpi()的真正执行者是InstallPpi(PeiServices, PpiList)

    PeiServicesLocatePpi()的真正执行者是LocatePpi(PeiServices, Guid, Instance, PpiDescriptor, Ppi)

    这两个是PPI最基本的服务函数。下面解读一下其原型。

 

2.1 PeiInstallPpi

EFI_STATUS

EFIAPI

PeiInstallPpi (

  IN CONSTEFI_PEI_SERVICES        **PeiServices,

  IN CONSTEFI_PEI_PPI_DESCRIPTOR  *PpiList

  )

{

    Step1,由PeiSerivces参数找到PEI Core实例,并找到PPI Database的空闲节点。

    Step2,如果PPIDatabase已满,则退出。

    Step3,如果PPI描述符的Flags标志无EFI_PEI_PPI_DESCRIPTOR_PPI属性,则退出。

    Step4,将PpiList的第一个PPI描述符注册到PPI DataBase中。

    Step5,如果此PPI描述符的Flags有EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST属性,则注册结束,执行Step6,否则跳到Step2。

    Step6,如果新注册的PPI描述符,有其相同GUID的NOTIFY PPI被注册过,则调用其NotifyPPI函数。

}

 

 

 

2.2 PeiLocatePpi

EFI_STATUS

EFIAPI

PeiLocatePpi (

  IN CONSTEFI_PEI_SERVICES        **PeiServices,

  IN CONSTEFI_GUID                *Guid,

  IN UINTN                         Instance,

  IN OUTEFI_PEI_PPI_DESCRIPTOR   **PpiDescriptor,

  IN OUT VOID                      **Ppi

  )

{

    Step1,根据PeiServices找到PEI Core实例

    Step2,在注册过的PPI描述符中,找到描述符Guid与参数中Guid相匹配的PPI描述符项。根据Instance,确定找第几个PPI描述符。如果PpiDescriptor不为空,则将PPI描述符赋给PpiDescriptor;如果Ppi不为空,则将PPI描述符的Ppi字段赋给该Ppi参数。

    Step3,如果Step2有找到相应的PPI,返回成功标志;否则返回没找到标志。

}

<think>好的,我现在需要详细解答用户关于EFI_PEI_PPI_DESCRIPTOR的问题,包括它的定义、结构解析、使用场景以及相关开发文档的内容。首先,我需要回忆和查阅相关的UEFI和PEI阶段的知识,确保信息的准确性。 根据用户提供的引用内容,特别是引用[1]和[2],PEI阶段的核心是PEI Foundation和PEIM模块。EFI_PEI_PPI_DESCRIPTOR在PEI初始化过程中用于描述PPI(PEIM-to-PEIM Interfaces),这些接口允许不同模块之间进行通信。接下来,我需要明确这个描述符的结构定义。 查阅UEFI开发文档,EFI_PEI_PPI_DESCRIPTOR通常包含几个关键字段:Flags、GUID和Ppi。Flags用于指示PPI的类型,比如是否自动安装。GUID是全局唯一标识符,用于识别不同的接口。Ppi则是指向实际接口的指针。需要详细说明每个字段的作用和可能的值。 使用场景方面,PEIM在初始化时会通过InstallPpi函数注册自己的服务,其他模块则通过LocatePpi来查找并使用这些服务。比如,内存初始化模块可能提供一个PPI供其他模块调用。这里需要结合具体例子,让用户更容易理解。 结构解析部分,需要逐字段解释,比如Flags的EFI_PEI_PPI_DESCRIPTOR_PPIEFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK等值的含义。GUID的结构和使用方法,以及Ppi指针的类型转换注意事项。 开发文档方面,用户可能需要参考《UEFI Platform Initialization (PI) Specifications》和EDK2的代码库,特别是PeiServices.h头文件。同时,引用中的示例代码和函数原型(如PEI入口点函数)需要联系起来,说明EFI_PEI_PPI_DESCRIPTOR如何被传递和使用。 最后,生成相关问题时要考虑用户可能的后续疑问,比如与其他描述符的区别、动态注册方法、错误处理等。确保问题覆盖结构、使用和实际开发中的常见情况。</think>### EFI_PEI_PPI_DESCRIPTOR 详解 #### **1. 定义与作用** `EFI_PEI_PPI_DESCRIPTOR` 是 UEFI **PEI 阶段**(Pre-EFI Initialization)中用于描述 **PPI**(PEIM-to-PEIM Interfaces)的核心数据结构。PPI 是 PEIM(PEI 模块)之间通信的接口协议,类似于 DXE 阶段的 Protocol,但作用范围仅限于 PEI 阶段[^2]。 #### **2. 结构解析** 其标准定义如下(以 EDK2 代码为例): ```c typedef struct { UINTN Flags; // 描述符类型标识 EFI_GUID *Guid; // PPI 的唯一标识(GUID) VOID *Ppi; // 指向 PPI 实例的指针 } EFI_PEI_PPI_DESCRIPTOR; ``` - **Flags**:控制描述符行为的标志,常见值: - `EFI_PEI_PPI_DESCRIPTOR_PPI`:表示这是一个普通 PPI。 - `EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK`:表示这是一个回调通知类型的 PPI。 - **Guid**:全局唯一标识符(如 `gEfiPeiCpuIoPpiGuid`),用于标识 PPI 的类型。 - **Ppi**:指向具体 PPI 实例的指针,需通过类型转换(如 `(EFI_PEI_CPU_IO_PPI*)`)访问。 #### **3. 使用场景** - **注册 PPI**:PEIM 在初始化时通过 `InstallPpi()` 注册自己的服务。 ```c EFI_PEI_PPI_DESCRIPTOR mPpiList = { EFI_PEI_PPI_DESCRIPTOR_PPI, &gExamplePpiGuid, &mExamplePpiInstance }; PeiServicesInstallPpi(&mPpiList); ``` - **查找 PPI**:其他 PEIM 通过 `LocatePpi()` 获取已注册的 PPI: ```c ExamplePpi* Ppi; PeiServicesLocatePpi(&gExamplePpiGuid, 0, NULL, (VOID**)&Ppi); ``` #### **4. 典型应用示例** - **内存初始化**:内存控制器 PEIM 可能通过 PPI 提供 `MemInitPpi`,供其他模块调用。 - **硬件抽象**:如 `EFI_PEI_CPU_IO_PPI` 提供 CPU 级别的 I/O 操作接口[^1]。 #### **5. 开发文档参考** - **UEFI PI 规范**:详细定义 PEI 阶段的所有数据结构和流程(Volume 1: Pre-EFI Initialization)。 - **EDK2 源码**:`MdePkg/Include/Ppi/` 目录包含标准 PPI 的定义,例如 `CpuIoPpi.h`。 - **调试技巧**:使用 `DEBUG((EFI_D_INFO, "PPI GUID: %g\n", Guid))` 输出 GUID 信息以验证注册状态。 --- §§ 相关问题 §§ 1. **PPI 与 DXE 阶段的 Protocol 有何本质区别?** 2. **如何动态注册一个支持回调通知的 PPI?** 3. **在 PEI 阶段,若 `LocatePpi` 失败应如何处理?** 4. **EFI_GUID 的结构定义是什么?如何生成自定义 GUID?** 5. **哪些常见 PPI 必须由 PEI Foundation 预先提供?** [^1]: PEI Foundation 入口函数通过 `PpiList` 参数传递初始 PPI。 : PEI 阶段的模块交互依赖 PPI,而 DXE 阶段使用 Protocol 实现更复杂的服务。 [^3]: BDS 阶段的入口函数通过类似机制管理启动流程。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值