St这个系列是根据 QEMU 执行输出的 Log 来研究代码的。这里继续跟踪研究代码,这次研究的对象是下面这条串口输出:
Register PPI Notify: DCD0BE23-9586-40F4-B643-06522CED4EDE
这句话来自 \MdeModulePkg\Core\Pei\Security\Security.c 文件中的InitializeSecurityServices() 函数:
/**
Initialize the security services.
@param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
@param OldCoreData Pointer to the old core data.
NULL if being run in non-permanent memory mode.
**/
VOID
InitializeSecurityServices (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_CORE_INSTANCE *OldCoreData
)
{
if (OldCoreData == NULL) {
PeiServicesNotifyPpi (&mNotifyList);
}
return;
}
其中 mNotifyList 注册了一个 Ppi Notify 的 Callback 函数:SecurityPpiNotifyCallback()
EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
&gEfiPeiSecurity2PpiGuid,
SecurityPpiNotifyCallback
};
PeiServicesNotifyPpi() 的定义在 \MdePkg\Library\PeiServicesLib\PeiServicesLib.c:
/**
This service enables PEIMs to register a given service to be invoked when another service is
installed or reinstalled.
@param NotifyList A pointer to the list of notification interfaces
that the caller shall install.
@retval EFI_SUCCESS The interface was successfully installed.
@retval EFI_INVALID_PARAMETER The NotifyList pointer is NULL.
@retval EFI_INVALID_PARAMETER Any of the PEI notify descriptors in the list do
not have the EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES
bit set in the Flags field.
@retval EFI_OUT_OF_RESOURCES There is no additional space in the PPI database.
**/
EFI_STATUS
EFIAPI
PeiServicesNotifyPpi (
IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList
)
这个函数的功能是:注册一个 Callback函数,当给定的 Service 安装(install)或者重安装(re-install)时触发这个 callback函数。
经过检查,代码中没有人安装gEfiPeiSecurity2PpiGuid,所以 CallBack 不会发生。接下来找一个有触发 CallBack 函数的作为例子看一下这个如何动作的。
串口输出” Register PPI Notify: 49EDB1C1-BF21-4761-BB12-EB0031AABB397” 和上面的函数类似,这个 GUID定义在 \MdePkg\MdePkg.dec 中:
## Include/Ppi/FirmwareVolumeInfo.h
gEfiPeiFirmwareVolumeInfoPpiGuid = { 0x49edb1c1, 0xbf21, 0x4761, { 0xbb, 0x12, 0xeb, 0x0, 0x31, 0xaa, 0xbb, 0x39 } }
1. 首先注册Notify,在\MdeModulePkg\Core\Pei\FwVol\FwVol.c 中:
EFI_PEI_NOTIFY_DESCRIPTOR mNotifyOnFvInfoList[] = {
{
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
&gEfiPeiFirmwareVolumeInfoPpiGuid,
FirmwareVolumeInfoPpiNotifyCallback
},
{
(EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gEfiPeiFirmwareVolumeInfo2PpiGuid,
FirmwareVolumeInfoPpiNotifyCallback
}
};
接下来可以在在串口 Log 中找到如下字样:
Install PPI: 49EDB1C1-BF21-4761-BB12-EB0031AABB39
Notify: PPI Guid: 49EDB1C1-BF21-4761-BB12-EB0031AABB39, Peim notify entry point: 82153C
2. “Install PPI: 49EDB1C1-BF21-4761-BB12-EB0031AABB39”来自:
\MdePkg\Library\PeiServicesLib\PeiServicesLib.c 中的InternalPeiServicesInstallFvInfoPpi () 函数,首先给PpiGuid赋值
//
// To install FvInfo Ppi.
//
FvInfoPpi = AllocateZeroPool (sizeof (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI));
ASSERT (FvInfoPpi != NULL);
PpiGuid = &gEfiPeiFirmwareVolumeInfoPpiGuid;
接下来PeiServicesInstallPpi (FvInfoPpiDescriptor) 会安装这个 Ppi:
FvInfoPpiDescriptor->Guid = PpiGuid;
FvInfoPpiDescriptor->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
FvInfoPpiDescriptor->Ppi = (VOID *) FvInfoPpi;
Status = PeiServicesInstallPpi (FvInfoPpiDescriptor);
安装过程会出现“Install PPI: 49EDB1C1-BF21-4761-BB12-EB0031AABB39” 的提示。
3. “Notify: PPI Guid: 49EDB1C1-BF21-4761-BB12-EB0031AABB39, Peim notify entry point: 82153C”
因为这里安装了gEfiPeiFirmwareVolumeInfoPpiGuid 所以会执行FirmwareVolumeInfoPpiNotifyCallback() 这个 Callback 函数。在函数中有定义
DEBUG ((
EFI_D_INFO,
"The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
(UINT32) CurFvCount,
(VOID *) FvInfo2Ppi.FvInfo,
FvInfo2Ppi.FvInfoSize,
FvHandle
));
于是我们在串口上能看到如下 Log :
“The 1th FV start address is 0x00000900000, size is 0x00C00000, handle is 0x900000”
就是说按照我们的预期一样,PeiServicesNotifyPpi 函数是用来注册一个 Callback 函数,当安装给定 GUID 的Service 后,触发这个 Callback 函数。