1340 lines
48 KiB
Diff
1340 lines
48 KiB
Diff
From 9bedaec05b7b8ba9aee248361bb61a85a26726cb Mon Sep 17 00:00:00 2001
|
|
From: Michael Kubacki <michael.a.kubacki@intel.com>
|
|
Date: Fri, 12 Apr 2019 06:46:02 +0800
|
|
Subject: [PATCH] MdeModulePkg/PeiCore: Enable T-RAM evacuation in PeiCore
|
|
(CVE-2019-11098)
|
|
|
|
REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1614
|
|
|
|
Introduces new changes to PeiCore to move the contents of temporary
|
|
RAM visible to the PeiCore to permanent memory. This expands on
|
|
pre-existing shadowing support in the PeiCore to perform the following
|
|
additional actions:
|
|
|
|
1. Migrate pointers in PPIs installed in PeiCore to the permanent
|
|
memory copy of PeiCore.
|
|
|
|
2. Copy all installed firmware volumes to permanent memory.
|
|
|
|
3. Relocate and fix up the PEIMs within the firmware volumes.
|
|
|
|
4. Convert all PPIs into the migrated firmware volume to the corresponding
|
|
PPI address in the permanent memory location.
|
|
|
|
This applies to PPIs and PEI notifications.
|
|
|
|
5. Convert all status code callbacks in the migrated firmware volume to
|
|
the corresponding address in the permanent memory location.
|
|
|
|
6. Update the FV HOB to the corresponding firmware volume in permanent
|
|
memory.
|
|
|
|
7. Use PcdMigrateTemporaryRamFirmwareVolumes to control if enable the
|
|
feature or not. when disable the PCD, the EvacuateTempRam() will
|
|
never be called.
|
|
|
|
The function control flow as below:
|
|
PeiCore()
|
|
DumpPpiList()
|
|
EvacuateTempRam()
|
|
ConvertPeiCorePpiPointers()
|
|
ConvertPpiPointersFv()
|
|
MigratePeimsInFv()
|
|
MigratePeim()
|
|
PeiGetPe32Data()
|
|
LoadAndRelocatePeCoffImageInPlace()
|
|
MigrateSecModulesInFv()
|
|
ConvertPpiPointersFv()
|
|
ConvertStatusCodeCallbacks()
|
|
ConvertFvHob()
|
|
RemoveFvHobsInTemporaryMemory()
|
|
DumpPpiList()
|
|
|
|
Cc: Jian J Wang <jian.j.wang@intel.com>
|
|
Cc: Hao A Wu <hao.a.wu@intel.com>
|
|
Cc: Dandan Bi <dandan.bi@intel.com>
|
|
Cc: Liming Gao <liming.gao@intel.com>
|
|
Cc: Debkumar De <debkumar.de@intel.com>
|
|
Cc: Harry Han <harry.han@intel.com>
|
|
Cc: Catharine West <catharine.west@intel.com>
|
|
Signed-off-by: Michael Kubacki <michael.a.kubacki@intel.com>
|
|
Reviewed-by: Liming Gao <liming.gao@intel.com>
|
|
Acked-by: Laszlo Ersek <lersek@redhat.com>
|
|
---
|
|
MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c | 417 +++++++++++++++++-
|
|
MdeModulePkg/Core/Pei/Image/Image.c | 130 +++++-
|
|
MdeModulePkg/Core/Pei/Memory/MemoryServices.c | 82 ++++
|
|
MdeModulePkg/Core/Pei/PeiMain.h | 169 +++++++
|
|
MdeModulePkg/Core/Pei/PeiMain.inf | 2 +
|
|
MdeModulePkg/Core/Pei/PeiMain/PeiMain.c | 22 +-
|
|
MdeModulePkg/Core/Pei/Ppi/Ppi.c | 286 ++++++++++++
|
|
7 files changed, 1099 insertions(+), 9 deletions(-)
|
|
|
|
diff --git a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
|
|
index 4c2eac1384..5bc0f8674d 100644
|
|
--- a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
|
|
+++ b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
|
|
@@ -952,6 +952,409 @@ PeiCheckAndSwitchStack (
|
|
}
|
|
}
|
|
|
|
+/**
|
|
+ Migrate a PEIM from temporary RAM to permanent memory.
|
|
+
|
|
+ @param PeimFileHandle Pointer to the FFS file header of the image.
|
|
+ @param MigratedFileHandle Pointer to the FFS file header of the migrated image.
|
|
+
|
|
+ @retval EFI_SUCCESS Sucessfully migrated the PEIM to permanent memory.
|
|
+
|
|
+**/
|
|
+EFI_STATUS
|
|
+EFIAPI
|
|
+MigratePeim (
|
|
+ IN EFI_PEI_FILE_HANDLE FileHandle,
|
|
+ IN EFI_PEI_FILE_HANDLE MigratedFileHandle
|
|
+ )
|
|
+{
|
|
+ EFI_STATUS Status;
|
|
+ EFI_FFS_FILE_HEADER *FileHeader;
|
|
+ VOID *Pe32Data;
|
|
+ VOID *ImageAddress;
|
|
+ CHAR8 *AsciiString;
|
|
+ UINTN Index;
|
|
+
|
|
+ Status = EFI_SUCCESS;
|
|
+
|
|
+ FileHeader = (EFI_FFS_FILE_HEADER *) FileHandle;
|
|
+ ASSERT (!IS_FFS_FILE2 (FileHeader));
|
|
+
|
|
+ ImageAddress = NULL;
|
|
+ PeiGetPe32Data (MigratedFileHandle, &ImageAddress);
|
|
+ if (ImageAddress != NULL) {
|
|
+ DEBUG_CODE_BEGIN ();
|
|
+ AsciiString = PeCoffLoaderGetPdbPointer (ImageAddress);
|
|
+ for (Index = 0; AsciiString[Index] != 0; Index++) {
|
|
+ if (AsciiString[Index] == '\\' || AsciiString[Index] == '/') {
|
|
+ AsciiString = AsciiString + Index + 1;
|
|
+ Index = 0;
|
|
+ } else if (AsciiString[Index] == '.') {
|
|
+ AsciiString[Index] = 0;
|
|
+ }
|
|
+ }
|
|
+ DEBUG ((DEBUG_INFO, "%a", AsciiString));
|
|
+ DEBUG_CODE_END ();
|
|
+
|
|
+ Pe32Data = (VOID *) ((UINTN) ImageAddress - (UINTN) MigratedFileHandle + (UINTN) FileHandle);
|
|
+ Status = LoadAndRelocatePeCoffImageInPlace (Pe32Data, ImageAddress);
|
|
+ ASSERT_EFI_ERROR (Status);
|
|
+ }
|
|
+
|
|
+ return Status;
|
|
+}
|
|
+
|
|
+/**
|
|
+ Migrate Status Code Callback function pointers inside an FV from temporary memory to permanent memory.
|
|
+
|
|
+ @param OrgFvHandle Address of FV handle in temporary memory.
|
|
+ @param FvHandle Address of FV handle in permanent memory.
|
|
+ @param FvSize Size of the FV.
|
|
+
|
|
+**/
|
|
+VOID
|
|
+ConvertStatusCodeCallbacks (
|
|
+ IN UINTN OrgFvHandle,
|
|
+ IN UINTN FvHandle,
|
|
+ IN UINTN FvSize
|
|
+ )
|
|
+{
|
|
+ EFI_PEI_HOB_POINTERS Hob;
|
|
+ UINTN *NumberOfEntries;
|
|
+ UINTN *CallbackEntry;
|
|
+ UINTN Index;
|
|
+
|
|
+ Hob.Raw = GetFirstGuidHob (&gStatusCodeCallbackGuid);
|
|
+ while (Hob.Raw != NULL) {
|
|
+ NumberOfEntries = GET_GUID_HOB_DATA (Hob);
|
|
+ CallbackEntry = NumberOfEntries + 1;
|
|
+ for (Index = 0; Index < *NumberOfEntries; Index++) {
|
|
+ if (((VOID *) CallbackEntry[Index]) != NULL) {
|
|
+ if ((CallbackEntry[Index] >= OrgFvHandle) && (CallbackEntry[Index] < (OrgFvHandle + FvSize))) {
|
|
+ DEBUG ((
|
|
+ DEBUG_INFO,
|
|
+ "Migrating CallbackEntry[%Lu] from 0x%0*Lx to ",
|
|
+ (UINT64)Index,
|
|
+ (sizeof CallbackEntry[Index]) * 2,
|
|
+ (UINT64)CallbackEntry[Index]
|
|
+ ));
|
|
+ if (OrgFvHandle > FvHandle) {
|
|
+ CallbackEntry[Index] = CallbackEntry[Index] - (OrgFvHandle - FvHandle);
|
|
+ } else {
|
|
+ CallbackEntry[Index] = CallbackEntry[Index] + (FvHandle - OrgFvHandle);
|
|
+ }
|
|
+ DEBUG ((
|
|
+ DEBUG_INFO,
|
|
+ "0x%0*Lx\n",
|
|
+ (sizeof CallbackEntry[Index]) * 2,
|
|
+ (UINT64)CallbackEntry[Index]
|
|
+ ));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ Hob.Raw = GET_NEXT_HOB (Hob);
|
|
+ Hob.Raw = GetNextGuidHob (&gStatusCodeCallbackGuid, Hob.Raw);
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ Migrates SEC modules in the given firmware volume.
|
|
+
|
|
+ Migrating SECURITY_CORE files requires special treatment since they are not tracked for PEI dispatch.
|
|
+
|
|
+ This functioun should be called after the FV has been copied to its post-memory location and the PEI Core FV list has
|
|
+ been updated.
|
|
+
|
|
+ @param Private Pointer to the PeiCore's private data structure.
|
|
+ @param FvIndex The firmware volume index to migrate.
|
|
+ @param OrgFvHandle The handle to the firmware volume in temporary memory.
|
|
+
|
|
+ @retval EFI_SUCCESS SEC modules were migrated successfully
|
|
+ @retval EFI_INVALID_PARAMETER The Private pointer is NULL or FvCount is invalid.
|
|
+ @retval EFI_NOT_FOUND Can't find valid FFS header.
|
|
+
|
|
+**/
|
|
+EFI_STATUS
|
|
+EFIAPI
|
|
+MigrateSecModulesInFv (
|
|
+ IN PEI_CORE_INSTANCE *Private,
|
|
+ IN UINTN FvIndex,
|
|
+ IN UINTN OrgFvHandle
|
|
+ )
|
|
+{
|
|
+ EFI_STATUS Status;
|
|
+ EFI_STATUS FindFileStatus;
|
|
+ EFI_PEI_FILE_HANDLE MigratedFileHandle;
|
|
+ EFI_PEI_FILE_HANDLE FileHandle;
|
|
+ UINT32 SectionAuthenticationStatus;
|
|
+ UINT32 FileSize;
|
|
+ VOID *OrgPe32SectionData;
|
|
+ VOID *Pe32SectionData;
|
|
+ EFI_FFS_FILE_HEADER *FfsFileHeader;
|
|
+ EFI_COMMON_SECTION_HEADER *Section;
|
|
+ BOOLEAN IsFfs3Fv;
|
|
+ UINTN SectionInstance;
|
|
+
|
|
+ if (Private == NULL || FvIndex >= Private->FvCount) {
|
|
+ return EFI_INVALID_PARAMETER;
|
|
+ }
|
|
+
|
|
+ do {
|
|
+ FindFileStatus = PeiFfsFindNextFile (
|
|
+ GetPeiServicesTablePointer (),
|
|
+ EFI_FV_FILETYPE_SECURITY_CORE,
|
|
+ Private->Fv[FvIndex].FvHandle,
|
|
+ &MigratedFileHandle
|
|
+ );
|
|
+ if (!EFI_ERROR (FindFileStatus ) && MigratedFileHandle != NULL) {
|
|
+ FileHandle = (EFI_PEI_FILE_HANDLE) ((UINTN) MigratedFileHandle - (UINTN) Private->Fv[FvIndex].FvHandle + OrgFvHandle);
|
|
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) MigratedFileHandle;
|
|
+
|
|
+ DEBUG ((DEBUG_VERBOSE, " Migrating SEC_CORE MigratedFileHandle at 0x%x.\n", (UINTN) MigratedFileHandle));
|
|
+ DEBUG ((DEBUG_VERBOSE, " FileHandle at 0x%x.\n", (UINTN) FileHandle));
|
|
+
|
|
+ IsFfs3Fv = CompareGuid (&Private->Fv[FvIndex].FvHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);
|
|
+ if (IS_FFS_FILE2 (FfsFileHeader)) {
|
|
+ ASSERT (FFS_FILE2_SIZE (FfsFileHeader) > 0x00FFFFFF);
|
|
+ if (!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);
|
|
+ }
|
|
+
|
|
+ SectionInstance = 1;
|
|
+ SectionAuthenticationStatus = 0;
|
|
+ Status = ProcessSection (
|
|
+ GetPeiServicesTablePointer (),
|
|
+ EFI_SECTION_PE32,
|
|
+ &SectionInstance,
|
|
+ Section,
|
|
+ FileSize,
|
|
+ &Pe32SectionData,
|
|
+ &SectionAuthenticationStatus,
|
|
+ IsFfs3Fv
|
|
+ );
|
|
+
|
|
+ if (!EFI_ERROR (Status)) {
|
|
+ OrgPe32SectionData = (VOID *) ((UINTN) Pe32SectionData - (UINTN) MigratedFileHandle + (UINTN) FileHandle);
|
|
+ DEBUG ((DEBUG_VERBOSE, " PE32 section in migrated file at 0x%x.\n", (UINTN) Pe32SectionData));
|
|
+ DEBUG ((DEBUG_VERBOSE, " PE32 section in original file at 0x%x.\n", (UINTN) OrgPe32SectionData));
|
|
+ Status = LoadAndRelocatePeCoffImageInPlace (OrgPe32SectionData, Pe32SectionData);
|
|
+ ASSERT_EFI_ERROR (Status);
|
|
+ }
|
|
+ }
|
|
+ } while (!EFI_ERROR (FindFileStatus));
|
|
+
|
|
+ return EFI_SUCCESS;
|
|
+}
|
|
+
|
|
+/**
|
|
+ Migrates PEIMs in the given firmware volume.
|
|
+
|
|
+ @param Private Pointer to the PeiCore's private data structure.
|
|
+ @param FvIndex The firmware volume index to migrate.
|
|
+ @param OrgFvHandle The handle to the firmware volume in temporary memory.
|
|
+ @param FvHandle The handle to the firmware volume in permanent memory.
|
|
+
|
|
+ @retval EFI_SUCCESS The PEIMs in the FV were migrated successfully
|
|
+ @retval EFI_INVALID_PARAMETER The Private pointer is NULL or FvCount is invalid.
|
|
+
|
|
+**/
|
|
+EFI_STATUS
|
|
+EFIAPI
|
|
+MigratePeimsInFv (
|
|
+ IN PEI_CORE_INSTANCE *Private,
|
|
+ IN UINTN FvIndex,
|
|
+ IN UINTN OrgFvHandle,
|
|
+ IN UINTN FvHandle
|
|
+ )
|
|
+{
|
|
+ EFI_STATUS Status;
|
|
+ volatile UINTN FileIndex;
|
|
+ EFI_PEI_FILE_HANDLE MigratedFileHandle;
|
|
+ EFI_PEI_FILE_HANDLE FileHandle;
|
|
+
|
|
+ if (Private == NULL || FvIndex >= Private->FvCount) {
|
|
+ return EFI_INVALID_PARAMETER;
|
|
+ }
|
|
+
|
|
+ if (Private->Fv[FvIndex].ScanFv) {
|
|
+ for (FileIndex = 0; FileIndex < Private->Fv[FvIndex].PeimCount; FileIndex++) {
|
|
+ if (Private->Fv[FvIndex].FvFileHandles[FileIndex] != NULL) {
|
|
+ FileHandle = Private->Fv[FvIndex].FvFileHandles[FileIndex];
|
|
+
|
|
+ MigratedFileHandle = (EFI_PEI_FILE_HANDLE) ((UINTN) FileHandle - OrgFvHandle + FvHandle);
|
|
+
|
|
+ DEBUG ((DEBUG_VERBOSE, " Migrating FileHandle %2d ", FileIndex));
|
|
+ Status = MigratePeim (FileHandle, MigratedFileHandle);
|
|
+ DEBUG ((DEBUG_VERBOSE, "\n"));
|
|
+ ASSERT_EFI_ERROR (Status);
|
|
+
|
|
+ if (!EFI_ERROR (Status)) {
|
|
+ Private->Fv[FvIndex].FvFileHandles[FileIndex] = MigratedFileHandle;
|
|
+ if (FvIndex == Private->CurrentPeimFvCount) {
|
|
+ Private->CurrentFvFileHandles[FileIndex] = MigratedFileHandle;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return EFI_SUCCESS;
|
|
+}
|
|
+
|
|
+/**
|
|
+ Migrate FVs out of temporary RAM before the cache is flushed.
|
|
+
|
|
+ @param Private PeiCore's private data structure
|
|
+ @param SecCoreData Points to a data structure containing information about the PEI core's operating
|
|
+ environment, such as the size and location of temporary RAM, the stack location and
|
|
+ the BFV location.
|
|
+
|
|
+ @retval EFI_SUCCESS Succesfully migrated installed FVs from temporary RAM to permanent memory.
|
|
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory exists to allocate needed pages.
|
|
+
|
|
+**/
|
|
+EFI_STATUS
|
|
+EFIAPI
|
|
+EvacuateTempRam (
|
|
+ IN PEI_CORE_INSTANCE *Private,
|
|
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
|
|
+ )
|
|
+{
|
|
+ EFI_STATUS Status;
|
|
+ volatile UINTN FvIndex;
|
|
+ volatile UINTN FvChildIndex;
|
|
+ UINTN ChildFvOffset;
|
|
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
|
|
+ EFI_FIRMWARE_VOLUME_HEADER *ChildFvHeader;
|
|
+ EFI_FIRMWARE_VOLUME_HEADER *MigratedFvHeader;
|
|
+ EFI_FIRMWARE_VOLUME_HEADER *MigratedChildFvHeader;
|
|
+
|
|
+ PEI_CORE_FV_HANDLE PeiCoreFvHandle;
|
|
+ EFI_PEI_CORE_FV_LOCATION_PPI *PeiCoreFvLocationPpi;
|
|
+
|
|
+ ASSERT (Private->PeiMemoryInstalled);
|
|
+
|
|
+ DEBUG ((DEBUG_VERBOSE, "Beginning evacuation of content in temporary RAM.\n"));
|
|
+
|
|
+ //
|
|
+ // Migrate PPI Pointers of PEI_CORE from temporary memory to newly loaded PEI_CORE in permanent memory.
|
|
+ //
|
|
+ Status = PeiLocatePpi ((CONST EFI_PEI_SERVICES **) &Private->Ps, &gEfiPeiCoreFvLocationPpiGuid, 0, NULL, (VOID **) &PeiCoreFvLocationPpi);
|
|
+ if (!EFI_ERROR (Status) && (PeiCoreFvLocationPpi->PeiCoreFvLocation != NULL)) {
|
|
+ PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE) PeiCoreFvLocationPpi->PeiCoreFvLocation;
|
|
+ } else {
|
|
+ PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE) SecCoreData->BootFirmwareVolumeBase;
|
|
+ }
|
|
+ for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) {
|
|
+ if (Private->Fv[FvIndex].FvHandle == PeiCoreFvHandle.FvHandle) {
|
|
+ PeiCoreFvHandle = Private->Fv[FvIndex];
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ Status = EFI_SUCCESS;
|
|
+
|
|
+ ConvertPeiCorePpiPointers (Private, PeiCoreFvHandle);
|
|
+
|
|
+ for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) {
|
|
+ FvHeader = Private->Fv[FvIndex].FvHeader;
|
|
+ ASSERT (FvHeader != NULL);
|
|
+ ASSERT (FvIndex < Private->FvCount);
|
|
+
|
|
+ DEBUG ((DEBUG_VERBOSE, "FV[%02d] at 0x%x.\n", FvIndex, (UINTN) FvHeader));
|
|
+ if (
|
|
+ !(
|
|
+ ((EFI_PHYSICAL_ADDRESS)(UINTN) FvHeader >= Private->PhysicalMemoryBegin) &&
|
|
+ (((EFI_PHYSICAL_ADDRESS)(UINTN) FvHeader + (FvHeader->FvLength - 1)) < Private->FreePhysicalMemoryTop)
|
|
+ )
|
|
+ ) {
|
|
+ Status = PeiServicesAllocatePages (
|
|
+ EfiBootServicesCode,
|
|
+ EFI_SIZE_TO_PAGES ((UINTN) FvHeader->FvLength),
|
|
+ (EFI_PHYSICAL_ADDRESS *) &MigratedFvHeader
|
|
+ );
|
|
+ ASSERT_EFI_ERROR (Status);
|
|
+
|
|
+ DEBUG ((
|
|
+ DEBUG_VERBOSE,
|
|
+ " Migrating FV[%d] from 0x%08X to 0x%08X\n",
|
|
+ FvIndex,
|
|
+ (UINTN) FvHeader,
|
|
+ (UINTN) MigratedFvHeader
|
|
+ ));
|
|
+
|
|
+ CopyMem (MigratedFvHeader, FvHeader, (UINTN) FvHeader->FvLength);
|
|
+
|
|
+ //
|
|
+ // Migrate any children for this FV now
|
|
+ //
|
|
+ for (FvChildIndex = FvIndex; FvChildIndex < Private->FvCount; FvChildIndex++) {
|
|
+ ChildFvHeader = Private->Fv[FvChildIndex].FvHeader;
|
|
+ if (
|
|
+ ((UINTN) ChildFvHeader > (UINTN) FvHeader) &&
|
|
+ (((UINTN) ChildFvHeader + ChildFvHeader->FvLength) < ((UINTN) FvHeader) + FvHeader->FvLength)
|
|
+ ) {
|
|
+ DEBUG ((DEBUG_VERBOSE, " Child FV[%02d] is being migrated.\n", FvChildIndex));
|
|
+ ChildFvOffset = (UINTN) ChildFvHeader - (UINTN) FvHeader;
|
|
+ DEBUG ((DEBUG_VERBOSE, " Child FV offset = 0x%x.\n", ChildFvOffset));
|
|
+ MigratedChildFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) MigratedFvHeader + ChildFvOffset);
|
|
+ Private->Fv[FvChildIndex].FvHeader = MigratedChildFvHeader;
|
|
+ Private->Fv[FvChildIndex].FvHandle = (EFI_PEI_FV_HANDLE) MigratedChildFvHeader;
|
|
+ DEBUG ((DEBUG_VERBOSE, " Child migrated FV header at 0x%x.\n", (UINTN) MigratedChildFvHeader));
|
|
+
|
|
+ Status = MigratePeimsInFv (Private, FvChildIndex, (UINTN) ChildFvHeader, (UINTN) MigratedChildFvHeader);
|
|
+ ASSERT_EFI_ERROR (Status);
|
|
+
|
|
+ ConvertPpiPointersFv (
|
|
+ Private,
|
|
+ (UINTN) ChildFvHeader,
|
|
+ (UINTN) MigratedChildFvHeader,
|
|
+ (UINTN) ChildFvHeader->FvLength - 1
|
|
+ );
|
|
+
|
|
+ ConvertStatusCodeCallbacks (
|
|
+ (UINTN) ChildFvHeader,
|
|
+ (UINTN) MigratedChildFvHeader,
|
|
+ (UINTN) ChildFvHeader->FvLength - 1
|
|
+ );
|
|
+
|
|
+ ConvertFvHob (Private, (UINTN) ChildFvHeader, (UINTN) MigratedChildFvHeader);
|
|
+ }
|
|
+ }
|
|
+ Private->Fv[FvIndex].FvHeader = MigratedFvHeader;
|
|
+ Private->Fv[FvIndex].FvHandle = (EFI_PEI_FV_HANDLE) MigratedFvHeader;
|
|
+
|
|
+ Status = MigratePeimsInFv (Private, FvIndex, (UINTN) FvHeader, (UINTN) MigratedFvHeader);
|
|
+ ASSERT_EFI_ERROR (Status);
|
|
+
|
|
+ ConvertPpiPointersFv (
|
|
+ Private,
|
|
+ (UINTN) FvHeader,
|
|
+ (UINTN) MigratedFvHeader,
|
|
+ (UINTN) FvHeader->FvLength - 1
|
|
+ );
|
|
+
|
|
+ ConvertStatusCodeCallbacks (
|
|
+ (UINTN) FvHeader,
|
|
+ (UINTN) MigratedFvHeader,
|
|
+ (UINTN) FvHeader->FvLength - 1
|
|
+ );
|
|
+
|
|
+ ConvertFvHob (Private, (UINTN) FvHeader, (UINTN) MigratedFvHeader);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ RemoveFvHobsInTemporaryMemory (Private);
|
|
+
|
|
+ return Status;
|
|
+}
|
|
+
|
|
/**
|
|
Conduct PEIM dispatch.
|
|
|
|
@@ -988,7 +1391,11 @@ PeiDispatcher (
|
|
PeimFileHandle = NULL;
|
|
EntryPoint = 0;
|
|
|
|
- if ((Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME || PcdGetBool (PcdShadowPeimOnS3Boot))) {
|
|
+ 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.
|
|
@@ -1187,13 +1594,17 @@ PeiDispatcher (
|
|
PeiCheckAndSwitchStack (SecCoreData, Private);
|
|
|
|
if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW) && \
|
|
- (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME || PcdGetBool (PcdShadowPeimOnS3Boot))) {
|
|
+ (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)) {
|
|
+ if ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && !PcdGetBool (PcdShadowPeimOnBoot) &&
|
|
+ !PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes)) {
|
|
//
|
|
// Load PEIM into Memory for Register for shadow PEIM.
|
|
//
|
|
diff --git a/MdeModulePkg/Core/Pei/Image/Image.c b/MdeModulePkg/Core/Pei/Image/Image.c
|
|
index e3ee369933..1d15774527 100644
|
|
--- a/MdeModulePkg/Core/Pei/Image/Image.c
|
|
+++ b/MdeModulePkg/Core/Pei/Image/Image.c
|
|
@@ -328,8 +328,11 @@ LoadAndRelocatePeCoffImage (
|
|
//
|
|
// When Image has no reloc section, it can't be relocated into memory.
|
|
//
|
|
- if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && ((!IsPeiModule) ||
|
|
- (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) || (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))) {
|
|
+ if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) &&
|
|
+ ((!IsPeiModule) || PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
|
|
+ (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) ||
|
|
+ (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))
|
|
+ ) {
|
|
DEBUG ((EFI_D_INFO|EFI_D_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data));
|
|
}
|
|
|
|
@@ -343,8 +346,11 @@ LoadAndRelocatePeCoffImage (
|
|
// 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) ||
|
|
- (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) || (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))) {
|
|
+ if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) &&
|
|
+ ((!IsPeiModule) || PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
|
|
+ (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) ||
|
|
+ (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))
|
|
+ ) {
|
|
//
|
|
// Allocate more buffer to avoid buffer overflow.
|
|
//
|
|
@@ -444,6 +450,122 @@ LoadAndRelocatePeCoffImage (
|
|
return ReturnStatus;
|
|
}
|
|
|
|
+/**
|
|
+ Loads and relocates a PE/COFF image in place.
|
|
+
|
|
+ @param Pe32Data The base address of the PE/COFF file that is to be loaded and relocated
|
|
+ @param ImageAddress The base address of the relocated PE/COFF image
|
|
+
|
|
+ @retval EFI_SUCCESS The file was loaded and relocated.
|
|
+ @retval Others The file not be loaded and error occurred.
|
|
+
|
|
+**/
|
|
+EFI_STATUS
|
|
+LoadAndRelocatePeCoffImageInPlace (
|
|
+ IN VOID *Pe32Data,
|
|
+ IN VOID *ImageAddress
|
|
+ )
|
|
+{
|
|
+ EFI_STATUS Status;
|
|
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
|
|
+
|
|
+ ZeroMem (&ImageContext, sizeof (ImageContext));
|
|
+ ImageContext.Handle = Pe32Data;
|
|
+ ImageContext.ImageRead = PeiImageRead;
|
|
+
|
|
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
|
|
+ if (EFI_ERROR (Status)) {
|
|
+ ASSERT_EFI_ERROR (Status);
|
|
+ return Status;
|
|
+ }
|
|
+
|
|
+ ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN) ImageAddress;
|
|
+
|
|
+ //
|
|
+ // Load the image in place
|
|
+ //
|
|
+ Status = PeCoffLoaderLoadImage (&ImageContext);
|
|
+ if (EFI_ERROR (Status)) {
|
|
+ ASSERT_EFI_ERROR (Status);
|
|
+ return Status;
|
|
+ }
|
|
+
|
|
+ //
|
|
+ // Relocate the image in place
|
|
+ //
|
|
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
|
|
+ if (EFI_ERROR (Status)) {
|
|
+ ASSERT_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);
|
|
+ }
|
|
+
|
|
+ return Status;
|
|
+}
|
|
+
|
|
+/**
|
|
+ Find the PE32 Data for an FFS file.
|
|
+
|
|
+ @param FileHandle Pointer to the FFS file header of the image.
|
|
+ @param Pe32Data Pointer to a (VOID *) PE32 Data pointer.
|
|
+
|
|
+ @retval EFI_SUCCESS Image is successfully loaded.
|
|
+ @retval EFI_NOT_FOUND Fail to locate PE32 Data.
|
|
+
|
|
+**/
|
|
+EFI_STATUS
|
|
+PeiGetPe32Data (
|
|
+ IN EFI_PEI_FILE_HANDLE FileHandle,
|
|
+ OUT VOID **Pe32Data
|
|
+ )
|
|
+{
|
|
+ EFI_STATUS Status;
|
|
+ EFI_SECTION_TYPE SearchType1;
|
|
+ EFI_SECTION_TYPE SearchType2;
|
|
+ UINT32 AuthenticationState;
|
|
+
|
|
+ *Pe32Data = NULL;
|
|
+
|
|
+ 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
|
|
+ );
|
|
+ }
|
|
+ return Status;
|
|
+}
|
|
+
|
|
/**
|
|
Loads a PEIM into memory for subsequent execution. If there are compressed
|
|
images or images that need to be relocated into memory for performance reasons,
|
|
diff --git a/MdeModulePkg/Core/Pei/Memory/MemoryServices.c b/MdeModulePkg/Core/Pei/Memory/MemoryServices.c
|
|
index 6b3a64a811..9d933f0393 100644
|
|
--- a/MdeModulePkg/Core/Pei/Memory/MemoryServices.c
|
|
+++ b/MdeModulePkg/Core/Pei/Memory/MemoryServices.c
|
|
@@ -166,6 +166,88 @@ MigrateMemoryPages (
|
|
Private->FreePhysicalMemoryTop = NewMemPagesBase;
|
|
}
|
|
|
|
+/**
|
|
+ Removes any FV HOBs whose base address is not in PEI installed memory.
|
|
+
|
|
+ @param[in] Private Pointer to PeiCore's private data structure.
|
|
+
|
|
+**/
|
|
+VOID
|
|
+RemoveFvHobsInTemporaryMemory (
|
|
+ IN PEI_CORE_INSTANCE *Private
|
|
+ )
|
|
+{
|
|
+ EFI_PEI_HOB_POINTERS Hob;
|
|
+ EFI_HOB_FIRMWARE_VOLUME *FirmwareVolumeHob;
|
|
+
|
|
+ DEBUG ((DEBUG_INFO, "Removing FVs in FV HOB not already migrated to permanent memory.\n"));
|
|
+
|
|
+ for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
|
|
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV || GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV2 || GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV3) {
|
|
+ FirmwareVolumeHob = Hob.FirmwareVolume;
|
|
+ DEBUG ((DEBUG_INFO, " Found FV HOB.\n"));
|
|
+ DEBUG ((
|
|
+ DEBUG_INFO,
|
|
+ " BA=%016lx L=%016lx\n",
|
|
+ FirmwareVolumeHob->BaseAddress,
|
|
+ FirmwareVolumeHob->Length
|
|
+ ));
|
|
+ if (
|
|
+ !(
|
|
+ ((EFI_PHYSICAL_ADDRESS) (UINTN) FirmwareVolumeHob->BaseAddress >= Private->PhysicalMemoryBegin) &&
|
|
+ (((EFI_PHYSICAL_ADDRESS) (UINTN) FirmwareVolumeHob->BaseAddress + (FirmwareVolumeHob->Length - 1)) < Private->FreePhysicalMemoryTop)
|
|
+ )
|
|
+ ) {
|
|
+ DEBUG ((DEBUG_INFO, " Removing FV HOB to an FV in T-RAM (was not migrated).\n"));
|
|
+ Hob.Header->HobType = EFI_HOB_TYPE_UNUSED;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ Migrate the base address in firmware volume allocation HOBs
|
|
+ from temporary memory to PEI installed memory.
|
|
+
|
|
+ @param[in] PrivateData Pointer to PeiCore's private data structure.
|
|
+ @param[in] OrgFvHandle Address of FV Handle in temporary memory.
|
|
+ @param[in] FvHandle Address of FV Handle in permanent memory.
|
|
+
|
|
+**/
|
|
+VOID
|
|
+ConvertFvHob (
|
|
+ IN PEI_CORE_INSTANCE *PrivateData,
|
|
+ IN UINTN OrgFvHandle,
|
|
+ IN UINTN FvHandle
|
|
+ )
|
|
+{
|
|
+ EFI_PEI_HOB_POINTERS Hob;
|
|
+ EFI_HOB_FIRMWARE_VOLUME *FirmwareVolumeHob;
|
|
+ EFI_HOB_FIRMWARE_VOLUME2 *FirmwareVolume2Hob;
|
|
+ EFI_HOB_FIRMWARE_VOLUME3 *FirmwareVolume3Hob;
|
|
+
|
|
+ DEBUG ((DEBUG_INFO, "Converting FVs in FV HOB.\n"));
|
|
+
|
|
+ for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
|
|
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {
|
|
+ FirmwareVolumeHob = Hob.FirmwareVolume;
|
|
+ if (FirmwareVolumeHob->BaseAddress == OrgFvHandle) {
|
|
+ FirmwareVolumeHob->BaseAddress = FvHandle;
|
|
+ }
|
|
+ } else if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV2) {
|
|
+ FirmwareVolume2Hob = Hob.FirmwareVolume2;
|
|
+ if (FirmwareVolume2Hob->BaseAddress == OrgFvHandle) {
|
|
+ FirmwareVolume2Hob->BaseAddress = FvHandle;
|
|
+ }
|
|
+ } else if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV3) {
|
|
+ FirmwareVolume3Hob = Hob.FirmwareVolume3;
|
|
+ if (FirmwareVolume3Hob->BaseAddress == OrgFvHandle) {
|
|
+ FirmwareVolume3Hob->BaseAddress = FvHandle;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
/**
|
|
Migrate MemoryBaseAddress in memory allocation HOBs
|
|
from the temporary memory to PEI installed memory.
|
|
diff --git a/MdeModulePkg/Core/Pei/PeiMain.h b/MdeModulePkg/Core/Pei/PeiMain.h
|
|
index 56b3bd8579..6d95a5d32c 100644
|
|
--- a/MdeModulePkg/Core/Pei/PeiMain.h
|
|
+++ b/MdeModulePkg/Core/Pei/PeiMain.h
|
|
@@ -394,6 +394,41 @@ PeimDispatchReadiness (
|
|
IN VOID *DependencyExpression
|
|
);
|
|
|
|
+/**
|
|
+ Migrate a PEIM from temporary RAM to permanent memory.
|
|
+
|
|
+ @param PeimFileHandle Pointer to the FFS file header of the image.
|
|
+ @param MigratedFileHandle Pointer to the FFS file header of the migrated image.
|
|
+
|
|
+ @retval EFI_SUCCESS Sucessfully migrated the PEIM to permanent memory.
|
|
+
|
|
+**/
|
|
+EFI_STATUS
|
|
+EFIAPI
|
|
+MigratePeim (
|
|
+ IN EFI_PEI_FILE_HANDLE FileHandle,
|
|
+ IN EFI_PEI_FILE_HANDLE MigratedFileHandle
|
|
+ );
|
|
+
|
|
+/**
|
|
+ Migrate FVs out of temporary RAM before the cache is flushed.
|
|
+
|
|
+ @param Private PeiCore's private data structure
|
|
+ @param SecCoreData Points to a data structure containing information about the PEI core's operating
|
|
+ environment, such as the size and location of temporary RAM, the stack location and
|
|
+ the BFV location.
|
|
+
|
|
+ @retval EFI_SUCCESS Succesfully migrated installed FVs from temporary RAM to permanent memory.
|
|
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory exists to allocate needed pages.
|
|
+
|
|
+**/
|
|
+EFI_STATUS
|
|
+EFIAPI
|
|
+EvacuateTempRam (
|
|
+ IN PEI_CORE_INSTANCE *Private,
|
|
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
|
|
+ );
|
|
+
|
|
/**
|
|
Conduct PEIM dispatch.
|
|
|
|
@@ -477,6 +512,50 @@ ConvertPpiPointers (
|
|
IN PEI_CORE_INSTANCE *PrivateData
|
|
);
|
|
|
|
+/**
|
|
+
|
|
+ Migrate Notify Pointers inside an FV from temporary memory to permanent memory.
|
|
+
|
|
+ @param PrivateData Pointer to PeiCore's private data structure.
|
|
+ @param OrgFvHandle Address of FV Handle in temporary memory.
|
|
+ @param FvHandle Address of FV Handle in permanent memory.
|
|
+ @param FvSize Size of the FV.
|
|
+
|
|
+**/
|
|
+VOID
|
|
+ConvertPpiPointersFv (
|
|
+ IN PEI_CORE_INSTANCE *PrivateData,
|
|
+ IN UINTN OrgFvHandle,
|
|
+ IN UINTN FvHandle,
|
|
+ IN UINTN FvSize
|
|
+ );
|
|
+
|
|
+/**
|
|
+
|
|
+ Migrate PPI Pointers of PEI_CORE from temporary memory to permanent memory.
|
|
+
|
|
+ @param PrivateData Pointer to PeiCore's private data structure.
|
|
+ @param CoreFvHandle Address of PEI_CORE FV Handle in temporary memory.
|
|
+
|
|
+**/
|
|
+VOID
|
|
+ConvertPeiCorePpiPointers (
|
|
+ IN PEI_CORE_INSTANCE *PrivateData,
|
|
+ PEI_CORE_FV_HANDLE CoreFvHandle
|
|
+ );
|
|
+
|
|
+/**
|
|
+
|
|
+ Dumps the PPI lists to debug output.
|
|
+
|
|
+ @param PrivateData Points to PeiCore's private instance data.
|
|
+
|
|
+**/
|
|
+VOID
|
|
+DumpPpiList (
|
|
+ IN PEI_CORE_INSTANCE *PrivateData
|
|
+ );
|
|
+
|
|
/**
|
|
|
|
Install PPI services. It is implementation of EFI_PEI_SERVICE.InstallPpi.
|
|
@@ -808,6 +887,37 @@ PeiFfsFindNextFile (
|
|
IN OUT EFI_PEI_FILE_HANDLE *FileHandle
|
|
);
|
|
|
|
+/**
|
|
+ Go through the file to search SectionType section.
|
|
+ Search within encapsulation sections (compression and GUIDed) recursively,
|
|
+ until the match section is found.
|
|
+
|
|
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
|
|
+ @param SectionType Filter to find only section of this type.
|
|
+ @param SectionInstance Pointer to the filter to find the specific instance of section.
|
|
+ @param Section From where to search.
|
|
+ @param SectionSize The file size to search.
|
|
+ @param OutputBuffer A pointer to the discovered section, if successful.
|
|
+ NULL if section not found.
|
|
+ @param AuthenticationStatus Updated upon return to point to the authentication status for this section.
|
|
+ @param IsFfs3Fv Indicates the FV format.
|
|
+
|
|
+ @return EFI_NOT_FOUND The match section is not found.
|
|
+ @return EFI_SUCCESS The match section is found.
|
|
+
|
|
+**/
|
|
+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
|
|
+ );
|
|
+
|
|
/**
|
|
Searches for the next matching section within the specified file.
|
|
|
|
@@ -931,6 +1041,33 @@ MigrateMemoryPages (
|
|
IN BOOLEAN TemporaryRamMigrated
|
|
);
|
|
|
|
+/**
|
|
+ Removes any FV HOBs whose base address is not in PEI installed memory.
|
|
+
|
|
+ @param[in] Private Pointer to PeiCore's private data structure.
|
|
+
|
|
+**/
|
|
+VOID
|
|
+RemoveFvHobsInTemporaryMemory (
|
|
+ IN PEI_CORE_INSTANCE *Private
|
|
+ );
|
|
+
|
|
+/**
|
|
+ Migrate the base address in firmware volume allocation HOBs
|
|
+ from temporary memory to PEI installed memory.
|
|
+
|
|
+ @param[in] PrivateData Pointer to PeiCore's private data structure.
|
|
+ @param[in] OrgFvHandle Address of FV Handle in temporary memory.
|
|
+ @param[in] FvHandle Address of FV Handle in permanent memory.
|
|
+
|
|
+**/
|
|
+VOID
|
|
+ConvertFvHob (
|
|
+ IN PEI_CORE_INSTANCE *PrivateData,
|
|
+ IN UINTN OrgFvHandle,
|
|
+ IN UINTN FvHandle
|
|
+ );
|
|
+
|
|
/**
|
|
Migrate MemoryBaseAddress in memory allocation HOBs
|
|
from the temporary memory to PEI installed memory.
|
|
@@ -1249,6 +1386,38 @@ InitializeImageServices (
|
|
IN PEI_CORE_INSTANCE *OldCoreData
|
|
);
|
|
|
|
+/**
|
|
+ Loads and relocates a PE/COFF image in place.
|
|
+
|
|
+ @param Pe32Data The base address of the PE/COFF file that is to be loaded and relocated
|
|
+ @param ImageAddress The base address of the relocated PE/COFF image
|
|
+
|
|
+ @retval EFI_SUCCESS The file was loaded and relocated
|
|
+ @retval Others The file not be loaded and error occurred.
|
|
+
|
|
+**/
|
|
+EFI_STATUS
|
|
+LoadAndRelocatePeCoffImageInPlace (
|
|
+ IN VOID *Pe32Data,
|
|
+ IN VOID *ImageAddress
|
|
+ );
|
|
+
|
|
+/**
|
|
+ Find the PE32 Data for an FFS file.
|
|
+
|
|
+ @param FileHandle Pointer to the FFS file header of the image.
|
|
+ @param Pe32Data Pointer to a (VOID *) PE32 Data pointer.
|
|
+
|
|
+ @retval EFI_SUCCESS Image is successfully loaded.
|
|
+ @retval EFI_NOT_FOUND Fail to locate PE32 Data.
|
|
+
|
|
+**/
|
|
+EFI_STATUS
|
|
+PeiGetPe32Data (
|
|
+ IN EFI_PEI_FILE_HANDLE FileHandle,
|
|
+ OUT VOID **Pe32Data
|
|
+ );
|
|
+
|
|
/**
|
|
The wrapper function of PeiLoadImageLoadImage().
|
|
|
|
diff --git a/MdeModulePkg/Core/Pei/PeiMain.inf b/MdeModulePkg/Core/Pei/PeiMain.inf
|
|
index 6e25cc4023..5b36d516b3 100644
|
|
--- a/MdeModulePkg/Core/Pei/PeiMain.inf
|
|
+++ b/MdeModulePkg/Core/Pei/PeiMain.inf
|
|
@@ -76,6 +76,7 @@
|
|
## CONSUMES ## UNDEFINED # Locate PPI
|
|
## CONSUMES ## GUID # Used to compare with FV's file system GUID and get the FV's file system format
|
|
gEfiFirmwareFileSystem3Guid
|
|
+ gStatusCodeCallbackGuid
|
|
|
|
[Ppis]
|
|
gEfiPeiStatusCodePpiGuid ## SOMETIMES_CONSUMES # PeiReportStatusService is not ready if this PPI doesn't exist
|
|
@@ -109,6 +110,7 @@
|
|
gEfiMdeModulePkgTokenSpaceGuid.PcdShadowPeimOnS3Boot ## CONSUMES
|
|
gEfiMdeModulePkgTokenSpaceGuid.PcdShadowPeimOnBoot ## CONSUMES
|
|
gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack ## CONSUMES
|
|
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMigrateTemporaryRamFirmwareVolumes ## CONSUMES
|
|
|
|
# [BootMode]
|
|
# S3_RESUME ## SOMETIMES_CONSUMES
|
|
diff --git a/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c b/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
|
|
index cca57c4c06..2ad08878d9 100644
|
|
--- a/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
|
|
+++ b/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
|
|
@@ -319,8 +319,9 @@ PeiCore (
|
|
// PEI Core and PEIMs to get high performance.
|
|
//
|
|
OldCoreData->ShadowedPeiCore = (PEICORE_FUNCTION_POINTER) (UINTN) PeiCore;
|
|
- if ((HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME && PcdGetBool (PcdShadowPeimOnS3Boot))
|
|
- || (HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME && PcdGetBool (PcdShadowPeimOnBoot))) {
|
|
+ if (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
|
|
+ (HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME && PcdGetBool (PcdShadowPeimOnS3Boot)) ||
|
|
+ (HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME && PcdGetBool (PcdShadowPeimOnBoot))) {
|
|
OldCoreData->ShadowedPeiCore = ShadowPeiCore (OldCoreData);
|
|
}
|
|
|
|
@@ -418,6 +419,23 @@ PeiCore (
|
|
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
|
|
+ //
|
|
+ EvacuateTempRam (&PrivateData, SecCoreData);
|
|
+
|
|
+ DEBUG ((DEBUG_VERBOSE, "PPI lists after temporary RAM evacuation:\n"));
|
|
+ DumpPpiList (&PrivateData);
|
|
+ }
|
|
+
|
|
//
|
|
// Try to locate Temporary RAM Done Ppi.
|
|
//
|
|
diff --git a/MdeModulePkg/Core/Pei/Ppi/Ppi.c b/MdeModulePkg/Core/Pei/Ppi/Ppi.c
|
|
index 1ffe718c47..541047d98a 100644
|
|
--- a/MdeModulePkg/Core/Pei/Ppi/Ppi.c
|
|
+++ b/MdeModulePkg/Core/Pei/Ppi/Ppi.c
|
|
@@ -198,6 +198,227 @@ ConvertPpiPointers (
|
|
}
|
|
}
|
|
|
|
+/**
|
|
+
|
|
+ Migrate Notify Pointers inside an FV from temporary memory to permanent memory.
|
|
+
|
|
+ @param PrivateData Pointer to PeiCore's private data structure.
|
|
+ @param OrgFvHandle Address of FV Handle in temporary memory.
|
|
+ @param FvHandle Address of FV Handle in permanent memory.
|
|
+ @param FvSize Size of the FV.
|
|
+
|
|
+**/
|
|
+VOID
|
|
+ConvertPpiPointersFv (
|
|
+ IN PEI_CORE_INSTANCE *PrivateData,
|
|
+ IN UINTN OrgFvHandle,
|
|
+ IN UINTN FvHandle,
|
|
+ IN UINTN FvSize
|
|
+ )
|
|
+{
|
|
+ UINT8 Index;
|
|
+ UINTN Offset;
|
|
+ BOOLEAN OffsetPositive;
|
|
+ EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *FvInfoPpi;
|
|
+ UINT8 GuidIndex;
|
|
+ EFI_GUID *Guid;
|
|
+ EFI_GUID *GuidCheckList[2];
|
|
+
|
|
+ GuidCheckList[0] = &gEfiPeiFirmwareVolumeInfoPpiGuid;
|
|
+ GuidCheckList[1] = &gEfiPeiFirmwareVolumeInfo2PpiGuid;
|
|
+
|
|
+ if (FvHandle > OrgFvHandle) {
|
|
+ OffsetPositive = TRUE;
|
|
+ Offset = FvHandle - OrgFvHandle;
|
|
+ } else {
|
|
+ OffsetPositive = FALSE;
|
|
+ Offset = OrgFvHandle - FvHandle;
|
|
+ }
|
|
+
|
|
+ DEBUG ((DEBUG_VERBOSE, "Converting PPI pointers in FV.\n"));
|
|
+ DEBUG ((
|
|
+ DEBUG_VERBOSE,
|
|
+ " OrgFvHandle at 0x%08x. FvHandle at 0x%08x. FvSize = 0x%x\n",
|
|
+ (UINTN) OrgFvHandle,
|
|
+ (UINTN) FvHandle,
|
|
+ FvSize
|
|
+ ));
|
|
+ DEBUG ((
|
|
+ DEBUG_VERBOSE,
|
|
+ " OrgFvHandle range: 0x%08x - 0x%08x\n",
|
|
+ OrgFvHandle,
|
|
+ OrgFvHandle + FvSize
|
|
+ ));
|
|
+
|
|
+ for (Index = 0; Index < PrivateData->PpiData.CallbackNotifyList.CurrentCount; Index++) {
|
|
+ ConvertPointer (
|
|
+ (VOID **) &PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Raw,
|
|
+ OrgFvHandle,
|
|
+ OrgFvHandle + FvSize,
|
|
+ Offset,
|
|
+ OffsetPositive
|
|
+ );
|
|
+ ConvertPointer (
|
|
+ (VOID **) &PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Notify->Guid,
|
|
+ OrgFvHandle,
|
|
+ OrgFvHandle + FvSize,
|
|
+ Offset,
|
|
+ OffsetPositive
|
|
+ );
|
|
+ ConvertPointer (
|
|
+ (VOID **) &PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Notify->Notify,
|
|
+ OrgFvHandle,
|
|
+ OrgFvHandle + FvSize,
|
|
+ Offset,
|
|
+ OffsetPositive
|
|
+ );
|
|
+ }
|
|
+
|
|
+ for (Index = 0; Index < PrivateData->PpiData.DispatchNotifyList.CurrentCount; Index++) {
|
|
+ ConvertPointer (
|
|
+ (VOID **) &PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Raw,
|
|
+ OrgFvHandle,
|
|
+ OrgFvHandle + FvSize,
|
|
+ Offset,
|
|
+ OffsetPositive
|
|
+ );
|
|
+ ConvertPointer (
|
|
+ (VOID **) &PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Notify->Guid,
|
|
+ OrgFvHandle,
|
|
+ OrgFvHandle + FvSize,
|
|
+ Offset,
|
|
+ OffsetPositive
|
|
+ );
|
|
+ ConvertPointer (
|
|
+ (VOID **) &PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Notify->Notify,
|
|
+ OrgFvHandle,
|
|
+ OrgFvHandle + FvSize,
|
|
+ Offset,
|
|
+ OffsetPositive
|
|
+ );
|
|
+ }
|
|
+
|
|
+ for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
|
|
+ ConvertPointer (
|
|
+ (VOID **) &PrivateData->PpiData.PpiList.PpiPtrs[Index].Raw,
|
|
+ OrgFvHandle,
|
|
+ OrgFvHandle + FvSize,
|
|
+ Offset,
|
|
+ OffsetPositive
|
|
+ );
|
|
+ ConvertPointer (
|
|
+ (VOID **) &PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi->Guid,
|
|
+ OrgFvHandle,
|
|
+ OrgFvHandle + FvSize,
|
|
+ Offset,
|
|
+ OffsetPositive
|
|
+ );
|
|
+ ConvertPointer (
|
|
+ (VOID **) &PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi->Ppi,
|
|
+ OrgFvHandle,
|
|
+ OrgFvHandle + FvSize,
|
|
+ Offset,
|
|
+ OffsetPositive
|
|
+ );
|
|
+
|
|
+ Guid = PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi->Guid;
|
|
+ for (GuidIndex = 0; GuidIndex < ARRAY_SIZE (GuidCheckList); ++GuidIndex) {
|
|
+ //
|
|
+ // 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 *)GuidCheckList[GuidIndex])[0]) &&
|
|
+ (((INT32 *)Guid)[1] == ((INT32 *)GuidCheckList[GuidIndex])[1]) &&
|
|
+ (((INT32 *)Guid)[2] == ((INT32 *)GuidCheckList[GuidIndex])[2]) &&
|
|
+ (((INT32 *)Guid)[3] == ((INT32 *)GuidCheckList[GuidIndex])[3])) {
|
|
+ FvInfoPpi = PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi->Ppi;
|
|
+ DEBUG ((DEBUG_VERBOSE, " FvInfo: %p -> ", FvInfoPpi->FvInfo));
|
|
+ if ((UINTN)FvInfoPpi->FvInfo == OrgFvHandle) {
|
|
+ ConvertPointer (
|
|
+ (VOID **)&FvInfoPpi->FvInfo,
|
|
+ OrgFvHandle,
|
|
+ OrgFvHandle + FvSize,
|
|
+ Offset,
|
|
+ OffsetPositive
|
|
+ );
|
|
+ DEBUG ((DEBUG_VERBOSE, "%p", FvInfoPpi->FvInfo));
|
|
+ }
|
|
+ DEBUG ((DEBUG_VERBOSE, "\n"));
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+
|
|
+ Dumps the PPI lists to debug output.
|
|
+
|
|
+ @param PrivateData Points to PeiCore's private instance data.
|
|
+
|
|
+**/
|
|
+VOID
|
|
+DumpPpiList (
|
|
+ IN PEI_CORE_INSTANCE *PrivateData
|
|
+ )
|
|
+{
|
|
+ DEBUG_CODE_BEGIN ();
|
|
+ UINTN Index;
|
|
+
|
|
+ if (PrivateData == NULL) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ for (Index = 0; Index < PrivateData->PpiData.CallbackNotifyList.CurrentCount; Index++) {
|
|
+ DEBUG ((
|
|
+ DEBUG_VERBOSE,
|
|
+ "CallbackNotify[%2d] {%g} at 0x%x (%a)\n",
|
|
+ Index,
|
|
+ PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Notify->Guid,
|
|
+ (UINTN) PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Raw,
|
|
+ (
|
|
+ !(
|
|
+ ((EFI_PHYSICAL_ADDRESS) (UINTN) PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Raw >= PrivateData->PhysicalMemoryBegin) &&
|
|
+ (((EFI_PHYSICAL_ADDRESS) ((UINTN) PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Raw) + sizeof (EFI_PEI_NOTIFY_DESCRIPTOR)) < PrivateData->FreePhysicalMemoryTop)
|
|
+ )
|
|
+ ? "CAR" : "Post-Memory"
|
|
+ )
|
|
+ ));
|
|
+ }
|
|
+ for (Index = 0; Index < PrivateData->PpiData.DispatchNotifyList.CurrentCount; Index++) {
|
|
+ DEBUG ((DEBUG_VERBOSE,
|
|
+ "DispatchNotify[%2d] {%g} at 0x%x (%a)\n",
|
|
+ Index,
|
|
+ PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Notify->Guid,
|
|
+ (UINTN) PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Raw,
|
|
+ (
|
|
+ !(
|
|
+ ((EFI_PHYSICAL_ADDRESS) (UINTN) PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Raw >=PrivateData->PhysicalMemoryBegin) &&
|
|
+ (((EFI_PHYSICAL_ADDRESS) ((UINTN) PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Raw) + sizeof (EFI_PEI_NOTIFY_DESCRIPTOR)) < PrivateData->FreePhysicalMemoryTop)
|
|
+ )
|
|
+ ? "CAR" : "Post-Memory"
|
|
+ )
|
|
+ ));
|
|
+ }
|
|
+ for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
|
|
+ DEBUG ((DEBUG_VERBOSE,
|
|
+ "PPI[%2d] {%g} at 0x%x (%a)\n",
|
|
+ Index,
|
|
+ PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi->Guid,
|
|
+ (UINTN) PrivateData->PpiData.PpiList.PpiPtrs[Index].Raw,
|
|
+ (
|
|
+ !(
|
|
+ ((EFI_PHYSICAL_ADDRESS) (UINTN) PrivateData->PpiData.PpiList.PpiPtrs[Index].Raw >= PrivateData->PhysicalMemoryBegin) &&
|
|
+ (((EFI_PHYSICAL_ADDRESS) ((UINTN) PrivateData->PpiData.PpiList.PpiPtrs[Index].Raw) + sizeof (EFI_PEI_PPI_DESCRIPTOR)) < PrivateData->FreePhysicalMemoryTop)
|
|
+ )
|
|
+ ? "CAR" : "Post-Memory"
|
|
+ )
|
|
+ ));
|
|
+ }
|
|
+ DEBUG_CODE_END ();
|
|
+}
|
|
+
|
|
/**
|
|
|
|
This function installs an interface in the PEI PPI database by GUID.
|
|
@@ -830,3 +1051,68 @@ ProcessPpiListFromSec (
|
|
}
|
|
}
|
|
|
|
+/**
|
|
+
|
|
+ Migrate PPI Pointers of PEI_CORE from temporary memory to permanent memory.
|
|
+
|
|
+ @param PrivateData Pointer to PeiCore's private data structure.
|
|
+ @param CoreFvHandle Address of PEI_CORE FV Handle in temporary memory.
|
|
+
|
|
+**/
|
|
+VOID
|
|
+ConvertPeiCorePpiPointers (
|
|
+ IN PEI_CORE_INSTANCE *PrivateData,
|
|
+ PEI_CORE_FV_HANDLE CoreFvHandle
|
|
+ )
|
|
+{
|
|
+ EFI_FV_FILE_INFO FileInfo;
|
|
+ EFI_PHYSICAL_ADDRESS OrgImageBase;
|
|
+ EFI_PHYSICAL_ADDRESS MigratedImageBase;
|
|
+ UINTN PeiCoreModuleSize;
|
|
+ EFI_PEI_FILE_HANDLE PeiCoreFileHandle;
|
|
+ VOID *PeiCoreImageBase;
|
|
+ VOID *PeiCoreEntryPoint;
|
|
+ EFI_STATUS Status;
|
|
+
|
|
+ PeiCoreFileHandle = NULL;
|
|
+
|
|
+ //
|
|
+ // Find the PEI Core in the BFV in temporary memory.
|
|
+ //
|
|
+ Status = CoreFvHandle.FvPpi->FindFileByType (
|
|
+ CoreFvHandle.FvPpi,
|
|
+ EFI_FV_FILETYPE_PEI_CORE,
|
|
+ CoreFvHandle.FvHandle,
|
|
+ &PeiCoreFileHandle
|
|
+ );
|
|
+ ASSERT_EFI_ERROR (Status);
|
|
+
|
|
+ if (!EFI_ERROR (Status)) {
|
|
+ Status = CoreFvHandle.FvPpi->GetFileInfo (CoreFvHandle.FvPpi, PeiCoreFileHandle, &FileInfo);
|
|
+ ASSERT_EFI_ERROR (Status);
|
|
+
|
|
+ Status = PeiGetPe32Data (PeiCoreFileHandle, &PeiCoreImageBase);
|
|
+ ASSERT_EFI_ERROR (Status);
|
|
+
|
|
+ //
|
|
+ // Find PEI Core EntryPoint in the BFV in temporary memory.
|
|
+ //
|
|
+ Status = PeCoffLoaderGetEntryPoint ((VOID *) (UINTN) PeiCoreImageBase, &PeiCoreEntryPoint);
|
|
+ ASSERT_EFI_ERROR (Status);
|
|
+
|
|
+ OrgImageBase = (UINTN) PeiCoreImageBase;
|
|
+ MigratedImageBase = (UINTN) _ModuleEntryPoint - ((UINTN) PeiCoreEntryPoint - (UINTN) PeiCoreImageBase);
|
|
+
|
|
+ //
|
|
+ // Size of loaded PEI_CORE in permanent memory.
|
|
+ //
|
|
+ PeiCoreModuleSize = (UINTN)FileInfo.BufferSize - ((UINTN) OrgImageBase - (UINTN) FileInfo.Buffer);
|
|
+
|
|
+ //
|
|
+ // Migrate PEI_CORE PPI pointers from temporary memory to newly
|
|
+ // installed PEI_CORE in permanent memory.
|
|
+ //
|
|
+ ConvertPpiPointersFv (PrivateData, (UINTN) OrgImageBase, (UINTN) MigratedImageBase, PeiCoreModuleSize);
|
|
+ }
|
|
+}
|
|
+
|
|
--
|
|
2.27.0
|
|
|