WinDbg加载符号
0: kd> .reload /i PEICORE=0x`820120
*** WARNING: Unable to verify timestamp for PEICORE
0: kd> lm
start end module name
00820120 0083b2e0 PEICORE T (private pdb symbols) D:\Code\edk2\Build\Ovmf3264\NOOPT_VS2022\IA32\MdeModulePkg\Core\Pei\PeiMain\DEBUG\PeiCore.pdb
fffcc094 fffe58f4 SECMAIN T (private pdb symbols) d:\code\edk2\build\ovmf3264\noopt_vs2022\ia32\ovmfpkg\sec\secmain\debug\SecMain.pdb
SEC -> PEI:
C
VOID
EFIAPI
_ModuleEntryPoint (
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
)
{
ProcessModuleEntryPointList (SecCoreData, PpiList, NULL);
// Should never return
//
ASSERT (FALSE);
CpuDeadLoop ();
}
C
VOID
EFIAPI
ProcessModuleEntryPointList (
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList,
IN VOID *Context
)
{
PeiCore (SecCoreData, PpiList, Context);
}
PeiCore:
C
VOID
EFIAPI
PeiCore (
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreDataPtr,
IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList,
IN VOID *Data
)
{
DEBUG((DEBUG_INFO,"\nEntryPeiCore\n\n"));
__debugbreak();//008205e4
PEI_CORE_INSTANCE PrivateData;
EFI_SEC_PEI_HAND_OFF *SecCoreData;
EFI_SEC_PEI_HAND_OFF NewSecCoreData;
EFI_STATUS Status;
PEI_CORE_TEMP_POINTERS TempPtr;
PEI_CORE_INSTANCE *OldCoreData;
EFI_PEI_CPU_IO_PPI *CpuIo;
EFI_PEI_PCI_CFG2_PPI *PciCfg;
EFI_HOB_HANDOFF_INFO_TABLE *HandoffInformationTable;
EFI_PEI_TEMPORARY_RAM_DONE_PPI *TemporaryRamDonePpi;
UINTN Index;
//
// Retrieve context passed into PEI Core
//
OldCoreData = (PEI_CORE_INSTANCE *)Data;
SecCoreData = (EFI_SEC_PEI_HAND_OFF *)SecCoreDataPtr;
DEBUG((DEBUG_INFO,"SecCoreData @ %p\n",SecCoreData));
//
// Perform PEI Core phase specific actions.
//
if (OldCoreData == NULL) {
//
// If OldCoreData is NULL, means current is the first entry into the PEI Core before memory is available.
//
DEBUG((DEBUG_INFO,"OldData = Null\n"));
DEBUG((DEBUG_INFO,"PrivateData @ %p, Size = %u (0x%x)\n",&PrivateData,sizeof(PEI_CORE_INSTANCE),sizeof(PEI_CORE_INSTANCE)));
DEBUG((DEBUG_INFO,"PrivateData.ServiceTableShadow @ %p, Size = %u (0x%x)\n",&PrivateData.ServiceTableShadow,sizeof(PrivateData.ServiceTableShadow),sizeof(PrivateData.ServiceTableShadow)));
DEBUG((DEBUG_INFO,"gPs @ %p, Size = %u (0x%x)\n",&gPs,sizeof(gPs),sizeof(gPs)));
__debugbreak();
ZeroMem (&PrivateData, sizeof (PEI_CORE_INSTANCE));
//__debugbreak();
PrivateData.Signature = PEI_CORE_HANDLE_SIGNATURE;
CopyMem (&PrivateData.ServiceTableShadow, &gPs, sizeof (gPs));
//__debugbreak();
} else {
//
// Memory is available to the PEI Core. See if the PEI Core has been shadowed to memory yet.
//
if (OldCoreData->ShadowedPeiCore == NULL) {
//
// Fixup the PeiCore's private data
//
OldCoreData->Ps = &OldCoreData->ServiceTableShadow;
OldCoreData->CpuIo = &OldCoreData->ServiceTableShadow.CpuIo;
if (OldCoreData->HeapOffsetPositive) {
OldCoreData->HobList.Raw = (VOID *)(OldCoreData->HobList.Raw + OldCoreData->HeapOffset);
if (OldCoreData->UnknownFvInfo != NULL) {
OldCoreData->UnknownFvInfo = (PEI_CORE_UNKNOW_FORMAT_FV_INFO *)((UINT8 *)OldCoreData->UnknownFvInfo + OldCoreData->HeapOffset);
}
if (OldCoreData->CurrentFvFileHandles != NULL) {
OldCoreData->CurrentFvFileHandles = (EFI_PEI_FILE_HANDLE *)((UINT8 *)OldCoreData->CurrentFvFileHandles + OldCoreData->HeapOffset);
}
if (OldCoreData->PpiData.PpiList.PpiPtrs != NULL) {
OldCoreData->PpiData.PpiList.PpiPtrs = (PEI_PPI_LIST_POINTERS *)((UINT8 *)OldCoreData->PpiData.PpiList.PpiPtrs + OldCoreData->HeapOffset);
}
if (OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs != NULL) {
OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs = (PEI_PPI_LIST_POINTERS *)((UINT8 *)OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs + OldCoreData->HeapOffset);
}
if (OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs != NULL) {
OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs = (PEI_PPI_LIST_POINTERS *)((UINT8 *)OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs + OldCoreData->HeapOffset);
}
OldCoreData->Fv = (PEI_CORE_FV_HANDLE *)((UINT8 *)OldCoreData->Fv + OldCoreData->HeapOffset);
for (Index = 0; Index < OldCoreData->FvCount; Index++) {
if (OldCoreData->Fv[Index].PeimState != NULL) {
OldCoreData->Fv[Index].PeimState = (UINT8 *)OldCoreData->Fv[Index].PeimState + OldCoreData->HeapOffset;
}
if (OldCoreData->Fv[Index].FvFileHandles != NULL) {
OldCoreData->Fv[Index].FvFileHandles = (EFI_PEI_FILE_HANDLE *)((UINT8 *)OldCoreData->Fv[Index].FvFileHandles + OldCoreData->HeapOffset);
}
}
OldCoreData->TempFileGuid = (EFI_GUID *)((UINT8 *)OldCoreData->TempFileGuid + OldCoreData->HeapOffset);
OldCoreData->TempFileHandles = (EFI_PEI_FILE_HANDLE *)((UINT8 *)OldCoreData->TempFileHandles + OldCoreData->HeapOffset);
} else {
OldCoreData->HobList.Raw = (VOID *)(OldCoreData->HobList.Raw - OldCoreData->HeapOffset);
if (OldCoreData->UnknownFvInfo != NULL) {
OldCoreData->UnknownFvInfo = (PEI_CORE_UNKNOW_FORMAT_FV_INFO *)((UINT8 *)OldCoreData->UnknownFvInfo - OldCoreData->HeapOffset);
}
if (OldCoreData->CurrentFvFileHandles != NULL) {
OldCoreData->CurrentFvFileHandles = (EFI_PEI_FILE_HANDLE *)((UINT8 *)OldCoreData->CurrentFvFileHandles - OldCoreData->HeapOffset);
}
if (OldCoreData->PpiData.PpiList.PpiPtrs != NULL) {
OldCoreData->PpiData.PpiList.PpiPtrs = (PEI_PPI_LIST_POINTERS *)((UINT8 *)OldCoreData->PpiData.PpiList.PpiPtrs - OldCoreData->HeapOffset);
}
if (OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs != NULL) {
OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs = (PEI_PPI_LIST_POINTERS *)((UINT8 *)OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs - OldCoreData->HeapOffset);
}
if (OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs != NULL) {
OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs = (PEI_PPI_LIST_POINTERS *)((UINT8 *)OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs - OldCoreData->HeapOffset);
}
OldCoreData->Fv = (PEI_CORE_FV_HANDLE *)((UINT8 *)OldCoreData->Fv - OldCoreData->HeapOffset);
for (Index = 0; Index < OldCoreData->FvCount; Index++) {
if (OldCoreData->Fv[Index].PeimState != NULL) {
OldCoreData->Fv[Index].PeimState = (UINT8 *)OldCoreData->Fv[Index].PeimState - OldCoreData->HeapOffset;
}
if (OldCoreData->Fv[Index].FvFileHandles != NULL) {
OldCoreData->Fv[Index].FvFileHandles = (EFI_PEI_FILE_HANDLE *)((UINT8 *)OldCoreData->Fv[Index].FvFileHandles - OldCoreData->HeapOffset);
}
}
OldCoreData->TempFileGuid = (EFI_GUID *)((UINT8 *)OldCoreData->TempFileGuid - OldCoreData->HeapOffset);
OldCoreData->TempFileHandles = (EFI_PEI_FILE_HANDLE *)((UINT8 *)OldCoreData->TempFileHandles - OldCoreData->HeapOffset);
}
// Force relocating the dispatch table
OldCoreData->DelayedDispatchTable = NULL;
//
// Fixup for PeiService's address
//
SetPeiServicesTablePointer ((CONST EFI_PEI_SERVICES **)&OldCoreData->Ps);
//
// Initialize libraries that the PEI Core is linked against
//
ProcessLibraryConstructorList (NULL, (CONST EFI_PEI_SERVICES **)&OldCoreData->Ps);
//
// Update HandOffHob for new installed permanent memory
//
HandoffInformationTable = OldCoreData->HobList.HandoffInformationTable;
if (OldCoreData->HeapOffsetPositive) {
HandoffInformationTable->EfiEndOfHobList = HandoffInformationTable->EfiEndOfHobList + OldCoreData->HeapOffset;
} else {
HandoffInformationTable->EfiEndOfHobList = HandoffInformationTable->EfiEndOfHobList - OldCoreData->HeapOffset;
}
HandoffInformationTable->EfiMemoryTop = OldCoreData->PhysicalMemoryBegin + OldCoreData->PhysicalMemoryLength;
HandoffInformationTable->EfiMemoryBottom = OldCoreData->PhysicalMemoryBegin;
HandoffInformationTable->EfiFreeMemoryTop = OldCoreData->FreePhysicalMemoryTop;
HandoffInformationTable->EfiFreeMemoryBottom = HandoffInformationTable->EfiEndOfHobList + sizeof (EFI_HOB_GENERIC_HEADER);
//
// We need convert MemoryBaseAddress in memory allocation HOBs
//
ConvertMemoryAllocationHobs (OldCoreData);
//
// We need convert the PPI descriptor's pointer
//
ConvertPpiPointers (SecCoreData, OldCoreData);
//
// After the whole temporary memory is migrated, then we can allocate page in
// permanent memory.
//
OldCoreData->PeiMemoryInstalled = TRUE;
if (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes)) {
DEBUG ((DEBUG_VERBOSE, "Early Migration - PPI lists before temporary RAM evacuation:\n"));
DumpPpiList (OldCoreData);
//
// Migrate installed content from Temporary RAM to Permanent RAM at this
// stage when PEI core still runs from a cached location.
// FVs that doesn't contain PEI_CORE should be migrated here.
//
EvacuateTempRam (OldCoreData, SecCoreData);
DEBUG ((DEBUG_VERBOSE, "Early Migration - PPI lists after temporary RAM evacuation:\n"));
DumpPpiList (OldCoreData);
}
//
// Indicate that PeiCore reenter
//
OldCoreData->PeimDispatcherReenter = TRUE;
if ((PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) && (OldCoreData->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
//
// if Loading Module at Fixed Address is enabled, allocate the PEI code memory range usage bit map array.
// Every bit in the array indicate the status of the corresponding memory page available or not
//
OldCoreData->PeiCodeMemoryRangeUsageBitMap = AllocateZeroPool (((PcdGet32 (PcdLoadFixAddressPeiCodePageNumber)>>6) + 1)*sizeof (UINT64));
}
//
// Shadow PEI Core. When permanent memory is available, shadow
// PEI Core and PEIMs to get high performance.
//
OldCoreData->ShadowedPeiCore = (PEICORE_FUNCTION_POINTER)(UINTN)PeiCore;
if (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
((HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) && PcdGetBool (PcdShadowPeimOnS3Boot)) ||
((HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && PcdGetBool (PcdShadowPeimOnBoot)))
{
OldCoreData->ShadowedPeiCore = ShadowPeiCore (OldCoreData);
}
//
// PEI Core has now been shadowed to memory. Restart PEI Core in memory.
//
OldCoreData->ShadowedPeiCore (SecCoreData, PpiList, OldCoreData);
//
// Should never reach here.
//
ASSERT (FALSE);
CpuDeadLoop ();
UNREACHABLE ();
}
//
// Memory is available to the PEI Core and the PEI Core has been shadowed to memory.
//
CopyMem (&NewSecCoreData, SecCoreDataPtr, sizeof (NewSecCoreData));
SecCoreData = &NewSecCoreData;
CopyMem (&PrivateData, OldCoreData, sizeof (PrivateData));
CpuIo = (VOID *)PrivateData.ServiceTableShadow.CpuIo;
PciCfg = (VOID *)PrivateData.ServiceTableShadow.PciCfg;
CopyMem (&PrivateData.ServiceTableShadow, &gPs, sizeof (gPs));
PrivateData.ServiceTableShadow.CpuIo = CpuIo;
PrivateData.ServiceTableShadow.PciCfg = PciCfg;
}
//
// Cache a pointer to the PEI Services Table that is either in temporary memory or permanent memory
//
PrivateData.Ps = &PrivateData.ServiceTableShadow;
//
// Save PeiServicePointer so that it can be retrieved anywhere.
//
SetPeiServicesTablePointer ((CONST EFI_PEI_SERVICES **)&PrivateData.Ps);
//
// Initialize libraries that the PEI Core is linked against
//
//__debugbreak();
ProcessLibraryConstructorList (NULL, (CONST EFI_PEI_SERVICES **)&PrivateData.Ps);
//
// Initialize PEI Core Services
//
InitializeMemoryServices (&PrivateData, SecCoreData, OldCoreData);
//
// Update performance measurements
//
if (OldCoreData == NULL) {
PERF_EVENT ("SEC"); // Means the end of SEC phase.
//
// If first pass, start performance measurement.
//
PERF_CROSSMODULE_BEGIN ("PEI");
PERF_INMODULE_BEGIN ("PreMem");
} else {
PERF_INMODULE_END ("PreMem");
PERF_INMODULE_BEGIN ("PostMem");
}
//
// Complete PEI Core Service initialization
//
InitializeSecurityServices (&PrivateData.Ps, OldCoreData);
InitializeDispatcherData (&PrivateData, OldCoreData, SecCoreData);
InitializeImageServices (&PrivateData, OldCoreData);
//
// Perform PEI Core Phase specific actions
//
if (OldCoreData == NULL) {
//
// Report Status Code EFI_SW_PC_INIT
//
REPORT_STATUS_CODE (
EFI_PROGRESS_CODE,
(EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT)
);
//
// If SEC provided the PpiList, process it.
//
if (PpiList != NULL) {
ProcessPpiListFromSec ((CONST EFI_PEI_SERVICES **)&PrivateData.Ps, PpiList);
}
} else {
if (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes)) {
//
// When PcdMigrateTemporaryRamFirmwareVolumes is TRUE, alway shadow all
// PEIMs no matter the condition of PcdShadowPeimOnBoot and PcdShadowPeimOnS3Boot
//
DEBUG ((DEBUG_VERBOSE, "PPI lists before temporary RAM evacuation:\n"));
DumpPpiList (&PrivateData);
//
// Migrate installed content from Temporary RAM to Permanent RAM
// FVs containing PEI_CORE should be migrated here.
//
EvacuateTempRam (&PrivateData, SecCoreData);
Status = PeiServicesInstallPpi (&mMigrateTempRamPpi);
ASSERT_EFI_ERROR (Status);
DEBUG ((DEBUG_VERBOSE, "PPI lists after temporary RAM evacuation:\n"));
DumpPpiList (&PrivateData);
}
//
// Try to locate Temporary RAM Done Ppi.
//
Status = PeiServicesLocatePpi (
&gEfiTemporaryRamDonePpiGuid,
0,
NULL,
(VOID **)&TemporaryRamDonePpi
);
if (!EFI_ERROR (Status)) {
//
// Disable the use of Temporary RAM after the transition from Temporary RAM to Permanent RAM is complete.
//
TemporaryRamDonePpi->TemporaryRamDone ();
}
//
// Alert any listeners that there is permanent memory available
//
PERF_INMODULE_BEGIN ("DisMem");
Status = PeiServicesInstallPpi (&mMemoryDiscoveredPpi);
//
// Process the Notify list and dispatch any notifies for the Memory Discovered PPI
//
ProcessDispatchNotifyList (&PrivateData);
PERF_INMODULE_END ("DisMem");
}
//
// Call PEIM dispatcher
//
PeiDispatcher (SecCoreData, &PrivateData);
if (PrivateData.HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) {
//
// Check if InstallPeiMemory service was called on non-S3 resume boot path.
//
ASSERT (PrivateData.PeiMemoryInstalled == TRUE);
}
//
// Measure PEI Core execution time.
//
PERF_INMODULE_END ("PostMem");
//
// Lookup DXE IPL PPI
//
Status = PeiServicesLocatePpi (
&gEfiDxeIplPpiGuid,
0,
NULL,
(VOID **)&TempPtr.DxeIpl
);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
//
// Report status code to indicate DXE IPL PPI could not be found.
//
REPORT_STATUS_CODE (
EFI_ERROR_CODE | EFI_ERROR_MAJOR,
(EFI_SOFTWARE_PEI_CORE | EFI_SW_PEI_CORE_EC_DXEIPL_NOT_FOUND)
);
CpuDeadLoop ();
}
//
// Enter DxeIpl to load Dxe core.
//
DEBUG ((DEBUG_INFO, "DXE IPL Entry\n"));
Status = TempPtr.DxeIpl->Entry (
TempPtr.DxeIpl,
&PrivateData.Ps,
PrivateData.HobList
);
//
// Should never reach here.
//
ASSERT_EFI_ERROR (Status);
CpuDeadLoop ();
UNREACHABLE ();
}
PEI第一次进入
处理PeiServiceTable
此时OldCoreData传入的数据为NULL,进入分支
C
if (OldCoreData == NULL) {
//
// If OldCoreData is NULL, means current is the first entry into the PEI Core before memory is available.
//
DEBUG((DEBUG_INFO,"OldData = Null\n"));
DEBUG((DEBUG_INFO,"PrivateData @ %p, Size = %u (0x%x)\n",&PrivateData,sizeof(PEI_CORE_INSTANCE),sizeof(PEI_CORE_INSTANCE)));
DEBUG((DEBUG_INFO,"PrivateData.ServiceTableShadow @ %p, Size = %u (0x%x)\n",&PrivateData.ServiceTableShadow,sizeof(PrivateData.ServiceTableShadow),sizeof(PrivateData.ServiceTableShadow)));
DEBUG((DEBUG_INFO,"gPs @ %p, Size = %u (0x%x)\n",&gPs,sizeof(gPs),sizeof(gPs)));
__debugbreak();
ZeroMem (&PrivateData, sizeof (PEI_CORE_INSTANCE));
//__debugbreak();
PrivateData.Signature = PEI_CORE_HANDLE_SIGNATURE;
CopyMem (&PrivateData.ServiceTableShadow, &gPs, sizeof (gPs));
//__debugbreak();
} else {
此分支把gPs中覆盖到PrivateData.ServiceTableShadow
gPs:
PrivateData.ServiceTableShadow:
缓存指向 PeiServiceTable的指针并保存
C
//
// Cache a pointer to the PEI Services Table that is either in temporary memory or permanent memory
//
PrivateData.Ps = &PrivateData.ServiceTableShadow;
//
// Save PeiServicePointer so that it can be retrieved anywhere.
//
SetPeiServicesTablePointer ((CONST EFI_PEI_SERVICES **)&PrivateData.Ps);
C
VOID
EFIAPI
SetPeiServicesTablePointer (
IN CONST EFI_PEI_SERVICES **PeiServicesTablePointer
)
{
IA32_DESCRIPTOR Idtr;
ASSERT (PeiServicesTablePointer != NULL);
AsmReadIdtr (&Idtr);
(*(UINTN *)(Idtr.Base - sizeof (UINTN))) = (UINTN)PeiServicesTablePointer;
}
初始化Pei链接库
需要重新初始化Debug串口和AcpiTimer
C
ProcessLibraryConstructorList (NULL, (CONST EFI_PEI_SERVICES **)&PrivateData.Ps);
C
VOID
EFIAPI
ProcessLibraryConstructorList (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
Status = BaseDebugLibSerialPortConstructor ();
ASSERT_RETURN_ERROR (Status);
Status = AcpiTimerLibConstructor ();
ASSERT_RETURN_ERROR (Status);
}
初始化内存服务
为后续内存服务准备数据并建立最小HOB链表
C
//
// Initialize PEI Core Services
//
InitializeMemoryServices (&PrivateData, SecCoreData, OldCoreData);
C
VOID
InitializeMemoryServices (
IN PEI_CORE_INSTANCE *PrivateData,
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
IN PEI_CORE_INSTANCE *OldCoreData
)
{
PrivateData->SwitchStackSignal = FALSE;
//
// First entering PeiCore, following code will initialized some field
// in PeiCore's private data according to hand off data from SEC core.
//
if (OldCoreData == NULL) {
PrivateData->PeiMemoryInstalled = FALSE;
PrivateData->HobList.Raw = SecCoreData->PeiTemporaryRamBase;
PeiCoreBuildHobHandoffInfoTable (
BOOT_WITH_FULL_CONFIGURATION,
(EFI_PHYSICAL_ADDRESS)(UINTN)SecCoreData->PeiTemporaryRamBase,
(UINTN)SecCoreData->PeiTemporaryRamSize
);
//
// Set Ps to point to ServiceTableShadow in Cache
//
PrivateData->Ps = &(PrivateData->ServiceTableShadow);
}
return;
}
C
VOID
PeiCoreBuildHobHandoffInfoTable (
IN EFI_BOOT_MODE BootMode,
IN EFI_PHYSICAL_ADDRESS MemoryBegin,
IN UINT64 MemoryLength
)
{
EFI_HOB_HANDOFF_INFO_TABLE *Hob;
EFI_HOB_GENERIC_HEADER *HobEnd;
Hob = (VOID *)(UINTN)MemoryBegin;
HobEnd = (EFI_HOB_GENERIC_HEADER *)(Hob+1);
Hob->Header.HobType = EFI_HOB_TYPE_HANDOFF;
Hob->Header.HobLength = (UINT16)sizeof (EFI_HOB_HANDOFF_INFO_TABLE);
Hob->Header.Reserved = 0;
HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST;
HobEnd->HobLength = (UINT16)sizeof (EFI_HOB_GENERIC_HEADER);
HobEnd->Reserved = 0;
Hob->Version = EFI_HOB_HANDOFF_TABLE_VERSION;
Hob->BootMode = BootMode;
Hob->EfiMemoryTop = MemoryBegin + MemoryLength;
Hob->EfiMemoryBottom = MemoryBegin;
Hob->EfiFreeMemoryTop = MemoryBegin + MemoryLength;
Hob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS)(UINTN)(HobEnd + 1);
Hob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS)(UINTN)HobEnd;
}
PrivateData->Ps = &(PrivateData->ServiceTableShadow);看似与 PrivateData.Ps = &PrivateData.ServiceTableShadow;重复,实际是为了将全局副本里的指针预先填好,等搬到永久 RAM 后,成为全局映射
打时间戳
C
//
// Update performance measurements
//
if (OldCoreData == NULL) {
PERF_EVENT ("SEC"); // Means the end of SEC phase.
//
// If first pass, start performance measurement.
//
PERF_CROSSMODULE_BEGIN ("PEI");
PERF_INMODULE_BEGIN ("PreMem");
} else {
PERF_INMODULE_END ("PreMem");
PERF_INMODULE_BEGIN ("PostMem");
}
初始化安全服务
C
InitializeSecurityServices (&PrivateData.Ps, OldCoreData);
C
VOID
InitializeSecurityServices (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_CORE_INSTANCE *OldCoreData
)
{
if (OldCoreData == NULL) {
PeiServicesNotifyPpi (&mNotifyList);
}
return;
}
C
EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
&gEfiPeiSecurity2PpiGuid,
SecurityPpiNotifyCallback
};
C
EFI_STATUS
EFIAPI
PeiServicesNotifyPpi (
IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList
)
{
CONST EFI_PEI_SERVICES **PeiServices;
PeiServices = GetPeiServicesTablePointer ();
return (*PeiServices)->NotifyPpi (PeiServices, NotifyList);
}
获取 PeiServicesTable指针
C
CONST EFI_PEI_SERVICES **
EFIAPI
GetPeiServicesTablePointer (
VOID
)
{
CONST EFI_PEI_SERVICES **PeiServices;
IA32_DESCRIPTOR Idtr;
AsmReadIdtr (&Idtr);
PeiServices = (CONST EFI_PEI_SERVICES **)(*(UINTN *)(Idtr.Base - sizeof (UINTN)));
ASSERT (PeiServices != NULL);
return PeiServices;
}
注册 Security2-PPI 上线回调(&mNotifyList)
C
EFI_STATUS
EFIAPI
PeiNotifyPpi (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList
)
{
return InternalPeiNotifyPpi (PeiServices, NotifyList, FALSE);
}
C
EFI_STATUS
InternalPeiNotifyPpi (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList,
IN BOOLEAN Single
)
{
PEI_CORE_INSTANCE *PrivateData;
PEI_CALLBACK_NOTIFY_LIST *CallbackNotifyListPointer;
UINTN CallbackNotifyIndex;
UINTN LastCallbackNotifyCount;
PEI_DISPATCH_NOTIFY_LIST *DispatchNotifyListPointer;
UINTN DispatchNotifyIndex;
UINTN LastDispatchNotifyCount;
VOID *TempPtr;
if (NotifyList == NULL) {
return EFI_INVALID_PARAMETER;
}
PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
CallbackNotifyListPointer = &PrivateData->PpiData.CallbackNotifyList;
CallbackNotifyIndex = CallbackNotifyListPointer->CurrentCount;
LastCallbackNotifyCount = CallbackNotifyIndex;
DispatchNotifyListPointer = &PrivateData->PpiData.DispatchNotifyList;
DispatchNotifyIndex = DispatchNotifyListPointer->CurrentCount;
LastDispatchNotifyCount = DispatchNotifyIndex;
//
// This is loop installs all Notify descriptors in the NotifyList. It is
// terminated by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
// EFI_PEI_NOTIFY_DESCRIPTOR in the list.
//
for ( ; ;) {
//
// If some of the PPI data is invalid restore original Notify PPI database value
//
if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) == 0) {
CallbackNotifyListPointer->CurrentCount = LastCallbackNotifyCount;
DispatchNotifyListPointer->CurrentCount = LastDispatchNotifyCount;
DEBUG ((DEBUG_ERROR, "ERROR -> NotifyPpi: %g %p\n", NotifyList->Guid, NotifyList->Notify));
return EFI_INVALID_PARAMETER;
}
if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK) != 0) {
if (CallbackNotifyIndex >= CallbackNotifyListPointer->MaxCount) {
//
// Run out of room, grow the buffer.
//
TempPtr = AllocateZeroPool (
sizeof (PEI_PPI_LIST_POINTERS) * (CallbackNotifyListPointer->MaxCount + CALLBACK_NOTIFY_GROWTH_STEP)
);
ASSERT (TempPtr != NULL);
CopyMem (
TempPtr,
CallbackNotifyListPointer->NotifyPtrs,
sizeof (PEI_PPI_LIST_POINTERS) * CallbackNotifyListPointer->MaxCount
);
CallbackNotifyListPointer->NotifyPtrs = TempPtr;
CallbackNotifyListPointer->MaxCount = CallbackNotifyListPointer->MaxCount + CALLBACK_NOTIFY_GROWTH_STEP;
}
CallbackNotifyListPointer->NotifyPtrs[CallbackNotifyIndex].Notify = (EFI_PEI_NOTIFY_DESCRIPTOR *)NotifyList;
CallbackNotifyIndex++;
CallbackNotifyListPointer->CurrentCount++;
} else {
if (DispatchNotifyIndex >= DispatchNotifyListPointer->MaxCount) {
//
// Run out of room, grow the buffer.
//
TempPtr = AllocateZeroPool (
sizeof (PEI_PPI_LIST_POINTERS) * (DispatchNotifyListPointer->MaxCount + DISPATCH_NOTIFY_GROWTH_STEP)
);
ASSERT (TempPtr != NULL);
CopyMem (
TempPtr,
DispatchNotifyListPointer->NotifyPtrs,
sizeof (PEI_PPI_LIST_POINTERS) * DispatchNotifyListPointer->MaxCount
);
DispatchNotifyListPointer->NotifyPtrs = TempPtr;
DispatchNotifyListPointer->MaxCount = DispatchNotifyListPointer->MaxCount + DISPATCH_NOTIFY_GROWTH_STEP;
}
DispatchNotifyListPointer->NotifyPtrs[DispatchNotifyIndex].Notify = (EFI_PEI_NOTIFY_DESCRIPTOR *)NotifyList;
DispatchNotifyIndex++;
DispatchNotifyListPointer->CurrentCount++;
}
DEBUG ((DEBUG_INFO, "Register PPI Notify: %g\n", NotifyList->Guid));
if (Single) {
//
// Only single entry in the NotifyList.
//
break;
} else if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST)
{
//
// Continue until the end of the Notify List.
//
break;
}
//
// Go to the next descriptor.
//
NotifyList++;
}
//
// Process any callback level notifies for all previously installed PPIs.
//
ProcessNotify (
PrivateData,
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
0,
PrivateData->PpiData.PpiList.CurrentCount,
LastCallbackNotifyCount,
CallbackNotifyListPointer->CurrentCount
);
return EFI_SUCCESS;
}
增加缓冲区
C
VOID *
EFIAPI
AllocateZeroPool (
IN UINTN AllocationSize
)
{
VOID *Memory;
Memory = AllocatePool (AllocationSize);
if (Memory != NULL) {
Memory = ZeroMem (Memory, AllocationSize);
}
return Memory;
}
C
VOID *
EFIAPI
AllocatePool (
IN UINTN AllocationSize
)
{
EFI_STATUS Status;
VOID *Buffer;
Status = PeiServicesAllocatePool (AllocationSize, &Buffer);
if (EFI_ERROR (Status)) {
Buffer = NULL;
}
return Buffer;
}
C
EFI_STATUS
EFIAPI
PeiServicesAllocatePool (
IN UINTN Size,
OUT VOID **Buffer
)
{
CONST EFI_PEI_SERVICES **PeiServices;
PeiServices = GetPeiServicesTablePointer ();
return (*PeiServices)->AllocatePool (PeiServices, Size, Buffer);
}
由return (*PeiServices)->AllocatePool (PeiServices, Size, Buffer);调用
C
EFI_STATUS
EFIAPI
PeiAllocatePool (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN UINTN Size,
OUT VOID **Buffer
)
{
EFI_STATUS Status;
EFI_HOB_MEMORY_POOL *Hob;
//
// If some "post-memory" PEIM wishes to allocate larger pool,
// it should use AllocatePages service instead.
//
//
// Generally, the size of heap in temporary memory does not exceed 64K,
// HobLength is multiples of 8 bytes, so the maximum size of pool is 0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL)
//
if (Size > (0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL))) {
return EFI_OUT_OF_RESOURCES;
}
Status = PeiServicesCreateHob (
EFI_HOB_TYPE_MEMORY_POOL,
(UINT16)(sizeof (EFI_HOB_MEMORY_POOL) + Size),
(VOID **)&Hob
);
if (EFI_ERROR (Status)) {
*Buffer = NULL;
} else {
*Buffer = Hob + 1;
}
return Status;
}
创建HOB节点
C
EFI_STATUS
EFIAPI
PeiServicesCreateHob (
IN UINT16 Type,
IN UINT16 Length,
OUT VOID **Hob
)
{
CONST EFI_PEI_SERVICES **PeiServices;
PeiServices = GetPeiServicesTablePointer ();
return (*PeiServices)->CreateHob (PeiServices, Type, Length, Hob);
}
把通知指针整体替换到新缓冲区
C
DispatchNotifyListPointer->NotifyPtrs = TempPtr;
处理回调级别通知(未有实际内容执行)
C
ProcessNotify (
PrivateData,
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
0,
PrivateData->PpiData.PpiList.CurrentCount,
LastCallbackNotifyCount,
CallbackNotifyListPointer->CurrentCount
);
C
VOID
ProcessNotify (
IN PEI_CORE_INSTANCE *PrivateData,
IN UINTN NotifyType,
IN INTN InstallStartIndex,
IN INTN InstallStopIndex,
IN INTN NotifyStartIndex,
IN INTN NotifyStopIndex
)
{
INTN Index1;
INTN Index2;
EFI_GUID *SearchGuid;
EFI_GUID *CheckGuid;
EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor;
for (Index1 = NotifyStartIndex; Index1 < NotifyStopIndex; Index1++) {
if (NotifyType == EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK) {
NotifyDescriptor = PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index1].Notify;
} else {
NotifyDescriptor = PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index1].Notify;
}
CheckGuid = NotifyDescriptor->Guid;
for (Index2 = InstallStartIndex; Index2 < InstallStopIndex; Index2++) {
SearchGuid = PrivateData->PpiData.PpiList.PpiPtrs[Index2].Ppi->Guid;
//
// Don't use CompareGuid function here for performance reasons.
// Instead we compare the GUID as INT32 at a time and branch
// on the first failed comparison.
//
if ((((INT32 *)SearchGuid)[0] == ((INT32 *)CheckGuid)[0]) &&
(((INT32 *)SearchGuid)[1] == ((INT32 *)CheckGuid)[1]) &&
(((INT32 *)SearchGuid)[2] == ((INT32 *)CheckGuid)[2]) &&
(((INT32 *)SearchGuid)[3] == ((INT32 *)CheckGuid)[3]))
{
DEBUG ((
DEBUG_INFO,
"Notify: PPI Guid: %g, Peim notify entry point: %p\n",
SearchGuid,
NotifyDescriptor->Notify
));
NotifyDescriptor->Notify (
(EFI_PEI_SERVICES **)GetPeiServicesTablePointer (),
NotifyDescriptor,
(PrivateData->PpiData.PpiList.PpiPtrs[Index2].Ppi)->Ppi
);
}
}
}
}
初始化调度器数据
C
InitializeDispatcherData (&PrivateData, OldCoreData, SecCoreData);\
C
VOID
InitializeDispatcherData (
IN PEI_CORE_INSTANCE *PrivateData,
IN PEI_CORE_INSTANCE *OldCoreData,
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
)
{
if (OldCoreData == NULL) {
PrivateData->PeimDispatcherReenter = FALSE;
PeiInitializeFv (PrivateData, SecCoreData);
} else {
PeiReinitializeFv (PrivateData);
}
return;
}
初始化 PeiCore FV列表
C
VOID
PeiInitializeFv (
IN PEI_CORE_INSTANCE *PrivateData,
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
)
{
EFI_STATUS Status;
EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
EFI_PEI_FV_HANDLE FvHandle;
EFI_FIRMWARE_VOLUME_HEADER *BfvHeader;
//
// Install FV_PPI for FFS2 file system.
//
PeiServicesInstallPpi (&mPeiFfs2FvPpiList);
//
// Install FV_PPI for FFS3 file system.
//
PeiServicesInstallPpi (&mPeiFfs3FvPpiList);
BfvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
//
// The FV_PPI in BFV's format should be installed.
//
Status = PeiServicesLocatePpi (
&BfvHeader->FileSystemGuid,
0,
NULL,
(VOID **)&FvPpi
);
ASSERT_EFI_ERROR (Status);
//
// Get handle of BFV
//
Status = FvPpi->ProcessVolume (
FvPpi,
SecCoreData->BootFirmwareVolumeBase,
(UINTN)BfvHeader->FvLength,
&FvHandle
);
ASSERT_EFI_ERROR (Status);
PrivateData->Fv = AllocateZeroPool (sizeof (PEI_CORE_FV_HANDLE) * FV_GROWTH_STEP);
ASSERT (PrivateData->Fv != NULL);
PrivateData->MaxFvCount = FV_GROWTH_STEP;
//
// Update internal PEI_CORE_FV array.
//
PrivateData->Fv[PrivateData->FvCount].FvHeader = BfvHeader;
PrivateData->Fv[PrivateData->FvCount].FvPpi = FvPpi;
PrivateData->Fv[PrivateData->FvCount].FvHandle = FvHandle;
PrivateData->Fv[PrivateData->FvCount].AuthenticationStatus = 0;
DEBUG ((
DEBUG_INFO,
"The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
(UINT32)PrivateData->FvCount,
(VOID *)BfvHeader,
(UINT32)BfvHeader->FvLength,
FvHandle
));
PrivateData->FvCount++;
//
// Post a call-back for the FvInfoPPI and FvInfo2PPI services to expose
// additional FVs to PeiCore.
//
Status = PeiServicesNotifyPpi (mNotifyOnFvInfoList);
ASSERT_EFI_ERROR (Status);
}
为 FFS2 文件系统安装 FV PPI (&mPeiFfs2FvPpiList)
C
EFI_PEI_PPI_DESCRIPTOR mPeiFfs2FvPpiList = {
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gEfiFirmwareFileSystem2Guid,
&mPeiFfs2FwVol.Fv
};
获取 PeiServicesTable 指针
C
EFI_STATUS
EFIAPI
PeiServicesInstallPpi (
IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
)
{
CONST EFI_PEI_SERVICES **PeiServices;
PeiServices = GetPeiServicesTablePointer ();
return (*PeiServices)->InstallPpi (PeiServices, PpiList);
}
安装 PPI
C
EFI_STATUS
EFIAPI
PeiInstallPpi (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
)
{
return InternalPeiInstallPpi (PeiServices, PpiList, FALSE);
}
C
EFI_STATUS
InternalPeiInstallPpi (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList,
IN BOOLEAN Single
)
{
PEI_CORE_INSTANCE *PrivateData;
PEI_PPI_LIST *PpiListPointer;
UINTN Index;
UINTN LastCount;
VOID *TempPtr;
if (PpiList == NULL) {
return EFI_INVALID_PARAMETER;
}
PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
PpiListPointer = &PrivateData->PpiData.PpiList;
Index = PpiListPointer->CurrentCount;
LastCount = Index;
//
// This is loop installs all PPI descriptors in the PpiList. It is terminated
// by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
// EFI_PEI_PPI_DESCRIPTOR in the list.
//
for ( ; ;) {
//
// Check if it is a valid PPI.
// If not, rollback list to exclude all in this list.
// Try to indicate which item failed.
//
if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_PPI) == 0) {
PpiListPointer->CurrentCount = LastCount;
DEBUG ((DEBUG_ERROR, "ERROR -> InstallPpi: %g %p\n", PpiList->Guid, PpiList->Ppi));
return EFI_INVALID_PARAMETER;
}
if (Index >= PpiListPointer->MaxCount) {
//
// Run out of room, grow the buffer.
//
TempPtr = AllocateZeroPool (
sizeof (PEI_PPI_LIST_POINTERS) * (PpiListPointer->MaxCount + PPI_GROWTH_STEP)
);
ASSERT (TempPtr != NULL);
CopyMem (
TempPtr,
PpiListPointer->PpiPtrs,
sizeof (PEI_PPI_LIST_POINTERS) * PpiListPointer->MaxCount
);
PpiListPointer->PpiPtrs = TempPtr;
PpiListPointer->MaxCount = PpiListPointer->MaxCount + PPI_GROWTH_STEP;
}
DEBUG ((DEBUG_INFO, "Install PPI: %g\n", PpiList->Guid));
PpiListPointer->PpiPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR *)PpiList;
Index++;
PpiListPointer->CurrentCount++;
if (Single) {
//
// Only single entry in the PpiList.
//
break;
} else if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST)
{
//
// Continue until the end of the PPI List.
//
break;
}
//
// Go to the next descriptor.
//
PpiList++;
}
//
// Process any callback level notifies for newly installed PPIs.
//
ProcessNotify (
PrivateData,
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
LastCount,
PpiListPointer->CurrentCount,
0,
PrivateData->PpiData.CallbackNotifyList.CurrentCount
);
return EFI_SUCCESS;
}
为 FFS3 文件系统安装 FV PPI (&mPeiFfs3FvPpiList)
内容与FFS2一致
设置BootFVHeader
C
BfvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
确认BFV的PPI是否被成功安装
C
Status = PeiServicesLocatePpi (
&BfvHeader->FileSystemGuid,
0,
NULL,
(VOID **)&FvPpi
);
ASSERT_EFI_ERROR (Status);
C
EFI_STATUS
EFIAPI
PeiServicesLocatePpi (
IN CONST EFI_GUID *Guid,
IN UINTN Instance,
IN OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor OPTIONAL,
IN OUT VOID **Ppi
)
{
CONST EFI_PEI_SERVICES **PeiServices;
PeiServices = GetPeiServicesTablePointer ();
return (*PeiServices)->LocatePpi (PeiServices, Guid, Instance, PpiDescriptor, Ppi);
}
C
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
)
{
PEI_CORE_INSTANCE *PrivateData;
UINTN Index;
EFI_GUID *CheckGuid;
EFI_PEI_PPI_DESCRIPTOR *TempPtr;
PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
//
// Search the data base for the matching instance of the GUIDed PPI.
//
for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
TempPtr = PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi;
CheckGuid = TempPtr->Guid;
//
// Don't use CompareGuid function here for performance reasons.
// Instead we compare the GUID as INT32 at a time and branch
// on the first failed comparison.
//
if ((((INT32 *)Guid)[0] == ((INT32 *)CheckGuid)[0]) &&
(((INT32 *)Guid)[1] == ((INT32 *)CheckGuid)[1]) &&
(((INT32 *)Guid)[2] == ((INT32 *)CheckGuid)[2]) &&
(((INT32 *)Guid)[3] == ((INT32 *)CheckGuid)[3]))
{
if (Instance == 0) {
if (PpiDescriptor != NULL) {
*PpiDescriptor = TempPtr;
}
if (Ppi != NULL) {
*Ppi = TempPtr->Ppi;
}
return EFI_SUCCESS;
}
Instance--;
}
}
return EFI_NOT_FOUND;
}
获取卷句柄FvHandle
C
//
// Get handle of BFV
//
Status = FvPpi->ProcessVolume (
FvPpi,
SecCoreData->BootFirmwareVolumeBase,
(UINTN)BfvHeader->FvLength,
&FvHandle
);
ASSERT_EFI_ERROR (Status);
C
EFI_STATUS
EFIAPI
PeiFfsFvPpiProcessVolume (
IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
IN VOID *Buffer,
IN UINTN BufferSize,
OUT EFI_PEI_FV_HANDLE *FvHandle
)
{
EFI_STATUS Status;
ASSERT (FvHandle != NULL);
if (Buffer == NULL) {
return EFI_VOLUME_CORRUPTED;
}
//
// The build-in EFI_PEI_FIRMWARE_VOLUME_PPI for FFS2/FFS3 support memory-mapped
// FV image and the handle is pointed to FV image's buffer.
//
*FvHandle = (EFI_PEI_FV_HANDLE)Buffer;
//
// Do verify for given FV buffer.
//
Status = VerifyFv ((EFI_FIRMWARE_VOLUME_HEADER *)Buffer);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Fail to verify FV which address is 0x%11p", Buffer));
return EFI_VOLUME_CORRUPTED;
}
return EFI_SUCCESS;
}
扩大pool更新FvCount=0的数据并计数增加
C
PrivateData->Fv = AllocateZeroPool (sizeof (PEI_CORE_FV_HANDLE) * FV_GROWTH_STEP);
ASSERT (PrivateData->Fv != NULL);
PrivateData->MaxFvCount = FV_GROWTH_STEP;
//
// Update internal PEI_CORE_FV array.
//
PrivateData->Fv[PrivateData->FvCount].FvHeader = BfvHeader;
PrivateData->Fv[PrivateData->FvCount].FvPpi = FvPpi;
PrivateData->Fv[PrivateData->FvCount].FvHandle = FvHandle;
PrivateData->Fv[PrivateData->FvCount].AuthenticationStatus = 0;
DEBUG ((
DEBUG_INFO,
"The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
(UINT32)PrivateData->FvCount,
(VOID *)BfvHeader,
(UINT32)BfvHeader->FvLength,
FvHandle
));
PrivateData->FvCount++;
注册 FV 信息上线回调 (mNotifyOnFvInfoList)
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
}
};
与之前的List不同,是结构体数组,不需要写成&mNotifyOnFvInfoList
C
Status = PeiServicesNotifyPpi (mNotifyOnFvInfoList);
ASSERT_EFI_ERROR (Status);
初始化映像服务
安装PEI文件加载PPI(&gPpiLoadFilePpiList)
C
InitializeImageServices (&PrivateData, OldCoreData);
C
VOID
InitializeImageServices (
IN PEI_CORE_INSTANCE *PrivateData,
IN PEI_CORE_INSTANCE *OldCoreData
)
{
if (OldCoreData == NULL) {
//
// The first time we are XIP (running from FLASH). We need to remember the
// FLASH address so we can reinstall the memory version that runs faster
//
PrivateData->XipLoadFile = &gPpiLoadFilePpiList;
PeiServicesInstallPpi (PrivateData->XipLoadFile);
} else {
//
// 2nd time we are running from memory so replace the XIP version with the
// new memory version.
//
PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);
}
}
C
EFI_PEI_PPI_DESCRIPTOR gPpiLoadFilePpiList = {
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gEfiPeiLoadFilePpiGuid,
&mPeiLoadImagePpi
};
报告状态码
C
REPORT_STATUS_CODE (
EFI_PROGRESS_CODE,
(EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT)
);
C
EFI_STATUS
EFIAPI
ReportStatusCode (
IN EFI_STATUS_CODE_TYPE Type,
IN EFI_STATUS_CODE_VALUE Value
)
{
return InternalReportStatusCode (Type, Value, 0, &gEfiCallerIdGuid, NULL);
}
C
EFI_STATUS
InternalReportStatusCode (
IN EFI_STATUS_CODE_TYPE Type,
IN EFI_STATUS_CODE_VALUE Value,
IN UINT32 Instance,
IN CONST EFI_GUID *CallerId OPTIONAL,
IN EFI_STATUS_CODE_DATA *Data OPTIONAL
)
{
CONST EFI_PEI_SERVICES **PeiServices;
EFI_STATUS Status;
if ((ReportProgressCodeEnabled () && (((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE)) ||
(ReportErrorCodeEnabled () && (((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE)) ||
(ReportDebugCodeEnabled () && (((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE)))
{
PeiServices = GetPeiServicesTablePointer ();
Status = (*PeiServices)->ReportStatusCode (
PeiServices,
Type,
Value,
Instance,
(EFI_GUID *)CallerId,
Data
);
if (Status == EFI_NOT_AVAILABLE_YET) {
Status = OemHookStatusCodeInitialize ();
if (!EFI_ERROR (Status)) {
return OemHookStatusCodeReport (Type, Value, Instance, (EFI_GUID *)CallerId, Data);
}
}
return Status;
}
return EFI_UNSUPPORTED;
}
C
EFI_STATUS
EFIAPI
PeiReportStatusCode (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN EFI_STATUS_CODE_TYPE CodeType,
IN EFI_STATUS_CODE_VALUE Value,
IN UINT32 Instance,
IN CONST EFI_GUID *CallerId,
IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
)
{
EFI_STATUS Status;
EFI_PEI_PROGRESS_CODE_PPI *StatusCodePpi;
//
// Locate StatusCode Ppi.
//
Status = PeiServicesLocatePpi (
&gEfiPeiStatusCodePpiGuid,
0,
NULL,
(VOID **)&StatusCodePpi
);
if (!EFI_ERROR (Status)) {
Status = StatusCodePpi->ReportStatusCode (
PeiServices,
CodeType,
Value,
Instance,
CallerId,
Data
);
return Status;
}
return EFI_NOT_AVAILABLE_YET;
}
定位状态码PPI
C
EFI_STATUS
EFIAPI
PeiServicesLocatePpi (
IN CONST EFI_GUID *Guid,
IN UINTN Instance,
IN OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor OPTIONAL,
IN OUT VOID **Ppi
)
{
CONST EFI_PEI_SERVICES **PeiServices;
PeiServices = GetPeiServicesTablePointer ();
return (*PeiServices)->LocatePpi (PeiServices, Guid, Instance, PpiDescriptor, Ppi);
}
C
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
)
{
PEI_CORE_INSTANCE *PrivateData;
UINTN Index;
EFI_GUID *CheckGuid;
EFI_PEI_PPI_DESCRIPTOR *TempPtr;
PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
//
// Search the data base for the matching instance of the GUIDed PPI.
//
for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
TempPtr = PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi;
CheckGuid = TempPtr->Guid;
//
// Don't use CompareGuid function here for performance reasons.
// Instead we compare the GUID as INT32 at a time and branch
// on the first failed comparison.
//
if ((((INT32 *)Guid)[0] == ((INT32 *)CheckGuid)[0]) &&
(((INT32 *)Guid)[1] == ((INT32 *)CheckGuid)[1]) &&
(((INT32 *)Guid)[2] == ((INT32 *)CheckGuid)[2]) &&
(((INT32 *)Guid)[3] == ((INT32 *)CheckGuid)[3]))
{
if (Instance == 0) {
if (PpiDescriptor != NULL) {
*PpiDescriptor = TempPtr;
}
if (Ppi != NULL) {
*Ppi = TempPtr->Ppi;
}
return EFI_SUCCESS;
}
Instance--;
}
}
return EFI_NOT_FOUND;
}
没有定位到状态码PPI
通过 OEM Hook 状态代码库报告状态码
C
if (Status == EFI_NOT_AVAILABLE_YET) {
Status = OemHookStatusCodeInitialize ();
if (!EFI_ERROR (Status)) {
return OemHookStatusCodeReport (Type, Value, Instance, (EFI_GUID *)CallerId, Data);
}
}
处理SEC提供的PpiList
C
VOID
ProcessPpiListFromSec (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
)
{
EFI_STATUS Status;
EFI_SEC_HOB_DATA_PPI *SecHobDataPpi;
EFI_HOB_GENERIC_HEADER *SecHobList;
for ( ; ;) {
if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) != 0) {
//
// It is a notification PPI.
//
Status = InternalPeiNotifyPpi (PeiServices, (CONST EFI_PEI_NOTIFY_DESCRIPTOR *)PpiList, TRUE);
ASSERT_EFI_ERROR (Status);
} else {
//
// It is a normal PPI.
//
Status = InternalPeiInstallPpi (PeiServices, PpiList, TRUE);
ASSERT_EFI_ERROR (Status);
}
if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) == EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
//
// Continue until the end of the PPI List.
//
break;
}
PpiList++;
}
//
// If the EFI_SEC_HOB_DATA_PPI is in the list of PPIs passed to the PEI entry point,
// the PEI Foundation will call the GetHobs() member function and install all HOBs
// returned into the HOB list. It does this after installing all PPIs passed from SEC
// into the PPI database and before dispatching any PEIMs.
//
Status = PeiLocatePpi (PeiServices, &gEfiSecHobDataPpiGuid, 0, NULL, (VOID **)&SecHobDataPpi);
if (!EFI_ERROR (Status)) {
Status = SecHobDataPpi->GetHobs (SecHobDataPpi, &SecHobList);
if (!EFI_ERROR (Status)) {
Status = PeiInstallSecHobData (PeiServices, SecHobList);
ASSERT_EFI_ERROR (Status);
}
}
}
判断PPI类型并注册回调或安装接口
C
if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) != 0) {
//
// It is a notification PPI.
//
Status = InternalPeiNotifyPpi (PeiServices, (CONST EFI_PEI_NOTIFY_DESCRIPTOR *)PpiList, TRUE);
ASSERT_EFI_ERROR (Status);
} else {
//
// It is a normal PPI.
//
Status = InternalPeiInstallPpi (PeiServices, PpiList, TRUE);
ASSERT_EFI_ERROR (Status);
}
定位SecHobDataPpi决定是否把数据块安装到HOB链表
C
Status = PeiLocatePpi (PeiServices, &gEfiSecHobDataPpiGuid, 0, NULL, (VOID **)&SecHobDataPpi);
if (!EFI_ERROR (Status)) {
Status = SecHobDataPpi->GetHobs (SecHobDataPpi, &SecHobList);
if (!EFI_ERROR (Status)) {
Status = PeiInstallSecHobData (PeiServices, SecHobList);
ASSERT_EFI_ERROR (Status);
}
}
这里并没有在传递给 PEI 入口点的 PPI 列表中定位到SecHobDataPpi
调用PEIM调度器
C
PeiDispatcher (SecCoreData, &PrivateData);
C
VOID
PeiDispatcher (
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
IN PEI_CORE_INSTANCE *Private
)
{
EFI_STATUS Status;
UINT32 Index1;
UINT32 Index2;
CONST EFI_PEI_SERVICES **PeiServices;
EFI_PEI_FILE_HANDLE PeimFileHandle;
UINTN FvCount;
UINTN PeimCount;
UINT32 AuthenticationState;
EFI_PHYSICAL_ADDRESS EntryPoint;
EFI_PEIM_ENTRY_POINT2 PeimEntryPoint;
UINTN SaveCurrentPeimCount;
UINTN SaveCurrentFvCount;
EFI_PEI_FILE_HANDLE SaveCurrentFileHandle;
EFI_FV_FILE_INFO FvFileInfo;
PEI_CORE_FV_HANDLE *CoreFvHandle;
EFI_HOB_GUID_TYPE *GuidHob;
UINT32 TableSize;
PeiServices = (CONST EFI_PEI_SERVICES **)&Private->Ps;
PeimEntryPoint = NULL;
PeimFileHandle = NULL;
EntryPoint = 0;
if (Private->DelayedDispatchTable == NULL) {
GuidHob = GetFirstGuidHob (&gEfiDelayedDispatchTableGuid);
if (GuidHob != NULL) {
Private->DelayedDispatchTable = (DELAYED_DISPATCH_TABLE *)(GET_GUID_HOB_DATA (GuidHob));
} else {
TableSize = sizeof (DELAYED_DISPATCH_TABLE) + ((DELAYED_DISPATCH_MAX_ENTRIES - 1) * sizeof (DELAYED_DISPATCH_ENTRY));
Private->DelayedDispatchTable = BuildGuidHob (&gEfiDelayedDispatchTableGuid, TableSize);
if (Private->DelayedDispatchTable != NULL) {
ZeroMem (Private->DelayedDispatchTable, TableSize);
Status = PeiServicesInstallPpi (&mDelayedDispatchDesc);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a Failed to install Delayed Dispatch PPI: %r!\n", __func__, Status));
ASSERT_EFI_ERROR (Status);
} else {
Status = PeiServicesNotifyPpi (&mDelayedDispatchNotifyDesc);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a Failed to notify Delayed Dispatch on End of Pei: %r!\n", __func__, Status));
ASSERT_EFI_ERROR (Status);
}
}
}
}
}
if ((Private->PeiMemoryInstalled) &&
(PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
(Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||
PcdGetBool (PcdShadowPeimOnS3Boot))
)
{
//
// Once real memory is available, shadow the RegisterForShadow modules. And meanwhile
// update the modules' status from PEIM_STATE_REGISTER_FOR_SHADOW to PEIM_STATE_DONE.
//
SaveCurrentPeimCount = Private->CurrentPeimCount;
SaveCurrentFvCount = Private->CurrentPeimFvCount;
SaveCurrentFileHandle = Private->CurrentFileHandle;
for (Index1 = 0; Index1 < Private->FvCount; Index1++) {
for (Index2 = 0; Index2 < Private->Fv[Index1].PeimCount; Index2++) {
if (Private->Fv[Index1].PeimState[Index2] == PEIM_STATE_REGISTER_FOR_SHADOW) {
PeimFileHandle = Private->Fv[Index1].FvFileHandles[Index2];
Private->CurrentFileHandle = PeimFileHandle;
Private->CurrentPeimFvCount = Index1;
Private->CurrentPeimCount = Index2;
Status = PeiLoadImage (
(CONST EFI_PEI_SERVICES **)&Private->Ps,
PeimFileHandle,
PEIM_STATE_REGISTER_FOR_SHADOW,
&EntryPoint,
&AuthenticationState
);
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);
}
//
// Process the Notify list and dispatch any notifies for
// newly installed PPIs.
//
ProcessDispatchNotifyList (Private);
}
}
}
Private->CurrentFileHandle = SaveCurrentFileHandle;
Private->CurrentPeimFvCount = SaveCurrentFvCount;
Private->CurrentPeimCount = SaveCurrentPeimCount;
}
//
// This is the main dispatch loop. It will search known FVs for PEIMs and
// attempt to dispatch them. If any PEIM gets dispatched through a single
// pass of the dispatcher, it will start over from the BFV again to see
// if any new PEIMs dependencies got satisfied. With a well ordered
// FV where PEIMs are found in the order their dependencies are also
// satisfied, this dispatcher should run only once.
//
do {
//
// In case that reenter PeiCore happens, the last pass record is still available.
//
if (!Private->PeimDispatcherReenter) {
Private->PeimNeedingDispatch = FALSE;
Private->PeimDispatchOnThisPass = FALSE;
} else {
Private->PeimDispatcherReenter = FALSE;
}
for (FvCount = Private->CurrentPeimFvCount; FvCount < Private->FvCount; FvCount++) {
CoreFvHandle = FindNextCoreFvHandle (Private, FvCount);
ASSERT (CoreFvHandle != NULL);
//
// If the FV has corresponding EFI_PEI_FIRMWARE_VOLUME_PPI instance, then dispatch it.
//
if (CoreFvHandle->FvPpi == NULL) {
continue;
}
Private->CurrentPeimFvCount = FvCount;
if (Private->CurrentPeimCount == 0) {
//
// When going through each FV, at first, search Apriori file to
// reorder all PEIMs to ensure the PEIMs in Apriori file to get
// dispatch at first.
//
DiscoverPeimsAndOrderWithApriori (Private, CoreFvHandle);
}
//
// Start to dispatch all modules within the current FV.
//
for (PeimCount = Private->CurrentPeimCount;
PeimCount < Private->Fv[FvCount].PeimCount;
PeimCount++)
{
Private->CurrentPeimCount = PeimCount;
PeimFileHandle = Private->CurrentFileHandle = Private->CurrentFvFileHandles[PeimCount];
if (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_NOT_DISPATCHED) {
if (!DepexSatisfied (Private, PeimFileHandle, PeimCount)) {
Private->PeimNeedingDispatch = TRUE;
} else {
Status = CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, PeimFileHandle, &FvFileInfo);
ASSERT_EFI_ERROR (Status);
if (FvFileInfo.FileType == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
//
// For FV type file, Produce new FvInfo PPI and FV HOB
//
Status = ProcessFvFile (Private, &Private->Fv[FvCount], PeimFileHandle);
if (Status == EFI_SUCCESS) {
//
// PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
//
Private->Fv[FvCount].PeimState[PeimCount]++;
Private->PeimDispatchOnThisPass = TRUE;
} else {
//
// The related GuidedSectionExtraction/Decompress PPI for the
// encapsulated FV image section may be installed in the rest
// of this do-while loop, so need to make another pass.
//
Private->PeimNeedingDispatch = TRUE;
}
} else {
//
// For PEIM driver, Load its entry point
//
Status = PeiLoadImage (
PeiServices,
PeimFileHandle,
PEIM_STATE_NOT_DISPATCHED,
&EntryPoint,
&AuthenticationState
);
if (Status == EFI_SUCCESS) {
//
// The PEIM has its dependencies satisfied, and its entry point
// has been found, so invoke it.
//
PERF_START_IMAGE_BEGIN (PeimFileHandle);
REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
EFI_PROGRESS_CODE,
(EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN),
(VOID *)(&PeimFileHandle),
sizeof (PeimFileHandle)
);
Status = VerifyPeim (Private, CoreFvHandle->FvHandle, PeimFileHandle, AuthenticationState);
if (Status != EFI_SECURITY_VIOLATION) {
//
// PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
//
Private->Fv[FvCount].PeimState[PeimCount]++;
//
// Call the PEIM entry point for PEIM driver
//
PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices);
Private->PeimDispatchOnThisPass = TRUE;
} else {
//
// The related GuidedSectionExtraction PPI for the
// signed PEIM image section may be installed in the rest
// of this do-while loop, so need to make another pass.
//
Private->PeimNeedingDispatch = TRUE;
}
REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
EFI_PROGRESS_CODE,
(EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END),
(VOID *)(&PeimFileHandle),
sizeof (PeimFileHandle)
);
PERF_START_IMAGE_END (PeimFileHandle);
}
}
PeiCheckAndSwitchStack (SecCoreData, Private);
//
// Process the Notify list and dispatch any notifies for
// newly installed PPIs.
//
ProcessDispatchNotifyList (Private);
//
// Recheck SwitchStackSignal after ProcessDispatchNotifyList()
// in case PeiInstallPeiMemory() is done in a callback with
// EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH.
//
PeiCheckAndSwitchStack (SecCoreData, Private);
if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW) && \
(PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
(Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||
PcdGetBool (PcdShadowPeimOnS3Boot))
)
{
//
// If memory is available we shadow images by default for performance reasons.
// We call the entry point a 2nd time so the module knows it's shadowed.
//
// PERF_START (PeiServices, L"PEIM", PeimFileHandle, 0);
if ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && !PcdGetBool (PcdShadowPeimOnBoot) &&
!PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes))
{
//
// Load PEIM into Memory for Register for shadow PEIM.
//
Status = PeiLoadImage (
PeiServices,
PeimFileHandle,
PEIM_STATE_REGISTER_FOR_SHADOW,
&EntryPoint,
&AuthenticationState
);
if (Status == EFI_SUCCESS) {
PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
}
}
ASSERT (PeimEntryPoint != NULL);
PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices);
// PERF_END (PeiServices, L"PEIM", PeimFileHandle, 0);
//
// PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE
//
Private->Fv[FvCount].PeimState[PeimCount]++;
//
// Process the Notify list and dispatch any notifies for
// newly installed PPIs.
//
ProcessDispatchNotifyList (Private);
}
}
}
// Dispatch pending delalyed dispatch requests
if (Private->DelayedDispatchTable != NULL) {
if (DelayedDispatchDispatcher (Private->DelayedDispatchTable, NULL)) {
ProcessDispatchNotifyList (Private);
}
}
}
//
// Before walking through the next FV, we should set them to NULL/0 to
// start at the beginning of the next FV.
//
Private->CurrentFileHandle = NULL;
Private->CurrentPeimCount = 0;
Private->CurrentFvFileHandles = NULL;
Private->AprioriCount = 0;
}
//
// Before making another pass, we should set it to 0 to
// go through all the FVs.
//
Private->CurrentPeimFvCount = 0;
//
// PeimNeedingDispatch being TRUE means we found a PEIM/FV that did not get
// dispatched. So we need to make another pass
//
// PeimDispatchOnThisPass being TRUE means we dispatched a PEIM/FV on this
// pass. If we did not dispatch a PEIM/FV there is no point in trying again
// as it will fail the next time too (nothing has changed).
//
// Also continue dispatch loop if there are outstanding delay-
// dispatch registrations still running.
} while ((Private->PeimNeedingDispatch && Private->PeimDispatchOnThisPass) ||
(Private->DelayedDispatchTable->Count > 0));
}
从HOB链表里获取第一个匹配的GUID-HOB节点
C
GuidHob = GetFirstGuidHob (&gEfiDelayedDispatchTableGuid);
C
VOID *
EFIAPI
GetFirstGuidHob (
IN CONST EFI_GUID *Guid
)
{
VOID *HobList;
HobList = GetHobList ();
return GetNextGuidHob (Guid, HobList);
}
获取HOB链表
C
VOID *
EFIAPI
GetHobList (
VOID
)
{
EFI_STATUS Status;
VOID *HobList;
Status = PeiServicesGetHobList (&HobList);
ASSERT_EFI_ERROR (Status);
ASSERT (HobList != NULL);
return HobList;
}
C
EFI_STATUS
EFIAPI
PeiServicesGetHobList (
OUT VOID **HobList
)
{
CONST EFI_PEI_SERVICES **PeiServices;
PeiServices = GetPeiServicesTablePointer ();
return (*PeiServices)->GetHobList (PeiServices, HobList);
}
C
EFI_STATUS
EFIAPI
PeiGetHobList (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN OUT VOID **HobList
)
{
PEI_CORE_INSTANCE *PrivateData;
//
// Only check this parameter in debug mode
//
DEBUG_CODE_BEGIN ();
if (HobList == NULL) {
return EFI_INVALID_PARAMETER;
}
DEBUG_CODE_END ();
PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
*HobList = PrivateData->HobList.Raw;
return EFI_SUCCESS;
}
顺序遍历直到匹配(先节点type再GUID)
C
VOID *
EFIAPI
GetNextGuidHob (
IN CONST EFI_GUID *Guid,
IN CONST VOID *HobStart
)
{
EFI_PEI_HOB_POINTERS GuidHob;
GuidHob.Raw = (UINT8 *)HobStart;
while ((GuidHob.Raw = GetNextHob (EFI_HOB_TYPE_GUID_EXTENSION, GuidHob.Raw)) != NULL) {
if (CompareGuid (Guid, &GuidHob.Guid->Name)) {
break;
}
GuidHob.Raw = GET_NEXT_HOB (GuidHob);
}
return GuidHob.Raw;
}
C
VOID *
EFIAPI
GetNextHob (
IN UINT16 Type,
IN CONST VOID *HobStart
)
{
EFI_PEI_HOB_POINTERS Hob;
ASSERT (HobStart != NULL);
Hob.Raw = (UINT8 *)HobStart;
//
// Parse the HOB list until end of list or matching type is found.
//
while (!END_OF_HOB_LIST (Hob)) {
if (Hob.Header->HobType == Type) {
return Hob.Raw;
}
Hob.Raw = GET_NEXT_HOB (Hob);
}
return NULL;
}
没有匹配到GUID-HOB节点
自定义GUID-HOB节点
C
VOID *
EFIAPI
BuildGuidHob (
IN CONST EFI_GUID *Guid,
IN UINTN DataLength
)
{
EFI_HOB_GUID_TYPE *Hob;
//
// Make sure Guid is valid
//
ASSERT (Guid != NULL);
//
// Make sure that data length is not too long.
//
ASSERT (DataLength <= (0xFFF8 - sizeof (EFI_HOB_GUID_TYPE)));
Hob = InternalPeiCreateHob (EFI_HOB_TYPE_GUID_EXTENSION, (UINT16)(sizeof (EFI_HOB_GUID_TYPE) + DataLength));
if (Hob == NULL) {
return Hob;
}
CopyGuid (&Hob->Name, Guid);
return Hob + 1;
}
创建节点
C
VOID *
EFIAPI
InternalPeiCreateHob (
IN UINT16 Type,
IN UINT16 Length
)
{
EFI_STATUS Status;
VOID *Hob;
Status = PeiServicesCreateHob (Type, Length, &Hob);
if (EFI_ERROR (Status)) {
Hob = NULL;
}
//
// Assume the process of HOB building is always successful.
//
ASSERT (Hob != NULL);
return Hob;
}
复制GUID (16字节复制两次)
C
GUID *
EFIAPI
CopyGuid (
OUT GUID *DestinationGuid,
IN CONST GUID *SourceGuid
)
{
WriteUnaligned64 (
(UINT64 *)DestinationGuid,
ReadUnaligned64 ((CONST UINT64 *)SourceGuid)
);
WriteUnaligned64 (
(UINT64 *)DestinationGuid + 1,
ReadUnaligned64 ((CONST UINT64 *)SourceGuid + 1)
);
return DestinationGuid;
}
安装延迟调度PPI(&mDelayedDispatchDesc)
PS:两次创建HOB节点
第一次创建自定义GUID-HOB 存"业务数据";第二次创建HOB 存"接口数组"
注册PEI结束时的回调 (&mDelayedDispatchNotifyDesc)
把之前因资源不足而推迟的 PEIM一次性补调度
尝试调度PEIMs
寻找FV实例
C
PEI_CORE_FV_HANDLE *
FindNextCoreFvHandle (
IN PEI_CORE_INSTANCE *Private,
IN UINTN Instance
)
{
if (Instance >= Private->FvCount) {
return NULL;
}
return &Private->Fv[Instance];
}
查找所有PEIMs并根据Apriori 文件排序
C
VOID
DiscoverPeimsAndOrderWithApriori (
IN PEI_CORE_INSTANCE *Private,
IN PEI_CORE_FV_HANDLE *CoreFileHandle
)
{
EFI_STATUS Status;
EFI_PEI_FILE_HANDLE FileHandle;
EFI_PEI_FILE_HANDLE AprioriFileHandle;
EFI_GUID *Apriori;
UINTN Index;
UINTN Index2;
UINTN PeimIndex;
UINTN PeimCount;
EFI_GUID *Guid;
EFI_PEI_FILE_HANDLE *TempFileHandles;
EFI_GUID *TempFileGuid;
EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
EFI_FV_FILE_INFO FileInfo;
FvPpi = CoreFileHandle->FvPpi;
//
// Walk the FV and find all the PEIMs and the Apriori file.
//
AprioriFileHandle = NULL;
Private->CurrentFvFileHandles = NULL;
Guid = NULL;
//
// If the current FV has been scanned, directly get its cached records.
//
if (CoreFileHandle->ScanFv) {
Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles;
return;
}
TempFileHandles = Private->TempFileHandles;
TempFileGuid = Private->TempFileGuid;
//
// Go ahead to scan this FV, get PeimCount and cache FileHandles within it to TempFileHandles.
//
PeimCount = 0;
FileHandle = NULL;
do {
Status = FvPpi->FindFileByType (FvPpi, PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE, CoreFileHandle->FvHandle, &FileHandle);
if (!EFI_ERROR (Status)) {
if (PeimCount >= Private->TempPeimCount) {
//
// Run out of room, grow the buffer.
//
TempFileHandles = AllocatePool (
sizeof (EFI_PEI_FILE_HANDLE) * (Private->TempPeimCount + TEMP_FILE_GROWTH_STEP)
);
ASSERT (TempFileHandles != NULL);
CopyMem (
TempFileHandles,
Private->TempFileHandles,
sizeof (EFI_PEI_FILE_HANDLE) * Private->TempPeimCount
);
Private->TempFileHandles = TempFileHandles;
TempFileGuid = AllocatePool (
sizeof (EFI_GUID) * (Private->TempPeimCount + TEMP_FILE_GROWTH_STEP)
);
ASSERT (TempFileGuid != NULL);
CopyMem (
TempFileGuid,
Private->TempFileGuid,
sizeof (EFI_GUID) * Private->TempPeimCount
);
Private->TempFileGuid = TempFileGuid;
Private->TempPeimCount = Private->TempPeimCount + TEMP_FILE_GROWTH_STEP;
}
TempFileHandles[PeimCount++] = FileHandle;
}
} while (!EFI_ERROR (Status));
DEBUG ((
DEBUG_INFO,
"%a(): Found 0x%x PEI FFS files in the %dth FV\n",
__func__,
PeimCount,
Private->CurrentPeimFvCount
));
if (PeimCount == 0) {
//
// No PEIM FFS file is found, set ScanFv flag and return.
//
CoreFileHandle->ScanFv = TRUE;
return;
}
//
// Record PeimCount, allocate buffer for PeimState and FvFileHandles.
//
CoreFileHandle->PeimCount = PeimCount;
CoreFileHandle->PeimState = AllocateZeroPool (sizeof (UINT8) * PeimCount);
ASSERT (CoreFileHandle->PeimState != NULL);
CoreFileHandle->FvFileHandles = AllocateZeroPool (sizeof (EFI_PEI_FILE_HANDLE) * PeimCount);
ASSERT (CoreFileHandle->FvFileHandles != NULL);
//
// Get Apriori File handle
//
Private->AprioriCount = 0;
Status = FvPpi->FindFileByName (FvPpi, &gPeiAprioriFileNameGuid, &CoreFileHandle->FvHandle, &AprioriFileHandle);
if (!EFI_ERROR (Status) && (AprioriFileHandle != NULL)) {
//
// Read the Apriori file
//
Status = FvPpi->FindSectionByType (FvPpi, EFI_SECTION_RAW, AprioriFileHandle, (VOID **)&Apriori);
if (!EFI_ERROR (Status)) {
//
// Calculate the number of PEIMs in the Apriori file
//
Status = FvPpi->GetFileInfo (FvPpi, AprioriFileHandle, &FileInfo);
ASSERT_EFI_ERROR (Status);
Private->AprioriCount = FileInfo.BufferSize;
if (IS_SECTION2 (FileInfo.Buffer)) {
Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER2);
} else {
Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER);
}
Private->AprioriCount /= sizeof (EFI_GUID);
for (Index = 0; Index < PeimCount; Index++) {
//
// Make an array of file name GUIDs that matches the FileHandle array so we can convert
// quickly from file name to file handle
//
Status = FvPpi->GetFileInfo (FvPpi, TempFileHandles[Index], &FileInfo);
ASSERT_EFI_ERROR (Status);
CopyMem (&TempFileGuid[Index], &FileInfo.FileName, sizeof (EFI_GUID));
}
//
// Walk through TempFileGuid array to find out who is invalid PEIM GUID in Apriori file.
// Add available PEIMs in Apriori file into FvFileHandles array.
//
Index = 0;
for (Index2 = 0; Index2 < Private->AprioriCount; Index2++) {
Guid = ScanGuid (TempFileGuid, PeimCount * sizeof (EFI_GUID), &Apriori[Index2]);
if (Guid != NULL) {
PeimIndex = ((UINTN)Guid - (UINTN)&TempFileGuid[0])/sizeof (EFI_GUID);
CoreFileHandle->FvFileHandles[Index++] = TempFileHandles[PeimIndex];
//
// Since we have copied the file handle we can remove it from this list.
//
TempFileHandles[PeimIndex] = NULL;
}
}
//
// Update valid AprioriCount
//
Private->AprioriCount = Index;
//
// Add in any PEIMs not in the Apriori file
//
for (Index2 = 0; Index2 < PeimCount; Index2++) {
if (TempFileHandles[Index2] != NULL) {
CoreFileHandle->FvFileHandles[Index++] = TempFileHandles[Index2];
TempFileHandles[Index2] = NULL;
}
}
ASSERT (Index == PeimCount);
}
} else {
CopyMem (CoreFileHandle->FvFileHandles, TempFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PeimCount);
}
//
// The current FV File Handles have been cached. So that we don't have to scan the FV again.
// Instead, we can retrieve the file handles within this FV from cached records.
//
CoreFileHandle->ScanFv = TRUE;
Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles;
}
在指定的 FV 中查找符合特定类型的 PEIM 文件
为了容纳PEIM,为PEIM动态扩展两个缓冲区:Handle和GUID。
寻找Apriori文件并获取文件信息
寻找Apriori文件中的PEIMs
添加不在Apriori文件中的PEIMs
开始调度当前 FV 内的PEIMs。
C
for (PeimCount = Private->CurrentPeimCount;
PeimCount < Private->Fv[FvCount].PeimCount;
PeimCount++)
{
Private->CurrentPeimCount = PeimCount;
PeimFileHandle = Private->CurrentFileHandle = Private->CurrentFvFileHandles[PeimCount];
if (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_NOT_DISPATCHED) {
if (!DepexSatisfied (Private, PeimFileHandle, PeimCount)) {
Private->PeimNeedingDispatch = TRUE;
} else {
Status = CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, PeimFileHandle, &FvFileInfo);
ASSERT_EFI_ERROR (Status);
if (FvFileInfo.FileType == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
//
// For FV type file, Produce new FvInfo PPI and FV HOB
//
Status = ProcessFvFile (Private, &Private->Fv[FvCount], PeimFileHandle);
if (Status == EFI_SUCCESS) {
//
// PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
//
Private->Fv[FvCount].PeimState[PeimCount]++;
Private->PeimDispatchOnThisPass = TRUE;
} else {
//
// The related GuidedSectionExtraction/Decompress PPI for the
// encapsulated FV image section may be installed in the rest
// of this do-while loop, so need to make another pass.
//
Private->PeimNeedingDispatch = TRUE;
}
} else {
//
// For PEIM driver, Load its entry point
//
Status = PeiLoadImage (
PeiServices,
PeimFileHandle,
PEIM_STATE_NOT_DISPATCHED,
&EntryPoint,
&AuthenticationState
);
if (Status == EFI_SUCCESS) {
//
// The PEIM has its dependencies satisfied, and its entry point
// has been found, so invoke it.
//
PERF_START_IMAGE_BEGIN (PeimFileHandle);
REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
EFI_PROGRESS_CODE,
(EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN),
(VOID *)(&PeimFileHandle),
sizeof (PeimFileHandle)
);
Status = VerifyPeim (Private, CoreFvHandle->FvHandle, PeimFileHandle, AuthenticationState);
if (Status != EFI_SECURITY_VIOLATION) {
//
// PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
//
Private->Fv[FvCount].PeimState[PeimCount]++;
//
// Call the PEIM entry point for PEIM driver
//
PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices);
Private->PeimDispatchOnThisPass = TRUE;
} else {
//
// The related GuidedSectionExtraction PPI for the
// signed PEIM image section may be installed in the rest
// of this do-while loop, so need to make another pass.
//
Private->PeimNeedingDispatch = TRUE;
}
REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
EFI_PROGRESS_CODE,
(EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END),
(VOID *)(&PeimFileHandle),
sizeof (PeimFileHandle)
);
PERF_START_IMAGE_END (PeimFileHandle);
}
}
PeiCheckAndSwitchStack (SecCoreData, Private);
//
// Process the Notify list and dispatch any notifies for
// newly installed PPIs.
//
ProcessDispatchNotifyList (Private);
//
// Recheck SwitchStackSignal after ProcessDispatchNotifyList()
// in case PeiInstallPeiMemory() is done in a callback with
// EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH.
//
PeiCheckAndSwitchStack (SecCoreData, Private);
if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW) && \
(PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
(Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||
PcdGetBool (PcdShadowPeimOnS3Boot))
)
{
//
// If memory is available we shadow images by default for performance reasons.
// We call the entry point a 2nd time so the module knows it's shadowed.
//
// PERF_START (PeiServices, L"PEIM", PeimFileHandle, 0);
if ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && !PcdGetBool (PcdShadowPeimOnBoot) &&
!PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes))
{
//
// Load PEIM into Memory for Register for shadow PEIM.
//
Status = PeiLoadImage (
PeiServices,
PeimFileHandle,
PEIM_STATE_REGISTER_FOR_SHADOW,
&EntryPoint,
&AuthenticationState
);
if (Status == EFI_SUCCESS) {
PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
}
}
ASSERT (PeimEntryPoint != NULL);
PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices);
// PERF_END (PeiServices, L"PEIM", PeimFileHandle, 0);
//
// PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE
//
Private->Fv[FvCount].PeimState[PeimCount]++;
//
// Process the Notify list and dispatch any notifies for
// newly installed PPIs.
//
ProcessDispatchNotifyList (Private);
}
}
}
// Dispatch pending delalyed dispatch requests
if (Private->DelayedDispatchTable != NULL) {
if (DelayedDispatchDispatcher (Private->DelayedDispatchTable, NULL)) {
ProcessDispatchNotifyList (Private);
}
}
}
加载PEIM进入点
C
EFI_STATUS
PeiLoadImage (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_FILE_HANDLE FileHandle,
IN UINT8 PeimState,
OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
OUT UINT32 *AuthenticationState
)
{
EFI_STATUS PpiStatus;
EFI_STATUS Status;
UINTN Index;
EFI_PEI_LOAD_FILE_PPI *LoadFile;
EFI_PHYSICAL_ADDRESS ImageAddress;
UINT64 ImageSize;
BOOLEAN IsStrip;
IsStrip = FALSE;
//
// If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
// one at a time, until one reports EFI_SUCCESS.
//
Index = 0;
do {
PpiStatus = PeiServicesLocatePpi (
&gEfiPeiLoadFilePpiGuid,
Index,
NULL,
(VOID **)&LoadFile
);
if (!EFI_ERROR (PpiStatus)) {
Status = LoadFile->LoadFile (
LoadFile,
FileHandle,
&ImageAddress,
&ImageSize,
EntryPoint,
AuthenticationState
);
if (!EFI_ERROR (Status) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
//
// The shadowed PEIM must be relocatable.
//
if (PeimState == PEIM_STATE_REGISTER_FOR_SHADOW) {
IsStrip = RelocationIsStrip ((VOID *)(UINTN)ImageAddress);
ASSERT (!IsStrip);
if (IsStrip) {
return EFI_UNSUPPORTED;
}
}
//
// The image to be started must have the machine type supported by PeiCore.
//
ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *)(UINTN)ImageAddress)));
if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *)(UINTN)ImageAddress))) {
return EFI_UNSUPPORTED;
}
return EFI_SUCCESS;
}
}
Index++;
} while (!EFI_ERROR (PpiStatus));
return PpiStatus;
}
C
EFI_STATUS
EFIAPI
PeiLoadImageLoadImageWrapper (
IN CONST EFI_PEI_LOAD_FILE_PPI *This,
IN EFI_PEI_FILE_HANDLE FileHandle,
OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg OPTIONAL,
OUT UINT64 *ImageSizeArg OPTIONAL,
OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
OUT UINT32 *AuthenticationState
)
{
return PeiLoadImageLoadImage (
GetPeiServicesTablePointer (),
FileHandle,
ImageAddressArg,
ImageSizeArg,
EntryPoint,
AuthenticationState
);
}
C
EFI_STATUS
PeiLoadImageLoadImage (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_FILE_HANDLE FileHandle,
OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg OPTIONAL,
OUT UINT64 *ImageSizeArg OPTIONAL,
OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
OUT UINT32 *AuthenticationState
)
{
EFI_STATUS Status;
VOID *Pe32Data;
EFI_PHYSICAL_ADDRESS ImageAddress;
UINT64 ImageSize;
EFI_PHYSICAL_ADDRESS ImageEntryPoint;
UINT16 Machine;
EFI_SECTION_TYPE SearchType1;
EFI_SECTION_TYPE SearchType2;
CHAR8 *AsciiString;
CHAR8 EfiFileName[512];
UINTN Index;
UINTN StartIndex;
*EntryPoint = 0;
ImageSize = 0;
*AuthenticationState = 0;
if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) {
SearchType1 = EFI_SECTION_TE;
SearchType2 = EFI_SECTION_PE32;
} else {
SearchType1 = EFI_SECTION_PE32;
SearchType2 = EFI_SECTION_TE;
}
//
// Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
// is true, TE will be searched first).
//
Status = PeiServicesFfsFindSectionData3 (
SearchType1,
0,
FileHandle,
&Pe32Data,
AuthenticationState
);
//
// If we didn't find a first exe section, try to find the second exe section.
//
if (EFI_ERROR (Status)) {
Status = PeiServicesFfsFindSectionData3 (
SearchType2,
0,
FileHandle,
&Pe32Data,
AuthenticationState
);
if (EFI_ERROR (Status)) {
//
// PEI core only carry the loader function for TE and PE32 executables
// If this two section does not exist, just return.
//
return Status;
}
}
DEBUG ((DEBUG_INFO, "Loading PEIM %g\n", FileHandle));
//
// If memory is installed, perform the shadow operations
//
Status = LoadAndRelocatePeCoffImage (
FileHandle,
Pe32Data,
&ImageAddress,
&ImageSize,
&ImageEntryPoint
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Got the entry point from the loaded Pe32Data
//
Pe32Data = (VOID *)((UINTN)ImageAddress);
*EntryPoint = ImageEntryPoint;
Machine = PeCoffLoaderGetMachineType (Pe32Data);
if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {
if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) {
return EFI_UNSUPPORTED;
}
}
if (ImageAddressArg != NULL) {
*ImageAddressArg = ImageAddress;
}
if (ImageSizeArg != NULL) {
*ImageSizeArg = ImageSize;
}
//
// Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
//
if (Machine != EFI_IMAGE_MACHINE_IA64) {
DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint));
} else {
//
// For IPF Image, the real entry point should be print.
//
DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));
}
//
// Print Module Name by PeImage PDB file name.
//
AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);
if (AsciiString != NULL) {
StartIndex = 0;
for (Index = 0; AsciiString[Index] != 0; Index++) {
if ((AsciiString[Index] == '\\') || (AsciiString[Index] == '/')) {
StartIndex = Index + 1;
}
}
//
// Copy the PDB file name to our temporary string, and replace .pdb with .efi
// The PDB file name is limited in the range of 0~511.
// If the length is bigger than 511, trim the redundant characters to avoid overflow in array boundary.
//
for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
EfiFileName[Index] = AsciiString[Index + StartIndex];
if (EfiFileName[Index] == 0) {
EfiFileName[Index] = '.';
}
if (EfiFileName[Index] == '.') {
EfiFileName[Index + 1] = 'e';
EfiFileName[Index + 2] = 'f';
EfiFileName[Index + 3] = 'i';
EfiFileName[Index + 4] = 0;
break;
}
}
if (Index == sizeof (EfiFileName) - 4) {
EfiFileName[Index] = 0;
}
DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName));
}
DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));
return EFI_SUCCESS;
}
C
EFI_STATUS
EFIAPI
PeiServicesFfsFindSectionData3 (
IN EFI_SECTION_TYPE SectionType,
IN UINTN SectionInstance,
IN EFI_PEI_FILE_HANDLE FileHandle,
OUT VOID **SectionData,
OUT UINT32 *AuthenticationStatus
)
{
CONST EFI_PEI_SERVICES **PeiServices;
PeiServices = GetPeiServicesTablePointer ();
return (*PeiServices)->FindSectionData3 (PeiServices, SectionType, SectionInstance, FileHandle, SectionData, AuthenticationStatus);
}
* 尝试找第一个可执行段类型(PEIM 的入口映像)
C
EFI_STATUS
EFIAPI
PeiFfsFindSectionData3 (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN EFI_SECTION_TYPE SectionType,
IN UINTN SectionInstance,
IN EFI_PEI_FILE_HANDLE FileHandle,
OUT VOID **SectionData,
OUT UINT32 *AuthenticationStatus
)
{
PEI_CORE_FV_HANDLE *CoreFvHandle;
CoreFvHandle = FileHandleToVolume (FileHandle);
if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
return EFI_NOT_FOUND;
}
if ((CoreFvHandle->FvPpi->Signature == EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE) &&
(CoreFvHandle->FvPpi->Revision == EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION))
{
return CoreFvHandle->FvPpi->FindSectionByType2 (CoreFvHandle->FvPpi, SectionType, SectionInstance, FileHandle, SectionData, AuthenticationStatus);
}
//
// The old FvPpi doesn't support to find section by section instance
// and return authentication status, so return EFI_UNSUPPORTED.
//
return EFI_UNSUPPORTED;
}
C
PEI_CORE_FV_HANDLE *
FileHandleToVolume (
IN EFI_PEI_FILE_HANDLE FileHandle
)
{
UINTN Index;
PEI_CORE_INSTANCE *PrivateData;
EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
UINTN BestIndex;
PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
BestIndex = PrivateData->FvCount;
//
// Find the best matched FV image that includes this FileHandle.
// FV may include the child FV, and they are in the same continuous space.
// If FileHandle is from the child FV, the updated logic can find its matched FV.
//
for (Index = 0; Index < PrivateData->FvCount; Index++) {
FwVolHeader = PrivateData->Fv[Index].FvHeader;
if (((UINT64)(UINTN)FileHandle > (UINT64)(UINTN)FwVolHeader) && \
((UINT64)(UINTN)FileHandle <= ((UINT64)(UINTN)FwVolHeader + FwVolHeader->FvLength - 1)))
{
if (BestIndex == PrivateData->FvCount) {
BestIndex = Index;
} else {
if ((UINT64)(UINTN)PrivateData->Fv[BestIndex].FvHeader < (UINT64)(UINTN)FwVolHeader) {
BestIndex = Index;
}
}
}
}
if (BestIndex < PrivateData->FvCount) {
return &PrivateData->Fv[BestIndex];
}
return NULL;
}
C
EFI_STATUS
EFIAPI
PeiFfsFvPpiFindSectionByType2 (
IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
IN EFI_SECTION_TYPE SearchType,
IN UINTN SearchInstance,
IN EFI_PEI_FILE_HANDLE FileHandle,
OUT VOID **SectionData,
OUT UINT32 *AuthenticationStatus
)
{
EFI_STATUS Status;
EFI_FFS_FILE_HEADER *FfsFileHeader;
UINT32 FileSize;
EFI_COMMON_SECTION_HEADER *Section;
PEI_FW_VOL_INSTANCE *FwVolInstance;
PEI_CORE_FV_HANDLE *CoreFvHandle;
UINTN Instance;
UINT32 ExtractedAuthenticationStatus;
if (SectionData == NULL) {
return EFI_NOT_FOUND;
}
FwVolInstance = PEI_FW_VOL_INSTANCE_FROM_FV_THIS (This);
//
// Retrieve the FirmwareVolume which the file resides in.
//
CoreFvHandle = FileHandleToVolume (FileHandle);
if (CoreFvHandle == NULL) {
return EFI_NOT_FOUND;
}
FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);
if (IS_FFS_FILE2 (FfsFileHeader)) {
ASSERT (FFS_FILE2_SIZE (FfsFileHeader) > 0x00FFFFFF);
if (!FwVolInstance->IsFfs3Fv) {
DEBUG ((DEBUG_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
return EFI_NOT_FOUND;
}
Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2));
FileSize = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
} else {
Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));
FileSize = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
}
Instance = SearchInstance + 1;
ExtractedAuthenticationStatus = 0;
Status = ProcessSection (
GetPeiServicesTablePointer (),
SearchType,
&Instance,
Section,
FileSize,
SectionData,
&ExtractedAuthenticationStatus,
FwVolInstance->IsFfs3Fv
);
if (!EFI_ERROR (Status)) {
//
// Inherit the authentication status.
//
*AuthenticationStatus = ExtractedAuthenticationStatus | CoreFvHandle->AuthenticationStatus;
}
return Status;
}
* 找到第一个段头后进行处理
C
EFI_STATUS
ProcessSection (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN EFI_SECTION_TYPE SectionType,
IN OUT UINTN *SectionInstance,
IN EFI_COMMON_SECTION_HEADER *Section,
IN UINTN SectionSize,
OUT VOID **OutputBuffer,
OUT UINT32 *AuthenticationStatus,
IN BOOLEAN IsFfs3Fv
)
{
EFI_STATUS Status;
UINT32 SectionLength;
UINT32 ParsedLength;
EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *GuidSectionPpi;
EFI_PEI_DECOMPRESS_PPI *DecompressPpi;
VOID *PpiOutput;
UINTN PpiOutputSize;
UINTN Index;
UINT32 Authentication;
PEI_CORE_INSTANCE *PrivateData;
EFI_GUID *SectionDefinitionGuid;
BOOLEAN SectionCached;
VOID *TempOutputBuffer;
UINT32 TempAuthenticationStatus;
UINT16 GuidedSectionAttributes;
PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
*OutputBuffer = NULL;
ParsedLength = 0;
Index = 0;
Status = EFI_NOT_FOUND;
PpiOutput = NULL;
PpiOutputSize = 0;
while (ParsedLength < SectionSize) {
if (IS_SECTION2 (Section)) {
ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);
if (!IsFfs3Fv) {
DEBUG ((DEBUG_ERROR, "Found a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
SectionLength = SECTION2_SIZE (Section);
if (SectionLength == 0) {
break;
}
//
// SectionLength is adjusted it is 4 byte aligned.
// Go to the next section
//
SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
ASSERT (SectionLength != 0);
ParsedLength += SectionLength;
Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
continue;
}
}
if (Section->Type == SectionType) {
//
// The type matches, so check the instance count to see if it's the one we want.
//
(*SectionInstance)--;
if (*SectionInstance == 0) {
//
// Got it!
//
if (IS_SECTION2 (Section)) {
*OutputBuffer = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER2));
} else {
*OutputBuffer = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER));
}
return EFI_SUCCESS;
} else {
if (IS_SECTION2 (Section)) {
SectionLength = SECTION2_SIZE (Section);
} else {
SectionLength = SECTION_SIZE (Section);
}
if (SectionLength == 0) {
break;
}
//
// SectionLength is adjusted it is 4 byte aligned.
// Go to the next section
//
SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
ASSERT (SectionLength != 0);
ParsedLength += SectionLength;
Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
continue;
}
} else if ((Section->Type == EFI_SECTION_GUID_DEFINED) || (Section->Type == EFI_SECTION_COMPRESSION)) {
//
// Check the encapsulated section is extracted into the cache data.
//
SectionCached = FALSE;
for (Index = 0; Index < PrivateData->CacheSection.AllSectionCount; Index++) {
if (Section == PrivateData->CacheSection.Section[Index]) {
SectionCached = TRUE;
PpiOutput = PrivateData->CacheSection.SectionData[Index];
PpiOutputSize = PrivateData->CacheSection.SectionSize[Index];
Authentication = PrivateData->CacheSection.AuthenticationStatus[Index];
//
// Search section directly from the cache data.
//
TempAuthenticationStatus = 0;
Status = ProcessSection (
PeiServices,
SectionType,
SectionInstance,
PpiOutput,
PpiOutputSize,
&TempOutputBuffer,
&TempAuthenticationStatus,
IsFfs3Fv
);
if (!EFI_ERROR (Status)) {
*OutputBuffer = TempOutputBuffer;
*AuthenticationStatus = TempAuthenticationStatus | Authentication;
return EFI_SUCCESS;
}
}
}
//
// If SectionCached is TRUE, the section data has been cached and scanned.
//
if (!SectionCached) {
Status = EFI_NOT_FOUND;
Authentication = 0;
if (Section->Type == EFI_SECTION_GUID_DEFINED) {
if (IS_SECTION2 (Section)) {
SectionDefinitionGuid = &((EFI_GUID_DEFINED_SECTION2 *)Section)->SectionDefinitionGuid;
GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION2 *)Section)->Attributes;
} else {
SectionDefinitionGuid = &((EFI_GUID_DEFINED_SECTION *)Section)->SectionDefinitionGuid;
GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION *)Section)->Attributes;
}
if (VerifyGuidedSectionGuid (SectionDefinitionGuid, &GuidSectionPpi)) {
Status = GuidSectionPpi->ExtractSection (
GuidSectionPpi,
Section,
&PpiOutput,
&PpiOutputSize,
&Authentication
);
} else if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {
//
// Figure out the proper authentication status for GUIDED section without processing required
//
Status = EFI_SUCCESS;
if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
Authentication |= EFI_AUTH_STATUS_IMAGE_SIGNED | EFI_AUTH_STATUS_NOT_TESTED;
}
if (IS_SECTION2 (Section)) {
PpiOutputSize = SECTION2_SIZE (Section) - ((EFI_GUID_DEFINED_SECTION2 *)Section)->DataOffset;
PpiOutput = (UINT8 *)Section + ((EFI_GUID_DEFINED_SECTION2 *)Section)->DataOffset;
} else {
PpiOutputSize = SECTION_SIZE (Section) - ((EFI_GUID_DEFINED_SECTION *)Section)->DataOffset;
PpiOutput = (UINT8 *)Section + ((EFI_GUID_DEFINED_SECTION *)Section)->DataOffset;
}
}
} else if (Section->Type == EFI_SECTION_COMPRESSION) {
Status = PeiServicesLocatePpi (&gEfiPeiDecompressPpiGuid, 0, NULL, (VOID **)&DecompressPpi);
if (!EFI_ERROR (Status)) {
Status = DecompressPpi->Decompress (
DecompressPpi,
(CONST EFI_COMPRESSION_SECTION *)Section,
&PpiOutput,
&PpiOutputSize
);
}
}
if (!EFI_ERROR (Status)) {
if ((Authentication & EFI_AUTH_STATUS_NOT_TESTED) == 0) {
//
// Update cache section data.
//
if (PrivateData->CacheSection.AllSectionCount < CACHE_SETION_MAX_NUMBER) {
PrivateData->CacheSection.AllSectionCount++;
}
PrivateData->CacheSection.Section[PrivateData->CacheSection.SectionIndex] = Section;
PrivateData->CacheSection.SectionData[PrivateData->CacheSection.SectionIndex] = PpiOutput;
PrivateData->CacheSection.SectionSize[PrivateData->CacheSection.SectionIndex] = PpiOutputSize;
PrivateData->CacheSection.AuthenticationStatus[PrivateData->CacheSection.SectionIndex] = Authentication;
PrivateData->CacheSection.SectionIndex = (PrivateData->CacheSection.SectionIndex + 1)%CACHE_SETION_MAX_NUMBER;
}
TempAuthenticationStatus = 0;
Status = ProcessSection (
PeiServices,
SectionType,
SectionInstance,
PpiOutput,
PpiOutputSize,
&TempOutputBuffer,
&TempAuthenticationStatus,
IsFfs3Fv
);
if (!EFI_ERROR (Status)) {
*OutputBuffer = TempOutputBuffer;
*AuthenticationStatus = TempAuthenticationStatus | Authentication;
return EFI_SUCCESS;
}
}
}
}
if (IS_SECTION2 (Section)) {
SectionLength = SECTION2_SIZE (Section);
} else {
SectionLength = SECTION_SIZE (Section);
}
if (SectionLength == 0) {
break;
}
//
// SectionLength is adjusted it is 4 byte aligned.
// Go to the next section
//
SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
ASSERT (SectionLength != 0);
ParsedLength += SectionLength;
Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
}
return EFI_NOT_FOUND;
}
遍历该FFS所有Section发现没有想要的Section
* 尝试找第二个可执行段类型(过程与上述相同)
* 加载并重定位PE/COFF映像到内存
C
EFI_STATUS
LoadAndRelocatePeCoffImage (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN VOID *Pe32Data,
OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
OUT UINT64 *ImageSize,
OUT EFI_PHYSICAL_ADDRESS *EntryPoint
)
{
EFI_STATUS Status;
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
PEI_CORE_INSTANCE *Private;
UINT64 AlignImageSize;
BOOLEAN IsXipImage;
EFI_STATUS ReturnStatus;
BOOLEAN IsS3Boot;
BOOLEAN IsPeiModule;
BOOLEAN IsRegisterForShadow;
EFI_FV_FILE_INFO FileInfo;
Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
ReturnStatus = EFI_SUCCESS;
IsXipImage = FALSE;
ZeroMem (&ImageContext, sizeof (ImageContext));
ImageContext.Handle = Pe32Data;
ImageContext.ImageRead = PeiImageRead;
Status = PeCoffLoaderGetImageInfo (&ImageContext);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Initialize local IsS3Boot and IsRegisterForShadow variable
//
IsS3Boot = FALSE;
if (Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) {
IsS3Boot = TRUE;
}
IsRegisterForShadow = FALSE;
if ( (Private->CurrentFileHandle == FileHandle)
&& (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW))
{
IsRegisterForShadow = TRUE;
}
//
// XIP image that ImageAddress is same to Image handle.
//
if (ImageContext.ImageAddress == (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data) {
IsXipImage = TRUE;
}
//
// Get file type first
//
Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo);
ASSERT_EFI_ERROR (Status);
//
// Check whether the file type is PEI module.
//
IsPeiModule = FALSE;
if ((FileInfo.FileType == EFI_FV_FILETYPE_PEI_CORE) ||
(FileInfo.FileType == EFI_FV_FILETYPE_PEIM) ||
(FileInfo.FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER))
{
IsPeiModule = TRUE;
}
//
// When Image has no reloc section, it can't be relocated into memory.
//
if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) &&
((!IsPeiModule) || PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
(!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) ||
(IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))
)
{
DEBUG ((DEBUG_INFO|DEBUG_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN)Pe32Data));
}
//
// Set default base address to current image address.
//
ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data;
//
// Allocate Memory for the image when memory is ready, and image is relocatable.
// On normal boot, PcdShadowPeimOnBoot decides whether load PEIM or PeiCore into memory.
// On S3 boot, PcdShadowPeimOnS3Boot decides whether load PEIM or PeiCore into memory.
//
if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) &&
((!IsPeiModule) || PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
(!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) ||
(IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))
)
{
//
// Allocate more buffer to avoid buffer overflow.
//
if (ImageContext.IsTeImage) {
AlignImageSize = ImageContext.ImageSize + ((EFI_TE_IMAGE_HEADER *)Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
} else {
AlignImageSize = ImageContext.ImageSize;
}
if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
AlignImageSize += ImageContext.SectionAlignment;
}
if ((PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext, Private);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
//
// The PEIM is not assigned valid address, try to allocate page to load it.
//
Status = PeiServicesAllocatePages (
EfiBootServicesCode,
EFI_SIZE_TO_PAGES ((UINT32)AlignImageSize),
&ImageContext.ImageAddress
);
}
} else {
Status = PeiServicesAllocatePages (
EfiBootServicesCode,
EFI_SIZE_TO_PAGES ((UINT32)AlignImageSize),
&ImageContext.ImageAddress
);
}
if (!EFI_ERROR (Status)) {
//
// Adjust the Image Address to make sure it is section alignment.
//
if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
ImageContext.ImageAddress =
(ImageContext.ImageAddress + ImageContext.SectionAlignment - 1) &
~((UINTN)ImageContext.SectionAlignment - 1);
}
//
// Fix alignment requirement when Load IPF TeImage into memory.
// Skip the reserved space for the stripped PeHeader when load TeImage into memory.
//
if (ImageContext.IsTeImage) {
ImageContext.ImageAddress = ImageContext.ImageAddress +
((EFI_TE_IMAGE_HEADER *)Pe32Data)->StrippedSize -
sizeof (EFI_TE_IMAGE_HEADER);
}
} else {
//
// No enough memory resource.
//
if (IsXipImage) {
//
// XIP image can still be invoked.
//
ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data;
ReturnStatus = EFI_WARN_BUFFER_TOO_SMALL;
} else {
//
// Non XIP image can't be loaded because no enough memory is allocated.
//
ASSERT (FALSE);
return EFI_OUT_OF_RESOURCES;
}
}
}
//
// Load the image to our new buffer
//
Status = PeCoffLoaderLoadImage (&ImageContext);
if (EFI_ERROR (Status)) {
if (ImageContext.ImageError == IMAGE_ERROR_INVALID_SECTION_ALIGNMENT) {
DEBUG ((DEBUG_ERROR, "PEIM Image Address 0x%11p doesn't meet with section alignment 0x%x.\n", (VOID *)(UINTN)ImageContext.ImageAddress, ImageContext.SectionAlignment));
}
return Status;
}
//
// Relocate the image in our new buffer
//
Status = PeCoffLoaderRelocateImage (&ImageContext);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Flush the instruction cache so the image data is written before we execute it
//
if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data) {
InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
}
*ImageAddress = ImageContext.ImageAddress;
*ImageSize = ImageContext.ImageSize;
*EntryPoint = ImageContext.EntryPoint;
return ReturnStatus;
}
** 获取映像信息
计算 ImageContext 结构体的以下字段:
- PeCoffHeaderOffset
- IsTeImage
- ImageType
- ImageAddress
- ImageSize
- DestinationAddress
- RelocationsStripped
- SectionAlignment
- SizeOfHeaders
- DllCharacteristics
- DllCharacteristicsEx
- DebugDirectoryEntryRva。
如果 ImageContext 为 NULL,则返回 RETURN_INVALID_PARAMETER。
如果通过 ImageContext 结构体中的 ImageRead 服务访问的 PE/COFF 映像不是受支持的 PE/COFF 映像类型,则返回 RETURN_UNSUPPORTED。
如果在计算 ImageContext 字段的过程中发生任何错误,则错误状态将返回到 ImageContext 的 ImageError 字段中。
如果映像是 TE 映像,则 SectionAlignment 设置为 0。
在调用此服务之前,ImageContext 结构体的 ImageRead 和 Handle 字段必须是有效的。
** 初始化本地 IsS3Boot 和 IsRegisterForShadow 变量
C
IsS3Boot = FALSE;
if (Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) {
IsS3Boot = TRUE;
}
IsRegisterForShadow = FALSE;
if ( (Private->CurrentFileHandle == FileHandle)
&& (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW))
{
IsRegisterForShadow = TRUE;
}
IsRegisterForShadow是Windows 内核在启动早期用来判断"当前这一组 CPU 是否需要注册为 shadow 服务处理器"的一个 内部标志位。
** 判断映像是否可以就地执行
C
if (ImageContext.ImageAddress == (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data) {
IsXipImage = TRUE;
}
** 再次校验是否是PEIM
C
//
// Get file type first
//
Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo);
ASSERT_EFI_ERROR (Status);
//
// Check whether the file type is PEI module.
//
IsPeiModule = FALSE;
if ((FileInfo.FileType == EFI_FV_FILETYPE_PEI_CORE) ||
(FileInfo.FileType == EFI_FV_FILETYPE_PEIM) ||
(FileInfo.FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER))
{
IsPeiModule = TRUE;
}
两步校验的目的
步骤 | 函数 | 校验级别 | 可能出错场景 |
---|---|---|---|
① 快速过滤 | FindFileByType | 仅看 FFS 头 1 字节 Type | 链接脚本写错、平台移植时 GUID 复用 |
② 最终确认 | FfsGetFileInfo | 再读一次头字段 | ① 的过滤结果与头字段不一致 |
** 确保不能重定位的映像不会被重定位到内存
C
if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) &&
((!IsPeiModule) || PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
(!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) ||
(IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))
)
{
DEBUG ((DEBUG_INFO|DEBUG_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN)Pe32Data));
}
** 将默认基址设置为当前映像地址
C
ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data;
** 当内存准备好且可重定位的时候为映像分配内存
C
if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) &&
((!IsPeiModule) || PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
(!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) ||
(IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))
)
{
//
// Allocate more buffer to avoid buffer overflow.
//
if (ImageContext.IsTeImage) {
AlignImageSize = ImageContext.ImageSize + ((EFI_TE_IMAGE_HEADER *)Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
} else {
AlignImageSize = ImageContext.ImageSize;
}
if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
AlignImageSize += ImageContext.SectionAlignment;
}
if ((PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext, Private);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
//
// The PEIM is not assigned valid address, try to allocate page to load it.
//
Status = PeiServicesAllocatePages (
EfiBootServicesCode,
EFI_SIZE_TO_PAGES ((UINT32)AlignImageSize),
&ImageContext.ImageAddress
);
}
} else {
Status = PeiServicesAllocatePages (
EfiBootServicesCode,
EFI_SIZE_TO_PAGES ((UINT32)AlignImageSize),
&ImageContext.ImageAddress
);
}
if (!EFI_ERROR (Status)) {
//
// Adjust the Image Address to make sure it is section alignment.
//
if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
ImageContext.ImageAddress =
(ImageContext.ImageAddress + ImageContext.SectionAlignment - 1) &
~((UINTN)ImageContext.SectionAlignment - 1);
}
//
// Fix alignment requirement when Load IPF TeImage into memory.
// Skip the reserved space for the stripped PeHeader when load TeImage into memory.
//
if (ImageContext.IsTeImage) {
ImageContext.ImageAddress = ImageContext.ImageAddress +
((EFI_TE_IMAGE_HEADER *)Pe32Data)->StrippedSize -
sizeof (EFI_TE_IMAGE_HEADER);
}
} else {
//
// No enough memory resource.
//
if (IsXipImage) {
//
// XIP image can still be invoked.
//
ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data;
ReturnStatus = EFI_WARN_BUFFER_TOO_SMALL;
} else {
//
// Non XIP image can't be loaded because no enough memory is allocated.
//
ASSERT (FALSE);
return EFI_OUT_OF_RESOURCES;
}
}
}
** 加载映像到内存
C
RETURN_STATUS
EFIAPI
PeCoffLoaderLoadImage (
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
)
{
RETURN_STATUS Status;
EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;
EFI_IMAGE_SECTION_HEADER *FirstSection;
EFI_IMAGE_SECTION_HEADER *Section;
UINTN NumberOfSections;
UINTN Index;
CHAR8 *Base;
CHAR8 *End;
EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
UINTN Size;
UINT32 TempDebugEntryRva;
UINT32 NumberOfRvaAndSizes;
EFI_IMAGE_RESOURCE_DIRECTORY *ResourceDirectory;
EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceDirectoryEntry;
EFI_IMAGE_RESOURCE_DIRECTORY_STRING *ResourceDirectoryString;
EFI_IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry;
CHAR16 *String;
UINT32 Offset;
UINT32 TeStrippedOffset;
ASSERT (ImageContext != NULL);
//
// Assume success
//
ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
//
// Copy the provided context information into our local version, get what we
// can from the original image, and then use that to make sure everything
// is legit.
//
CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
Status = PeCoffLoaderGetImageInfo (&CheckContext);
if (RETURN_ERROR (Status)) {
return Status;
}
//
// Make sure there is enough allocated space for the image being loaded
//
if (ImageContext->ImageSize < CheckContext.ImageSize) {
ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;
return RETURN_BUFFER_TOO_SMALL;
}
if (ImageContext->ImageAddress == 0) {
//
// Image cannot be loaded into 0 address.
//
ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
return RETURN_INVALID_PARAMETER;
}
//
// If there's no relocations, then make sure it's not a runtime driver,
// and that it's being loaded at the linked address.
//
if (CheckContext.RelocationsStripped) {
//
// If the image does not contain relocations and it is a runtime driver
// then return an error.
//
if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
return RETURN_LOAD_ERROR;
}
//
// If the image does not contain relocations, and the requested load address
// is not the linked address, then return an error.
//
if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
return RETURN_INVALID_PARAMETER;
}
}
//
// Make sure the allocated space has the proper section alignment
//
if (!(ImageContext->IsTeImage)) {
if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
return RETURN_INVALID_PARAMETER;
}
}
//
// Read the entire PE/COFF or TE header into memory
//
if (!(ImageContext->IsTeImage)) {
Status = ImageContext->ImageRead (
ImageContext->Handle,
0,
&ImageContext->SizeOfHeaders,
(VOID *)(UINTN)ImageContext->ImageAddress
);
Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
FirstSection = (EFI_IMAGE_SECTION_HEADER *)(
(UINTN)ImageContext->ImageAddress +
ImageContext->PeCoffHeaderOffset +
sizeof (UINT32) +
sizeof (EFI_IMAGE_FILE_HEADER) +
Hdr.Pe32->FileHeader.SizeOfOptionalHeader
);
NumberOfSections = (UINTN)(Hdr.Pe32->FileHeader.NumberOfSections);
TeStrippedOffset = 0;
} else {
Status = ImageContext->ImageRead (
ImageContext->Handle,
0,
&ImageContext->SizeOfHeaders,
(void *)(UINTN)ImageContext->ImageAddress
);
Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
FirstSection = (EFI_IMAGE_SECTION_HEADER *)(
(UINTN)ImageContext->ImageAddress +
sizeof (EFI_TE_IMAGE_HEADER)
);
NumberOfSections = (UINTN)(Hdr.Te->NumberOfSections);
TeStrippedOffset = (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
}
if (RETURN_ERROR (Status)) {
ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
return RETURN_LOAD_ERROR;
}
//
// Load each section of the image
//
Section = FirstSection;
for (Index = 0; Index < NumberOfSections; Index++) {
//
// Read the section
//
Size = (UINTN)Section->Misc.VirtualSize;
if ((Size == 0) || (Size > Section->SizeOfRawData)) {
Size = (UINTN)Section->SizeOfRawData;
}
//
// Compute sections address
//
Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress, TeStrippedOffset);
End = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress + Section->Misc.VirtualSize - 1, TeStrippedOffset);
//
// If the size of the section is non-zero and the base address or end address resolved to 0, then fail.
//
if ((Size > 0) && ((Base == NULL) || (End == NULL))) {
ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;
return RETURN_LOAD_ERROR;
}
if ((Section->SizeOfRawData > 0) && (Base != NULL)) {
Status = ImageContext->ImageRead (
ImageContext->Handle,
Section->PointerToRawData - TeStrippedOffset,
&Size,
Base
);
if (RETURN_ERROR (Status)) {
ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
return Status;
}
}
//
// If raw size is less then virtual size, zero fill the remaining
//
if ((Size < Section->Misc.VirtualSize) && (Base != NULL)) {
ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);
}
//
// Next Section
//
Section += 1;
}
//
// Get image's entry point
//
if (!(ImageContext->IsTeImage)) {
//
// Sizes of AddressOfEntryPoint are different so we need to do this safely
//
if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
//
// Use PE32 offset
//
ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
ImageContext,
(UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint,
0
);
} else {
//
// Use PE32+ offset
//
ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
ImageContext,
(UINTN)Hdr.Pe32Plus->OptionalHeader.AddressOfEntryPoint,
0
);
}
} else {
ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
ImageContext,
(UINTN)Hdr.Te->AddressOfEntryPoint,
TeStrippedOffset
);
}
//
// Determine the size of the fixup data
//
// Per the PE/COFF spec, you can't assume that a given data directory
// is present in the image. You have to check the NumberOfRvaAndSizes in
// the optional header to verify a desired directory entry is there.
//
if (!(ImageContext->IsTeImage)) {
if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
//
// Use PE32 offset
//
NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
} else {
//
// Use PE32+ offset
//
NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
}
//
// Must use UINT64 here, because there might a case that 32bit loader to load 64bit image.
//
if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINT64);
} else {
ImageContext->FixupDataSize = 0;
}
} else {
DirectoryEntry = &Hdr.Te->DataDirectory[0];
ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINT64);
}
//
// Consumer must allocate a buffer for the relocation fixup log.
// Only used for runtime drivers.
//
ImageContext->FixupData = NULL;
//
// Load the Codeview information if present
//
if (ImageContext->DebugDirectoryEntryRva != 0) {
DebugEntry = PeCoffLoaderImageAddress (
ImageContext,
ImageContext->DebugDirectoryEntryRva,
TeStrippedOffset
);
if (DebugEntry == NULL) {
ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
return RETURN_LOAD_ERROR;
}
TempDebugEntryRva = DebugEntry->RVA;
if ((DebugEntry->RVA == 0) && (DebugEntry->FileOffset != 0)) {
Section--;
if ((UINTN)Section->SizeOfRawData < Section->Misc.VirtualSize) {
TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
} else {
TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
}
}
if (TempDebugEntryRva != 0) {
ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva, TeStrippedOffset);
if (ImageContext->CodeView == NULL) {
ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
return RETURN_LOAD_ERROR;
}
if (DebugEntry->RVA == 0) {
Size = DebugEntry->SizeOfData;
Status = ImageContext->ImageRead (
ImageContext->Handle,
DebugEntry->FileOffset - TeStrippedOffset,
&Size,
ImageContext->CodeView
);
//
// Should we apply fix up to this field according to the size difference between PE and TE?
// Because now we maintain TE header fields unfixed, this field will also remain as they are
// in original PE image.
//
if (RETURN_ERROR (Status)) {
ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
return RETURN_LOAD_ERROR;
}
DebugEntry->RVA = TempDebugEntryRva;
}
switch (*(UINT32 *)ImageContext->CodeView) {
case CODEVIEW_SIGNATURE_NB10:
if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)) {
ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
return RETURN_UNSUPPORTED;
}
ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
break;
case CODEVIEW_SIGNATURE_RSDS:
if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY)) {
ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
return RETURN_UNSUPPORTED;
}
ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
break;
case CODEVIEW_SIGNATURE_MTOC:
if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY)) {
ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
return RETURN_UNSUPPORTED;
}
ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);
break;
default:
break;
}
}
}
//
// Get Image's HII resource section
//
ImageContext->HiiResourceData = 0;
if (!(ImageContext->IsTeImage)) {
if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
//
// Use PE32 offset
//
NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
} else {
//
// Use PE32+ offset
//
NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
}
if ((NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE) && (DirectoryEntry->Size != 0)) {
Base = PeCoffLoaderImageAddress (ImageContext, DirectoryEntry->VirtualAddress, 0);
if (Base != NULL) {
ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *)Base;
Offset = sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) *
(ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
if (Offset > DirectoryEntry->Size) {
ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
return RETURN_UNSUPPORTED;
}
ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(ResourceDirectory + 1);
for (Index = 0; Index < ResourceDirectory->NumberOfNamedEntries; Index++) {
if (ResourceDirectoryEntry->u1.s.NameIsString) {
//
// Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.
//
if (ResourceDirectoryEntry->u1.s.NameOffset >= DirectoryEntry->Size) {
ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
return RETURN_UNSUPPORTED;
}
ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *)(Base + ResourceDirectoryEntry->u1.s.NameOffset);
String = &ResourceDirectoryString->String[0];
if ((ResourceDirectoryString->Length == 3) &&
(String[0] == L'H') &&
(String[1] == L'I') &&
(String[2] == L'I'))
{
//
// Resource Type "HII" found
//
if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
//
// Move to next level - resource Name
//
if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {
ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
return RETURN_UNSUPPORTED;
}
ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *)(Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);
Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) +
sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
if (Offset > DirectoryEntry->Size) {
ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
return RETURN_UNSUPPORTED;
}
ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(ResourceDirectory + 1);
if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
//
// Move to next level - resource Language
//
if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {
ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
return RETURN_UNSUPPORTED;
}
ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *)(Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);
Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) +
sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
if (Offset > DirectoryEntry->Size) {
ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
return RETURN_UNSUPPORTED;
}
ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(ResourceDirectory + 1);
}
}
//
// Now it ought to be resource Data
//
if (!ResourceDirectoryEntry->u2.s.DataIsDirectory) {
if (ResourceDirectoryEntry->u2.OffsetToData >= DirectoryEntry->Size) {
ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
return RETURN_UNSUPPORTED;
}
ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *)(Base + ResourceDirectoryEntry->u2.OffsetToData);
ImageContext->HiiResourceData = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (ImageContext, ResourceDataEntry->OffsetToData, 0);
break;
}
}
}
ResourceDirectoryEntry++;
}
}
}
}
return Status;
}
** 应用重定位修正
C
RETURN_STATUS
EFIAPI
PeCoffLoaderRelocateImage (
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
)
{
RETURN_STATUS Status;
EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
EFI_IMAGE_DATA_DIRECTORY *RelocDir;
UINT64 Adjust;
EFI_IMAGE_BASE_RELOCATION *RelocBaseOrg;
EFI_IMAGE_BASE_RELOCATION *RelocBase;
EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
UINT16 *Reloc;
UINT16 *RelocEnd;
CHAR8 *Fixup;
CHAR8 *FixupBase;
UINT16 *Fixup16;
UINT32 *Fixup32;
UINT64 *Fixup64;
CHAR8 *FixupData;
PHYSICAL_ADDRESS BaseAddress;
UINT32 NumberOfRvaAndSizes;
UINT32 TeStrippedOffset;
UINT32 EndAddress;
ASSERT (ImageContext != NULL);
//
// Assume success
//
ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
//
// If there are no relocation entries, then we are done
//
if (ImageContext->RelocationsStripped) {
// Applies additional environment specific actions to relocate fixups
// to a PE/COFF image if needed
PeCoffLoaderRelocateImageExtraAction (ImageContext);
return RETURN_SUCCESS;
}
//
// If the destination address is not 0, use that rather than the
// image address as the relocation target.
//
if (ImageContext->DestinationAddress != 0) {
BaseAddress = ImageContext->DestinationAddress;
} else {
BaseAddress = ImageContext->ImageAddress;
}
if (!(ImageContext->IsTeImage)) {
Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
TeStrippedOffset = 0;
if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
//
// Use PE32 offset
//
Adjust = (UINT64)BaseAddress - Hdr.Pe32->OptionalHeader.ImageBase;
if (Adjust != 0) {
Hdr.Pe32->OptionalHeader.ImageBase = (UINT32)BaseAddress;
}
NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
RelocDir = &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
} else {
//
// Use PE32+ offset
//
Adjust = (UINT64)BaseAddress - Hdr.Pe32Plus->OptionalHeader.ImageBase;
if (Adjust != 0) {
Hdr.Pe32Plus->OptionalHeader.ImageBase = (UINT64)BaseAddress;
}
NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
RelocDir = &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
}
//
// Find the relocation block
// Per the PE/COFF spec, you can't assume that a given data directory
// is present in the image. You have to check the NumberOfRvaAndSizes in
// the optional header to verify a desired directory entry is there.
//
if ((NumberOfRvaAndSizes < EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC)) {
RelocDir = NULL;
}
} else {
Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
TeStrippedOffset = (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
Adjust = (UINT64)(BaseAddress - (Hdr.Te->ImageBase + TeStrippedOffset));
if (Adjust != 0) {
Hdr.Te->ImageBase = (UINT64)(BaseAddress - TeStrippedOffset);
}
//
// Find the relocation block
//
RelocDir = &Hdr.Te->DataDirectory[0];
}
RelocBase = NULL;
RelocBaseEnd = NULL;
if ((RelocDir != NULL) && (RelocDir->Size > 0)) {
Status = SafeUint32Add (RelocDir->VirtualAddress, (RelocDir->Size - 1), &EndAddress);
if (!RETURN_ERROR (Status)) {
RelocBase = (EFI_IMAGE_BASE_RELOCATION *)PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress, TeStrippedOffset);
RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *)PeCoffLoaderImageAddress (
ImageContext,
EndAddress,
TeStrippedOffset
);
}
if ((RelocBase == NULL) || (RelocBaseEnd == NULL) || ((UINTN)RelocBaseEnd < (UINTN)RelocBase)) {
ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
DEBUG ((DEBUG_ERROR, "Relocation block is not valid\n"));
return RETURN_LOAD_ERROR;
}
}
RelocBaseOrg = RelocBase;
//
// If Adjust is not zero, then apply fix ups to the image
//
if (Adjust != 0) {
//
// Run the relocation information and apply the fixups
//
FixupData = ImageContext->FixupData;
while ((UINTN)RelocBase < (UINTN)RelocBaseEnd) {
Reloc = (UINT16 *)((CHAR8 *)RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
//
// Add check for RelocBase->SizeOfBlock field.
//
if (RelocBase->SizeOfBlock == 0) {
ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
return RETURN_LOAD_ERROR;
}
if ((UINTN)RelocBase > MAX_ADDRESS - RelocBase->SizeOfBlock) {
ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
return RETURN_LOAD_ERROR;
}
RelocEnd = (UINT16 *)((CHAR8 *)RelocBase + RelocBase->SizeOfBlock);
if ((UINTN)RelocEnd > (UINTN)RelocBaseOrg + RelocDir->Size) {
ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
return RETURN_LOAD_ERROR;
}
FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress, TeStrippedOffset);
if (FixupBase == NULL) {
ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
return RETURN_LOAD_ERROR;
}
//
// Run this relocation record
//
while ((UINTN)Reloc < (UINTN)RelocEnd) {
Fixup = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress + (*Reloc & 0xFFF), TeStrippedOffset);
if (Fixup == NULL) {
ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
return RETURN_LOAD_ERROR;
}
switch ((*Reloc) >> 12) {
case EFI_IMAGE_REL_BASED_ABSOLUTE:
break;
case EFI_IMAGE_REL_BASED_HIGH:
Fixup16 = (UINT16 *)Fixup;
*Fixup16 = (UINT16)(*Fixup16 + ((UINT16)((UINT32)Adjust >> 16)));
if (FixupData != NULL) {
*(UINT16 *)FixupData = *Fixup16;
FixupData = FixupData + sizeof (UINT16);
}
break;
case EFI_IMAGE_REL_BASED_LOW:
Fixup16 = (UINT16 *)Fixup;
*Fixup16 = (UINT16)(*Fixup16 + (UINT16)Adjust);
if (FixupData != NULL) {
*(UINT16 *)FixupData = *Fixup16;
FixupData = FixupData + sizeof (UINT16);
}
break;
case EFI_IMAGE_REL_BASED_HIGHLOW:
Fixup32 = (UINT32 *)Fixup;
*Fixup32 = *Fixup32 + (UINT32)Adjust;
if (FixupData != NULL) {
FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
*(UINT32 *)FixupData = *Fixup32;
FixupData = FixupData + sizeof (UINT32);
}
break;
case EFI_IMAGE_REL_BASED_DIR64:
Fixup64 = (UINT64 *)Fixup;
*Fixup64 = *Fixup64 + (UINT64)Adjust;
if (FixupData != NULL) {
FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));
*(UINT64 *)(FixupData) = *Fixup64;
FixupData = FixupData + sizeof (UINT64);
}
break;
default:
//
// The common code does not handle some of the stranger IPF relocations
// PeCoffLoaderRelocateImageEx () adds support for these complex fixups
// on IPF and is a No-Op on other architectures.
//
Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
if (RETURN_ERROR (Status)) {
ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
return Status;
}
}
//
// Next relocation record
//
Reloc += 1;
}
//
// Next reloc block
//
RelocBase = (EFI_IMAGE_BASE_RELOCATION *)RelocEnd;
}
ASSERT ((UINTN)FixupData <= (UINTN)ImageContext->FixupData + ImageContext->FixupDataSize);
//
// Adjust the EntryPoint to match the linked-to address
//
if (ImageContext->DestinationAddress != 0) {
ImageContext->EntryPoint -= (UINT64)ImageContext->ImageAddress;
ImageContext->EntryPoint += (UINT64)ImageContext->DestinationAddress;
}
}
// Applies additional environment specific actions to relocate fixups
// to a PE/COFF image if needed
PeCoffLoaderRelocateImageExtraAction (ImageContext);
return RETURN_SUCCESS;
}
* 获取进入点
C
Pe32Data = (VOID *)((UINTN)ImageAddress);
*EntryPoint = ImageEntryPoint;
调用PEIM安全验证服务
C
EFI_STATUS
VerifyPeim (
IN PEI_CORE_INSTANCE *PrivateData,
IN EFI_PEI_FV_HANDLE VolumeHandle,
IN EFI_PEI_FILE_HANDLE FileHandle,
IN UINT32 AuthenticationStatus
)
{
EFI_STATUS Status;
BOOLEAN DeferExecution;
Status = EFI_NOT_FOUND;
if (PrivateData->PrivateSecurityPpi == NULL) {
//
// Check AuthenticationStatus first.
//
if ((AuthenticationStatus & EFI_AUTH_STATUS_IMAGE_SIGNED) != 0) {
if ((AuthenticationStatus & (EFI_AUTH_STATUS_TEST_FAILED | EFI_AUTH_STATUS_NOT_TESTED)) != 0) {
Status = EFI_SECURITY_VIOLATION;
}
}
} else {
//
// Check to see if the image is OK
//
Status = PrivateData->PrivateSecurityPpi->AuthenticationState (
(CONST EFI_PEI_SERVICES **)&PrivateData->Ps,
PrivateData->PrivateSecurityPpi,
AuthenticationStatus,
VolumeHandle,
FileHandle,
&DeferExecution
);
if (DeferExecution) {
Status = EFI_SECURITY_VIOLATION;
}
}
return Status;
}
变更PEIM调度状态
C
Private->Fv[FvCount].PeimState[PeimCount]++;
尝试调用PEIM进入点
C
PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices);
Private->PeimDispatchOnThisPass = TRUE;
windbg
0: kd> .reload /i PCDPEIM=0x`83b5a0
C
EFI_STATUS
EFIAPI
_ModuleEntryPoint (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
if (_gPeimRevision != 0) {
//
// Make sure that the PEI spec revision of the platform is >= PEI spec revision of the driver
//
ASSERT ((*PeiServices)->Hdr.Revision >= _gPeimRevision);
}
//
// Call constructor for all libraries
//
ProcessLibraryConstructorList (FileHandle, PeiServices);
//
// Call the driver entry point
//
return ProcessModuleEntryPointList (FileHandle, PeiServices);
}
* 为所有库调用构造函数
C
VOID
EFIAPI
ProcessLibraryConstructorList (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
Status = BaseDebugLibSerialPortConstructor ();
ASSERT_RETURN_ERROR (Status);
}
C
RETURN_STATUS
EFIAPI
BaseDebugLibSerialPortConstructor (
VOID
)
{
return SerialPortInitialize ();
}
* 调用PEIM进入点
C
EFI_STATUS
EFIAPI
ProcessModuleEntryPointList (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
return PcdPeimInit (FileHandle, PeiServices);
}
** PCD PEIM 模块的主入口函数
PCD PEIM模块主入口函数介绍:
C
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;
OldPpiList = NULL;
Status = PeiServicesLocatePpi (
&gPcdPpiGuid,
0,
&OldPpiList,
&Ppi
);
ASSERT_EFI_ERROR (Status);
if (OldPpiList != NULL) {
Status = PeiServicesReInstallPpi (OldPpiList, &mPpiList[0]);
ASSERT_EFI_ERROR (Status);
}
OldPpiList2 = NULL;
Status = PeiServicesLocatePpi (
&gGetPcdInfoPpiGuid,
0,
&OldPpiList2,
&Ppi2
);
ASSERT_EFI_ERROR (Status);
if (OldPpiList2 != NULL) {
Status = PeiServicesReInstallPpi (OldPpiList2, &mPpiList2[0]);
ASSERT_EFI_ERROR (Status);
}
OldPpiList = NULL;
Status = PeiServicesLocatePpi (
&gEfiPeiPcdPpiGuid,
0,
&OldPpiList,
&Ppi
);
ASSERT_EFI_ERROR (Status);
if (OldPpiList != NULL) {
Status = PeiServicesReInstallPpi (OldPpiList, &mPpiList[1]);
ASSERT_EFI_ERROR (Status);
}
OldPpiList2 = NULL;
Status = PeiServicesLocatePpi (
&gEfiGetPcdInfoPpiGuid,
0,
&OldPpiList2,
&Ppi2
);
ASSERT_EFI_ERROR (Status);
if (OldPpiList2 != NULL) {
Status = PeiServicesReInstallPpi (OldPpiList2, &mPpiList2[1]);
ASSERT_EFI_ERROR (Status);
}
return Status;
}
BuildPcdDatabase (FileHandle);
//
// Install PCD_PPI and EFI_PEI_PCD_PPI.
//
Status = PeiServicesInstallPpi (&mPpiList[0]);
ASSERT_EFI_ERROR (Status);
//
// Install GET_PCD_INFO_PPI and EFI_GET_PCD_INFO_PPI.
//
Status = PeiServicesInstallPpi (&mPpiList2[0]);
ASSERT_EFI_ERROR (Status);
Status = PeiServicesNotifyPpi (&mEndOfPeiSignalPpiNotifyList[0]);
ASSERT_EFI_ERROR (Status);
Status = PeiRegisterCallBackOnSet (
&gEfiMdeModulePkgTokenSpaceGuid,
PcdToken (PcdSetNvStoreDefaultId),
PcdSetNvStoreDefaultIdCallBack
);
ASSERT_EFI_ERROR (Status);
return Status;
}
报告PEIM 已初始化完毕
C
REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
EFI_PROGRESS_CODE,
(EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END),
(VOID *)(&PeimFileHandle),
sizeof (PeimFileHandle)
);
C
BOOLEAN
EFIAPI
ReportProgressCodeEnabled (
VOID
)
{
return (BOOLEAN)((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED) != 0);
}
C
EFI_STATUS
EFIAPI
ReportStatusCodeWithExtendedData (
IN EFI_STATUS_CODE_TYPE Type,
IN EFI_STATUS_CODE_VALUE Value,
IN CONST VOID *ExtendedData,
IN UINTN ExtendedDataSize
)
{
ASSERT (ExtendedData != NULL);
ASSERT (ExtendedDataSize != 0);
return ReportStatusCodeEx (
Type,
Value,
0,
NULL,
NULL,
ExtendedData,
ExtendedDataSize
);
}
检测性能测量值是否可以被记录
C
PERF_START_IMAGE_END (PeimFileHandle);
C
BOOLEAN
EFIAPI
LogPerformanceMeasurementEnabled (
IN CONST UINTN Type
)
{
//
// When Performance measurement is enabled and the type is not filtered, the performance can be logged.
//
if (PerformanceMeasurementEnabled () && ((PcdGet8 (PcdPerformanceLibraryPropertyMask) & Type) == 0)) {
return TRUE;
}
return FALSE;
}
根据SwitchStackSignal切换栈
轮到 MemoryInit PEIM 时才把 SwitchStackSignal 置 TRUE
C
PeiCheckAndSwitchStack (SecCoreData, Private);
C
VOID
PeiCheckAndSwitchStack (
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
IN PEI_CORE_INSTANCE *Private
)
{
VOID *LoadFixPeiCodeBegin;
EFI_STATUS Status;
CONST EFI_PEI_SERVICES **PeiServices;
UINT64 NewStackSize;
EFI_PHYSICAL_ADDRESS TopOfOldStack;
EFI_PHYSICAL_ADDRESS TopOfNewStack;
UINTN StackOffset;
BOOLEAN StackOffsetPositive;
EFI_PHYSICAL_ADDRESS TemporaryRamBase;
UINTN TemporaryRamSize;
UINTN TemporaryStackSize;
VOID *TemporaryStackBase;
UINTN PeiTemporaryRamSize;
VOID *PeiTemporaryRamBase;
EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI *TemporaryRamSupportPpi;
EFI_PHYSICAL_ADDRESS BaseOfNewHeap;
EFI_PHYSICAL_ADDRESS HoleMemBase;
UINTN HoleMemSize;
UINTN HeapTemporaryRamSize;
EFI_PHYSICAL_ADDRESS TempBase1;
UINTN TempSize1;
EFI_PHYSICAL_ADDRESS TempBase2;
UINTN TempSize2;
UINTN Index;
PeiServices = (CONST EFI_PEI_SERVICES **)&Private->Ps;
if (Private->SwitchStackSignal) {
//
// Before switch stack from temporary memory to permanent memory, calculate the heap and stack
// usage in temporary memory for debugging.
//
DEBUG_CODE_BEGIN ();
UINT32 *StackPointer;
EFI_PEI_HOB_POINTERS Hob;
for ( StackPointer = (UINT32 *)SecCoreData->StackBase;
(StackPointer < (UINT32 *)((UINTN)SecCoreData->StackBase + SecCoreData->StackSize)) \
&& (*StackPointer == PcdGet32 (PcdInitValueInTempStack));
StackPointer++)
{
}
DEBUG ((DEBUG_INFO, "Temp Stack : BaseAddress=0x%p Length=0x%X\n", SecCoreData->StackBase, (UINT32)SecCoreData->StackSize));
DEBUG ((DEBUG_INFO, "Temp Heap : BaseAddress=0x%p Length=0x%X\n", SecCoreData->PeiTemporaryRamBase, (UINT32)SecCoreData->PeiTemporaryRamSize));
DEBUG ((DEBUG_INFO, "Total temporary memory: %d bytes.\n", (UINT32)SecCoreData->TemporaryRamSize));
DEBUG ((
DEBUG_INFO,
" temporary memory stack ever used: %d bytes.\n",
(UINT32)(SecCoreData->StackSize - ((UINTN)StackPointer - (UINTN)SecCoreData->StackBase))
));
DEBUG ((
DEBUG_INFO,
" temporary memory heap used for HobList: %d bytes.\n",
(UINT32)((UINTN)Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - (UINTN)Private->HobList.Raw)
));
DEBUG ((
DEBUG_INFO,
" temporary memory heap occupied by memory pages: %d bytes.\n",
(UINT32)(UINTN)(Private->HobList.HandoffInformationTable->EfiMemoryTop - Private->HobList.HandoffInformationTable->EfiFreeMemoryTop)
));
for (Hob.Raw = Private->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
DEBUG ((
DEBUG_INFO,
"Memory Allocation 0x%08x 0x%0lx - 0x%0lx\n", \
Hob.MemoryAllocation->AllocDescriptor.MemoryType, \
Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress, \
Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength - 1
));
}
}
DEBUG_CODE_END ();
if ((PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
//
// Loading Module at Fixed Address is enabled
//
PeiLoadFixAddressHook (Private);
//
// If Loading Module at Fixed Address is enabled, Allocating memory range for Pei code range.
//
LoadFixPeiCodeBegin = AllocatePages ((UINTN)PcdGet32 (PcdLoadFixAddressPeiCodePageNumber));
DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PeiCodeBegin = 0x%lX, PeiCodeTop= 0x%lX\n", (UINT64)(UINTN)LoadFixPeiCodeBegin, (UINT64)((UINTN)LoadFixPeiCodeBegin + PcdGet32 (PcdLoadFixAddressPeiCodePageNumber) * EFI_PAGE_SIZE)));
}
//
// Reserve the size of new stack at bottom of physical memory
//
// The size of new stack in permanent memory must be the same size
// or larger than the size of old stack in temporary memory.
// But if new stack is smaller than the size of old stack, we also reserve
// the size of old stack at bottom of permanent memory.
//
NewStackSize = RShiftU64 (Private->PhysicalMemoryLength, 1);
NewStackSize = ALIGN_VALUE (NewStackSize, EFI_PAGE_SIZE);
NewStackSize = MIN (PcdGet32 (PcdPeiCoreMaxPeiStackSize), NewStackSize);
DEBUG ((DEBUG_INFO, "Old Stack size %d, New stack size %d\n", (UINT32)SecCoreData->StackSize, (UINT32)NewStackSize));
ASSERT (NewStackSize >= SecCoreData->StackSize);
//
// Calculate stack offset and heap offset between temporary memory and new permanent
// memory separately.
//
TopOfOldStack = (UINTN)SecCoreData->StackBase + SecCoreData->StackSize;
TopOfNewStack = Private->PhysicalMemoryBegin + NewStackSize;
if (TopOfNewStack >= TopOfOldStack) {
StackOffsetPositive = TRUE;
StackOffset = (UINTN)(TopOfNewStack - TopOfOldStack);
} else {
StackOffsetPositive = FALSE;
StackOffset = (UINTN)(TopOfOldStack - TopOfNewStack);
}
Private->StackOffsetPositive = StackOffsetPositive;
Private->StackOffset = StackOffset;
//
// Build Stack HOB that describes the permanent memory stack
//
DEBUG ((DEBUG_INFO, "Stack Hob: BaseAddress=0x%lX Length=0x%lX\n", TopOfNewStack - NewStackSize, NewStackSize));
BuildStackHob (TopOfNewStack - NewStackSize, NewStackSize);
//
// Cache information from SecCoreData into locals before SecCoreData is converted to a permanent memory address
//
TemporaryRamBase = (EFI_PHYSICAL_ADDRESS)(UINTN)SecCoreData->TemporaryRamBase;
TemporaryRamSize = SecCoreData->TemporaryRamSize;
TemporaryStackSize = SecCoreData->StackSize;
TemporaryStackBase = SecCoreData->StackBase;
PeiTemporaryRamSize = SecCoreData->PeiTemporaryRamSize;
PeiTemporaryRamBase = SecCoreData->PeiTemporaryRamBase;
//
// TemporaryRamSupportPpi is produced by platform's SEC
//
Status = PeiServicesLocatePpi (
&gEfiTemporaryRamSupportPpiGuid,
0,
NULL,
(VOID **)&TemporaryRamSupportPpi
);
if (!EFI_ERROR (Status)) {
//
// Heap Offset
//
BaseOfNewHeap = TopOfNewStack;
if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {
Private->HeapOffsetPositive = TRUE;
Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);
} else {
Private->HeapOffsetPositive = FALSE;
Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);
}
DEBUG ((DEBUG_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64)Private->HeapOffset, (UINT64)Private->StackOffset));
//
// Calculate new HandOffTable and PrivateData address in permanent memory's stack
//
if (StackOffsetPositive) {
SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData + StackOffset);
Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private + StackOffset);
} else {
SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData - StackOffset);
Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private - StackOffset);
}
//
// Temporary Ram Support PPI is provided by platform, it will copy
// temporary memory to permanent memory and do stack switching.
// After invoking Temporary Ram Support PPI, the following code's
// stack is in permanent memory.
//
TemporaryRamSupportPpi->TemporaryRamMigration (
PeiServices,
TemporaryRamBase,
(EFI_PHYSICAL_ADDRESS)(UINTN)(TopOfNewStack - TemporaryStackSize),
TemporaryRamSize
);
//
// Migrate memory pages allocated in pre-memory phase.
// It could not be called before calling TemporaryRamSupportPpi->TemporaryRamMigration()
// as the migrated memory pages may be overridden by TemporaryRamSupportPpi->TemporaryRamMigration().
//
MigrateMemoryPages (Private, TRUE);
//
// Entry PEI Phase 2
//
PeiCore (SecCoreData, NULL, Private);
} else {
//
// Migrate memory pages allocated in pre-memory phase.
//
MigrateMemoryPages (Private, FALSE);
//
// Migrate the PEI Services Table pointer from temporary RAM to permanent RAM.
//
MigratePeiServicesTablePointer ();
//
// Heap Offset
//
BaseOfNewHeap = TopOfNewStack;
HoleMemBase = TopOfNewStack;
HoleMemSize = TemporaryRamSize - PeiTemporaryRamSize - TemporaryStackSize;
if (HoleMemSize != 0) {
//
// Make sure HOB List start address is 8 byte alignment.
//
BaseOfNewHeap = ALIGN_VALUE (BaseOfNewHeap + HoleMemSize, 8);
}
if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {
Private->HeapOffsetPositive = TRUE;
Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);
} else {
Private->HeapOffsetPositive = FALSE;
Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);
}
DEBUG ((DEBUG_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64)Private->HeapOffset, (UINT64)Private->StackOffset));
//
// Migrate Heap
//
HeapTemporaryRamSize = (UINTN)(Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - Private->HobList.HandoffInformationTable->EfiMemoryBottom);
ASSERT (BaseOfNewHeap + HeapTemporaryRamSize <= Private->FreePhysicalMemoryTop);
CopyMem ((UINT8 *)(UINTN)BaseOfNewHeap, PeiTemporaryRamBase, HeapTemporaryRamSize);
//
// Migrate Stack
//
CopyMem ((UINT8 *)(UINTN)(TopOfNewStack - TemporaryStackSize), TemporaryStackBase, TemporaryStackSize);
//
// Copy Hole Range Data
//
if (HoleMemSize != 0) {
//
// Prepare Hole
//
if (PeiTemporaryRamBase < TemporaryStackBase) {
TempBase1 = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiTemporaryRamBase;
TempSize1 = PeiTemporaryRamSize;
TempBase2 = (EFI_PHYSICAL_ADDRESS)(UINTN)TemporaryStackBase;
TempSize2 = TemporaryStackSize;
} else {
TempBase1 = (EFI_PHYSICAL_ADDRESS)(UINTN)TemporaryStackBase;
TempSize1 = TemporaryStackSize;
TempBase2 = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiTemporaryRamBase;
TempSize2 = PeiTemporaryRamSize;
}
if (TemporaryRamBase < TempBase1) {
Private->HoleData[0].Base = TemporaryRamBase;
Private->HoleData[0].Size = (UINTN)(TempBase1 - TemporaryRamBase);
}
if (TempBase1 + TempSize1 < TempBase2) {
Private->HoleData[1].Base = TempBase1 + TempSize1;
Private->HoleData[1].Size = (UINTN)(TempBase2 - TempBase1 - TempSize1);
}
if (TempBase2 + TempSize2 < TemporaryRamBase + TemporaryRamSize) {
Private->HoleData[2].Base = TempBase2 + TempSize2;
Private->HoleData[2].Size = (UINTN)(TemporaryRamBase + TemporaryRamSize - TempBase2 - TempSize2);
}
//
// Copy Hole Range data.
//
for (Index = 0; Index < HOLE_MAX_NUMBER; Index++) {
if (Private->HoleData[Index].Size > 0) {
if (HoleMemBase > Private->HoleData[Index].Base) {
Private->HoleData[Index].OffsetPositive = TRUE;
Private->HoleData[Index].Offset = (UINTN)(HoleMemBase - Private->HoleData[Index].Base);
} else {
Private->HoleData[Index].OffsetPositive = FALSE;
Private->HoleData[Index].Offset = (UINTN)(Private->HoleData[Index].Base - HoleMemBase);
}
CopyMem ((VOID *)(UINTN)HoleMemBase, (VOID *)(UINTN)Private->HoleData[Index].Base, Private->HoleData[Index].Size);
HoleMemBase = HoleMemBase + Private->HoleData[Index].Size;
}
}
}
//
// Switch new stack
//
SwitchStack (
(SWITCH_STACK_ENTRY_POINT)(UINTN)PeiCoreEntry,
(VOID *)SecCoreData,
(VOID *)Private,
(VOID *)(UINTN)TopOfNewStack
);
}
//
// Code should not come here
//
ASSERT (FALSE);
}
}
在调度级别处理通知列表
分别处理新增的Notify和PPI
C
VOID
ProcessDispatchNotifyList (
IN PEI_CORE_INSTANCE *PrivateData
)
{
UINTN TempValue;
while (TRUE) {
//
// Check if the PEIM that was just dispatched resulted in any
// Notifies getting installed. If so, go process any dispatch
// level Notifies that match the previously installed PPIs.
// Use "while" instead of "if" since ProcessNotify can modify
// DispatchNotifyList.CurrentCount (with NotifyPpi) so we have
// to iterate until the same.
//
while (PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount != PrivateData->PpiData.DispatchNotifyList.CurrentCount) {
TempValue = PrivateData->PpiData.DispatchNotifyList.CurrentCount;
ProcessNotify (
PrivateData,
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
0,
PrivateData->PpiData.PpiList.LastDispatchedCount,
PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount,
PrivateData->PpiData.DispatchNotifyList.CurrentCount
);
PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount = TempValue;
}
//
// Check if the PEIM that was just dispatched resulted in any
// PPIs getting installed. If so, go process any dispatch
// level Notifies that match the installed PPIs.
// Use "while" instead of "if" since ProcessNotify can modify
// PpiList.CurrentCount (with InstallPpi) so we have to iterate
// until the same.
//
while (PrivateData->PpiData.PpiList.LastDispatchedCount != PrivateData->PpiData.PpiList.CurrentCount) {
TempValue = PrivateData->PpiData.PpiList.CurrentCount;
ProcessNotify (
PrivateData,
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
PrivateData->PpiData.PpiList.LastDispatchedCount,
PrivateData->PpiData.PpiList.CurrentCount,
0,
PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount
);
PrivateData->PpiData.PpiList.LastDispatchedCount = TempValue;
}
if (PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount == PrivateData->PpiData.DispatchNotifyList.CurrentCount) {
break;
}
}
return;
}
再次检测是否切换栈
C
PeiCheckAndSwitchStack (SecCoreData, Private);
永久内存到位后,把代码和数据迁移到内存
C
if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW) && \
(PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
(Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||
PcdGetBool (PcdShadowPeimOnS3Boot))
)
{
//
// If memory is available we shadow images by default for performance reasons.
// We call the entry point a 2nd time so the module knows it's shadowed.
//
// PERF_START (PeiServices, L"PEIM", PeimFileHandle, 0);
if ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && !PcdGetBool (PcdShadowPeimOnBoot) &&
!PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes))
{
//
// Load PEIM into Memory for Register for shadow PEIM.
//
Status = PeiLoadImage (
PeiServices,
PeimFileHandle,
PEIM_STATE_REGISTER_FOR_SHADOW,
&EntryPoint,
&AuthenticationState
);
if (Status == EFI_SUCCESS) {
PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
}
}
ASSERT (PeimEntryPoint != NULL);
PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices);
// PERF_END (PeiServices, L"PEIM", PeimFileHandle, 0);
//
// PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE
//
Private->Fv[FvCount].PeimState[PeimCount]++;
//
// Process the Notify list and dispatch any notifies for
// newly installed PPIs.
//
ProcessDispatchNotifyList (Private);
}
}
}
调度挂起的延迟调度请求
C
if (Private->DelayedDispatchTable != NULL) {
if (DelayedDispatchDispatcher (Private->DelayedDispatchTable, NULL)) {
ProcessDispatchNotifyList (Private);
}
}
}
至此一个PEIM调度完成
依次调度其他PEIM
0083b620 00843240 PCDPEIM (已调度)
008432a0 00846fc0 REPORTSTATUSCODEROUTERPEI
008470a0 0084b4a0 STATUSCODEHANDLERPEI
0084b5a0 00869440 PLATFORMPEI
* REPORTSTATUSCODEROUTERPEI
C
EFI_STATUS
EFIAPI
ProcessModuleEntryPointList (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
return GenericStatusCodePeiEntry (FileHandle, PeiServices);
}
C
EFI_STATUS
EFIAPI
GenericStatusCodePeiEntry (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
EFI_PEI_PPI_DESCRIPTOR *OldDescriptor;
EFI_PEI_PROGRESS_CODE_PPI *OldStatusCodePpi;
CreateRscHandlerCallbackPacket ();
//
// Install Report Status Code Handler PPI
//
Status = PeiServicesInstallPpi (mRscHandlerPpiList);
ASSERT_EFI_ERROR (Status);
//
// Install Status Code PPI. PI spec specifies that there can be only one instance
// of this PPI in system. So first check if other instance already exists.
// If no other instance exists, then just install the PPI.
// If other instance already exists, then reinstall it.
//
Status = PeiServicesLocatePpi (
&gEfiPeiStatusCodePpiGuid,
0,
&OldDescriptor,
(VOID **)&OldStatusCodePpi
);
if (!EFI_ERROR (Status)) {
Status = PeiServicesReInstallPpi (OldDescriptor, mStatusCodePpiList);
} else {
Status = PeiServicesInstallPpi (mStatusCodePpiList);
}
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}
* STATUSCODEHANDLERPEI
C
EFI_STATUS
EFIAPI
ProcessModuleEntryPointList (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
return StatusCodeHandlerPeiEntry (FileHandle, PeiServices);
}
C
EFI_STATUS
EFIAPI
StatusCodeHandlerPeiEntry (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
EFI_PEI_RSC_HANDLER_PPI *RscHandlerPpi;
Status = PeiServicesLocatePpi (
&gEfiPeiRscHandlerPpiGuid,
0,
NULL,
(VOID **)&RscHandlerPpi
);
ASSERT_EFI_ERROR (Status);
//
// Dispatch initialization request to sub-statuscode-devices.
// If enable UseSerial, then initialize serial port.
// if enable UseMemory, then initialize memory status code worker.
//
if (PcdGetBool (PcdStatusCodeUseSerial)) {
Status = SerialPortInitialize ();
ASSERT_EFI_ERROR (Status);
Status = RscHandlerPpi->Register (SerialStatusCodeReportWorker);
ASSERT_EFI_ERROR (Status);
}
if (PcdGetBool (PcdStatusCodeUseMemory)) {
Status = MemoryStatusCodeInitializeWorker ();
ASSERT_EFI_ERROR (Status);
Status = RscHandlerPpi->Register (MemoryStatusCodeReportWorker);
ASSERT_EFI_ERROR (Status);
}
return EFI_SUCCESS;
}
* PLATFORMPEI
C
EFI_STATUS
EFIAPI
ProcessModuleEntryPointList (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
return InitializePlatform (FileHandle, PeiServices);
}
C
EFI_STATUS
EFIAPI
InitializePlatform (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_HOB_PLATFORM_INFO *PlatformInfoHob;
EFI_STATUS Status;
DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
PlatformInfoHob = BuildPlatformInfoHob ();
if (TdIsEnabled ()) {
TdxHelperBuildGuidHobForTdxMeasurement ();
}
if (RETURN_ERROR (QemuFwCfgInitCache (PlatformInfoHob))) {
DEBUG ((DEBUG_ERROR, "QemuFwCfgInitCache failed !\n"));
}
PlatformInfoHob->SmmSmramRequire = FeaturePcdGet (PcdSmmSmramRequire);
PlatformInfoHob->SevEsIsEnabled = MemEncryptSevEsIsEnabled ();
PlatformInfoHob->PcdPciMmio64Size = PcdGet64 (PcdPciMmio64Size);
PlatformInfoHob->DefaultMaxCpuNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
PlatformDebugDumpCmos ();
if (QemuFwCfgS3Enabled ()) {
DEBUG ((DEBUG_INFO, "S3 support was detected on QEMU\n"));
PlatformInfoHob->S3Supported = TRUE;
Status = PcdSetBoolS (PcdAcpiS3Enable, TRUE);
ASSERT_EFI_ERROR (Status);
}
BootModeInitialization (PlatformInfoHob);
//
// Query Host Bridge DID
//
PlatformInfoHob->HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
AddressWidthInitialization (PlatformInfoHob);
MaxCpuCountInitialization (PlatformInfoHob);
if (PlatformInfoHob->SmmSmramRequire) {
Q35BoardVerification (PlatformInfoHob);
Q35TsegMbytesInitialization (PlatformInfoHob);
Q35SmramAtDefaultSmbaseInitialization (PlatformInfoHob);
}
PublishPeiMemory (PlatformInfoHob);
PlatformQemuUc32BaseInitialization (PlatformInfoHob);
InitializeRamRegions (PlatformInfoHob);
if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {
PeiFvInitialization (PlatformInfoHob);
MemTypeInfoInitialization (PlatformInfoHob);
MemMapInitialization (PlatformInfoHob);
NoexecDxeInitialization (PlatformInfoHob);
}
InstallClearCacheCallback ();
AmdSevInitialize (PlatformInfoHob);
if (PlatformInfoHob->HostBridgeDevId == 0xffff) {
MiscInitializationForMicrovm (PlatformInfoHob);
} else {
MiscInitialization (PlatformInfoHob);
PlatformIdInitialization (PeiServices);
}
IntelTdxInitialize ();
InstallFeatureControlCallback (PlatformInfoHob);
if (PlatformInfoHob->SmmSmramRequire) {
RelocateSmBase ();
}
//
// Performed after CoCo (SEV/TDX) initialization to allow the memory
// used to be validated before being used.
//
if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {
if (!PlatformInfoHob->SmmSmramRequire) {
ReserveEmuVariableNvStore ();
}
}
return EFI_SUCCESS;
}
PLATFORMPEI模块结束后进行切换栈
从临时内存到永久内存
* 打印临时内存信息
C
DEBUG_CODE_BEGIN ();
UINT32 *StackPointer;
EFI_PEI_HOB_POINTERS Hob;
for ( StackPointer = (UINT32 *)SecCoreData->StackBase;
(StackPointer < (UINT32 *)((UINTN)SecCoreData->StackBase + SecCoreData->StackSize)) \
&& (*StackPointer == PcdGet32 (PcdInitValueInTempStack));
StackPointer++)
{
}
DEBUG ((DEBUG_INFO, "Temp Stack : BaseAddress=0x%p Length=0x%X\n", SecCoreData->StackBase, (UINT32)SecCoreData->StackSize));
DEBUG ((DEBUG_INFO, "Temp Heap : BaseAddress=0x%p Length=0x%X\n", SecCoreData->PeiTemporaryRamBase, (UINT32)SecCoreData->PeiTemporaryRamSize));
DEBUG ((DEBUG_INFO, "Total temporary memory: %d bytes.\n", (UINT32)SecCoreData->TemporaryRamSize));
DEBUG ((
DEBUG_INFO,
" temporary memory stack ever used: %d bytes.\n",
(UINT32)(SecCoreData->StackSize - ((UINTN)StackPointer - (UINTN)SecCoreData->StackBase))
));
DEBUG ((
DEBUG_INFO,
" temporary memory heap used for HobList: %d bytes.\n",
(UINT32)((UINTN)Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - (UINTN)Private->HobList.Raw)
));
DEBUG ((
DEBUG_INFO,
" temporary memory heap occupied by memory pages: %d bytes.\n",
(UINT32)(UINTN)(Private->HobList.HandoffInformationTable->EfiMemoryTop - Private->HobList.HandoffInformationTable->EfiFreeMemoryTop)
));
for (Hob.Raw = Private->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
DEBUG ((
DEBUG_INFO,
"Memory Allocation 0x%08x 0x%0lx - 0x%0lx\n", \
Hob.MemoryAllocation->AllocDescriptor.MemoryType, \
Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress, \
Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength - 1
));
}
}
DEBUG_CODE_END ();
Temp Stack : BaseAddress=0x818000 Length=0x8000
Temp Heap : BaseAddress=0x810000 Length=0x8000
Total temporary memory: 65536 bytes.
temporary memory stack ever used: 32768 bytes.
temporary memory heap used for HobList: 7224 bytes.
temporary memory heap occupied by memory pages: 0 bytes.
Memory Allocation 0x00000000 0x7000000 - 0x7FFFFFF
Memory Allocation 0x00000000 0x30000 - 0x4FFFF
Memory Allocation 0x00000004 0x820000 - 0x8EFFFF
Memory Allocation 0x00000004 0x900000 - 0x177FFFF
Memory Allocation 0x00000000 0xE0000000 - 0xEFFFFFFF
* 预留新栈的大小
C
NewStackSize = RShiftU64 (Private->PhysicalMemoryLength, 1);
NewStackSize = ALIGN_VALUE (NewStackSize, EFI_PAGE_SIZE);
NewStackSize = MIN (PcdGet32 (PcdPeiCoreMaxPeiStackSize), NewStackSize);
DEBUG ((DEBUG_INFO, "Old Stack size %d, New stack size %d\n", (UINT32)SecCoreData->StackSize, (UINT32)NewStackSize));
ASSERT (NewStackSize >= SecCoreData->StackSize);
Old Stack size 32768, New stack size 131072
* 计算新栈和旧栈之间的偏移量
C
//
// Calculate stack offset and heap offset between temporary memory and new permanent
// memory separately.
//
TopOfOldStack = (UINTN)SecCoreData->StackBase + SecCoreData->StackSize;
TopOfNewStack = Private->PhysicalMemoryBegin + NewStackSize;
if (TopOfNewStack >= TopOfOldStack) {
StackOffsetPositive = TRUE;
StackOffset = (UINTN)(TopOfNewStack - TopOfOldStack);
} else {
StackOffsetPositive = FALSE;
StackOffset = (UINTN)(TopOfOldStack - TopOfNewStack);
}
Private->StackOffsetPositive = StackOffsetPositive;
Private->StackOffset = StackOffset;
* 建立栈HOB
C
DEBUG ((DEBUG_INFO, "Stack Hob: BaseAddress=0x%lX Length=0x%lX\n", TopOfNewStack - NewStackSize, NewStackSize));
BuildStackHob (TopOfNewStack - NewStackSize, NewStackSize);
Stack Hob: BaseAddress=0x2BF4000 Length=0x20000
* 记录 SecCoreData 中的缓存信息
C
TemporaryRamBase = (EFI_PHYSICAL_ADDRESS)(UINTN)SecCoreData->TemporaryRamBase;
TemporaryRamSize = SecCoreData->TemporaryRamSize;
TemporaryStackSize = SecCoreData->StackSize;
TemporaryStackBase = SecCoreData->StackBase;
PeiTemporaryRamSize = SecCoreData->PeiTemporaryRamSize;
PeiTemporaryRamBase = SecCoreData->PeiTemporaryRamBase;
* 定位并获取 TemporaryRamSupportPpi 接口
C
Status = PeiServicesLocatePpi (
&gEfiTemporaryRamSupportPpiGuid,
0,
NULL,
(VOID **)&TemporaryRamSupportPpi
);
* 计算新堆和旧堆之间的偏移量
C
BaseOfNewHeap = TopOfNewStack;
if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {
Private->HeapOffsetPositive = TRUE;
Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);
} else {
Private->HeapOffsetPositive = FALSE;
Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);
}
DEBUG ((DEBUG_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64)Private->HeapOffset, (UINT64)Private->StackOffset));
* 计算永久内存栈的HandOffTable和PrivateData地址
C
if (StackOffsetPositive) {
SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData + StackOffset);
Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private + StackOffset);
} else {
SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData - StackOffset);
Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private - StackOffset);
}
* 从临时内存迁移到永久内存
C
TemporaryRamSupportPpi->TemporaryRamMigration (
PeiServices,
TemporaryRamBase,
(EFI_PHYSICAL_ADDRESS)(UINTN)(TopOfNewStack - TemporaryStackSize),
TemporaryRamSize
);
C
EFI_STATUS
EFIAPI
TemporaryRamMigration (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
IN UINTN CopySize
)
{
IA32_DESCRIPTOR IdtDescriptor;
VOID *OldHeap;
VOID *NewHeap;
VOID *OldStack;
VOID *NewStack;
DEBUG_AGENT_CONTEXT_POSTMEM_SEC DebugAgentContext;
BOOLEAN OldStatus;
BASE_LIBRARY_JUMP_BUFFER JumpBuffer;
DEBUG ((
DEBUG_INFO,
"TemporaryRamMigration(0x%Lx, 0x%Lx, 0x%Lx)\n",
TemporaryMemoryBase,
PermanentMemoryBase,
(UINT64)CopySize
));
OldHeap = (VOID *)(UINTN)TemporaryMemoryBase;
NewHeap = (VOID *)((UINTN)PermanentMemoryBase + (CopySize >> 1));
OldStack = (VOID *)((UINTN)TemporaryMemoryBase + (CopySize >> 1));
NewStack = (VOID *)(UINTN)PermanentMemoryBase;
DebugAgentContext.HeapMigrateOffset = (UINTN)NewHeap - (UINTN)OldHeap;
DebugAgentContext.StackMigrateOffset = (UINTN)NewStack - (UINTN)OldStack;
OldStatus = SaveAndSetDebugTimerInterrupt (FALSE);
InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, (VOID *)&DebugAgentContext, NULL);
//
// Migrate Heap
//
CopyMem (NewHeap, OldHeap, CopySize >> 1);
//
// Migrate Stack
//
CopyMem (NewStack, OldStack, CopySize >> 1);
//
// Rebase IDT table in permanent memory
//
AsmReadIdtr (&IdtDescriptor);
IdtDescriptor.Base = IdtDescriptor.Base - (UINTN)OldStack + (UINTN)NewStack;
AsmWriteIdtr (&IdtDescriptor);
//
// Use SetJump()/LongJump() to switch to a new stack.
//
if (SetJump (&JumpBuffer) == 0) {
#if defined (MDE_CPU_IA32)
JumpBuffer.Esp = JumpBuffer.Esp + DebugAgentContext.StackMigrateOffset;
JumpBuffer.Ebp = JumpBuffer.Ebp + DebugAgentContext.StackMigrateOffset;
#endif
#if defined (MDE_CPU_X64)
JumpBuffer.Rsp = JumpBuffer.Rsp + DebugAgentContext.StackMigrateOffset;
JumpBuffer.Rbp = JumpBuffer.Rbp + DebugAgentContext.StackMigrateOffset;
#endif
LongJump (&JumpBuffer, (UINTN)-1);
}
SaveAndSetDebugTimerInterrupt (OldStatus);
return EFI_SUCCESS;
}
* 迁移内存页
C
VOID
MigrateMemoryPages (
IN PEI_CORE_INSTANCE *Private,
IN BOOLEAN TemporaryRamMigrated
)
{
EFI_PHYSICAL_ADDRESS NewMemPagesBase;
EFI_PHYSICAL_ADDRESS MemPagesBase;
Private->MemoryPages.Size = (UINTN)(Private->HobList.HandoffInformationTable->EfiMemoryTop -
Private->HobList.HandoffInformationTable->EfiFreeMemoryTop);
if (Private->MemoryPages.Size == 0) {
//
// No any memory page allocated in pre-memory phase.
//
return;
}
Private->MemoryPages.Base = Private->HobList.HandoffInformationTable->EfiFreeMemoryTop;
ASSERT (Private->MemoryPages.Size <= Private->FreePhysicalMemoryTop);
NewMemPagesBase = Private->FreePhysicalMemoryTop - Private->MemoryPages.Size;
NewMemPagesBase &= ~(UINT64)EFI_PAGE_MASK;
ASSERT (NewMemPagesBase >= Private->PhysicalMemoryBegin);
//
// Copy memory pages at temporary heap top to permanent heap top.
//
if (TemporaryRamMigrated) {
//
// Memory pages at temporary heap top has been migrated to permanent heap,
// Here still needs to copy them from permanent heap to permanent heap top.
//
MemPagesBase = Private->MemoryPages.Base;
if (Private->HeapOffsetPositive) {
MemPagesBase += Private->HeapOffset;
} else {
MemPagesBase -= Private->HeapOffset;
}
CopyMem ((VOID *)(UINTN)NewMemPagesBase, (VOID *)(UINTN)MemPagesBase, Private->MemoryPages.Size);
} else {
CopyMem ((VOID *)(UINTN)NewMemPagesBase, (VOID *)(UINTN)Private->MemoryPages.Base, Private->MemoryPages.Size);
}
if (NewMemPagesBase >= Private->MemoryPages.Base) {
Private->MemoryPages.OffsetPositive = TRUE;
Private->MemoryPages.Offset = (UINTN)(NewMemPagesBase - Private->MemoryPages.Base);
} else {
Private->MemoryPages.OffsetPositive = FALSE;
Private->MemoryPages.Offset = (UINTN)(Private->MemoryPages.Base - NewMemPagesBase);
}
DEBUG ((DEBUG_INFO, "Pages Offset = 0x%lX\n", (UINT64)Private->MemoryPages.Offset));
Private->FreePhysicalMemoryTop = NewMemPagesBase;
}
* 第二次进入
C
PeiCore (SecCoreData, NULL, Private);