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,返回成功标志;否则返回没找到标志。
}