在查看 Log 的时候,发现一个有趣的地方:
DiscoverPeimsAndOrderWithApriori(): Found 0x7 PEI FFS files in the 0th FV
Loading PEIM 9B3ADA4F-AE56-4C24-8DEA-F03B7558AE50
Loading PEIM at 0x0000083A7A0 EntryPoint=0x0000083AC68 PcdPeim.efi
Install PPI: 06E81C58-4AD7-44BC-8390-F10265F72480
Install PPI: 01F34D25-4DE2-23AD-3FF3-36353FF323F1
Install PPI: 4D8B155B-C059-4C8F-8926-06FD4331DB8A
………………….
Notify: PPI Guid: EE16160A-E8BE-47A6-820A-C6900DB0250A, Peim notify entry point: 847814
PlatformPei: ClearCacheOnMpServicesAvailable
Loading PEIM 9B3ADA4F-AE56-4C24-8DEA-F03B7558AE50
Loading PEIM at 0x00007ED8000 EntryPoint=0x00007ED84C8 PcdPeim.efi
Reinstall PPI: 06E81C58-4AD7-44BC-8390-F10265F72480
Reinstall PPI: 4D8B155B-C059-4C8F-8926-06FD4331DB8A
Reinstall PPI: 01F34D25-4DE2-23AD-3FF3-36353FF323F1
Reinstall PPI: A60C6B59-E459-425D-9C69-0BCC9CB27D81
就是说在 PEI 阶段,PcdPeim.efi 运行了两次。本着探究的精神着手研究原因。
首先研究了一下 PeiCore 的部分,唯一可以确定的是:第二次运行是在内存Ready 后的PeiDispatcher() 函数中:
if (Status == EFI_SUCCESS) {
//
// PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE
//
Private->Fv[Index1].PeimState[Index2]++;
//
// Call the PEIM entry point
//
PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
PERF_START_IMAGE_BEGIN (PeimFileHandle);
PeimEntryPoint(PeimFileHandle, (const EFI_PEI_SERVICES **) &Private->Ps);
PERF_START_IMAGE_END (PeimFileHandle);
}
于是目光转到 PcdPei 本身,在\MdeModulePkg\Universal\PCD\Pei\Pcd.c 文件中PcdPeimInit() 函数里面可以看到,运行之后调用了 PeiServicesRegisterForShadow() 函数:
EFI_STATUS
EFIAPI
PcdPeimInit (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
Status = PeiServicesRegisterForShadow (FileHandle);
if (Status == EFI_ALREADY_STARTED) {
//
// This is now starting in memory, the second time starting.
//
EFI_PEI_PPI_DESCRIPTOR *OldPpiList;
EFI_PEI_PPI_DESCRIPTOR *OldPpiList2;
VOID *Ppi;
VOID *Ppi2;
猜测第二次运行就是因为这个函数的缘故,修改之前的TestPei 加入PeiServicesRegisterForShadow() 函数:
EFI_STATUS
EFIAPI
InitializeTestPei (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
DEBUG ((DEBUG_INFO, "LABZ Test PEIM\n"));
Status = PeiServicesRegisterForShadow (FileHandle);
if (Status == EFI_ALREADY_STARTED) {
DEBUG ((DEBUG_INFO, "LABZ Test RUN AGAIN\n"));
}
return EFI_SUCCESS;
}
运行之后查看 Log:
iscoverPeimsAndOrderWithApriori(): Found 0x8 PEI FFS files in the 0th FV
Loading PEIM 122C386D-5ABC-4FB4-B124-FBB82488ACF4
Loading PEIM at 0x0000085A920 EntryPoint=0x0000085ADA8 TestPei.efi
LABZ Test PEIM
Loading PEIM 9B3ADA4F-AE56-4C24-8DEA-F03B7558AE50
Loading PEIM at 0x0000083A8A0 EntryPoint=0x0000083AD68 PcdPeim.efi
Install PPI: 06E81C58-4AD7-44BC-8390-F10265F72480
Install PPI: 01F34D25-4DE2-23AD-3FF3-36353FF323F1
……………………
Notify: PPI Guid: EE16160A-E8BE-47A6-820A-C6900DB0250A, Peim notify entry point: 847914
PlatformPei: ClearCacheOnMpServicesAvailable
Loading PEIM 122C386D-5ABC-4FB4-B124-FBB82488ACF4
Loading PEIM at 0x00007EDB000 EntryPoint=0x00007EDB488 TestPei.efi
LABZ Test PEIM
LABZ Test RUN AGAIN
Loading PEIM 9B3ADA4F-AE56-4C24-8DEA-F03B7558AE50
Loading PEIM at 0x00007ED5000 EntryPoint=0x00007ED54C8 PcdPeim.efi
Reinstall PPI: 06E81C58-4AD7-44BC-8390-F10265F72480
Reinstall PPI: 4D8B155B-C059-4C8F-8926-06FD4331DB8A
Reinstall PPI: 01F34D25-4DE2-23AD-3FF3-36353FF323F1
可以看到 TestPei 运行了2次。
在\mdepkg\library\peiserviceslib\PeiServicesLib.c可以看到 PeiServicesRegisterForShadow() 函数定义:
/**
This service is a wrapper for the PEI Service RegisterForShadow(), except the
pointer to the PEI Services Table has been removed. See the Platform
Initialization Pre-EFI Initialization Core Interface Specification for details.
@param FileHandle PEIM's file handle. Must be the currently
executing PEIM.
@retval EFI_SUCCESS The PEIM was successfully registered for
shadowing.
@retval EFI_ALREADY_STARTED The PEIM was previously
registered for shadowing.
@retval EFI_NOT_FOUND The FileHandle does not refer to a
valid file handle.
**/
EFI_STATUS
EFIAPI
PeiServicesRegisterForShadow (
IN EFI_PEI_FILE_HANDLE FileHandle
)
{
return (*GetPeiServicesTablePointer())->RegisterForShadow (FileHandle);
}
本质上是使用 EFI_PEI_SERVICE 中的RegisterForShadow来实现的,这个函数的作用是注册一个 PEIM, 当内存 Ready时会再次执行。
【参考1】
参考:
1. https://uefi.org/sites/default/files/resources/PI_Spec_1_7_A_final_May1.pdf Platform Initialization Specification, Vol. 1