[edk2-devel] [PATCH v2 1/9] MdeModulePkg/PeiCore: Enable T-RAM evacuation in PeiCore (CVE-2019-11098)

Guomin Jiang posted 9 patches 4 years, 4 months ago
[edk2-devel] [PATCH v2 1/9] MdeModulePkg/PeiCore: Enable T-RAM evacuation in PeiCore (CVE-2019-11098)
Posted by Guomin Jiang 4 years, 4 months ago
From: Michael Kubacki <michael.a.kubacki@intel.com>

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.

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>
---
 MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c | 402 ++++++++++++++++++
 MdeModulePkg/Core/Pei/Image/Image.c           | 115 +++++
 MdeModulePkg/Core/Pei/Memory/MemoryServices.c |  82 ++++
 MdeModulePkg/Core/Pei/PeiMain.h               | 168 ++++++++
 MdeModulePkg/Core/Pei/PeiMain.inf             |   1 +
 MdeModulePkg/Core/Pei/PeiMain/PeiMain.c       |  16 +
 MdeModulePkg/Core/Pei/Ppi/Ppi.c               | 287 +++++++++++++
 7 files changed, 1071 insertions(+)

diff --git a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
index 4c2eac1384e8..ef88b3423376 100644
--- a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
+++ b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
@@ -952,6 +952,408 @@ 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) {
+    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));
+
+    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[%d] from 0x%08X to ", Index, CallbackEntry[Index]));
+          if (OrgFvHandle > FvHandle) {
+            CallbackEntry[Index] = CallbackEntry[Index] - (OrgFvHandle - FvHandle);
+          } else {
+            CallbackEntry[Index] = CallbackEntry[Index] + (FvHandle - OrgFvHandle);
+          }
+          DEBUG ((DEBUG_INFO, "0x%08X\n", 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.
+
+**/
+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_INFO, "\n"));
+        ASSERT_EFI_ERROR (Status);
+
+        if (!EFI_ERROR (Status)) {
+          // if (Private->Fv[FvIndex].PeimState[FileIndex] == PEIM_STATE_REGISTER_FOR_SHADOW) {
+          //   Private->Fv[FvIndex].PeimState[FileIndex]++;
+          // }
+          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));
+
+          // @todo: find issue with file and section alignment in SEC PE32 images for migration
+          //        (alignment in P32 is given as 32-bit when actual alignment is 16-bit)
+          //        SEC PPIs are currently re-installed with a dedicated PEIM
+          // Status = MigrateSecModulesInFv (Private, FvChildIndex, (UINTN) ChildFvHeader);
+          // ASSERT_EFI_ERROR (Status);
+          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;
+
+      // @todo: find issue with file and section alignment in SEC PE32 images for migration
+      //        (alignment in P32 is given as 32-bit when actual alignment is 16-bit)
+      //        SEC PPIs are currently re-installed with a dedicated PEIM
+      // Status = MigrateSecModulesInFv (Private, FvIndex, (UINTN) FvHeader);
+      // ASSERT_EFI_ERROR (Status);
+      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.
 
diff --git a/MdeModulePkg/Core/Pei/Image/Image.c b/MdeModulePkg/Core/Pei/Image/Image.c
index e3ee3699337f..612797722a3e 100644
--- a/MdeModulePkg/Core/Pei/Image/Image.c
+++ b/MdeModulePkg/Core/Pei/Image/Image.c
@@ -444,6 +444,121 @@ 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
+
+**/
+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 6b3a64a811cd..9d933f0393a8 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 56b3bd85793d..b0101dba5e30 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,37 @@ 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
+
+**/
+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 6e25cc40232a..5ff14100a65f 100644
--- a/MdeModulePkg/Core/Pei/PeiMain.inf
+++ b/MdeModulePkg/Core/Pei/PeiMain.inf
@@ -76,6 +76,7 @@ [Guids]
   ## 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
diff --git a/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c b/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
index cca57c4c0686..802cd239e2eb 100644
--- a/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
+++ b/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
@@ -418,6 +418,22 @@ PeiCore (
       ProcessPpiListFromSec ((CONST EFI_PEI_SERVICES **) &PrivateData.Ps, PpiList);
     }
   } else {
+    if (
+      (!(PrivateData.HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) && PcdGetBool (PcdShadowPeimOnBoot)) ||
+      ((PrivateData.HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) && PcdGetBool (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 1ffe718c4702..018b25f86470 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,69 @@ 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.25.1.windows.1


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#61942): https://edk2.groups.io/g/devel/message/61942
Mute This Topic: https://groups.io/mt/75252660/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-

Re: [edk2-devel] [PATCH v2 1/9] MdeModulePkg/PeiCore: Enable T-RAM evacuation in PeiCore (CVE-2019-11098)
Posted by Laszlo Ersek 4 years, 4 months ago
On 07/02/20 07:15, Guomin Jiang wrote:

> diff --git a/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c b/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
> index cca57c4c0686..802cd239e2eb 100644
> --- a/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
> +++ b/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
> @@ -418,6 +418,22 @@ PeiCore (
>        ProcessPpiListFromSec ((CONST EFI_PEI_SERVICES **) &PrivateData.Ps, PpiList);
>      }
>    } else {
> +    if (
> +      (!(PrivateData.HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) && PcdGetBool (PcdShadowPeimOnBoot)) ||
> +      ((PrivateData.HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) && PcdGetBool (PcdShadowPeimOnS3Boot))
> +      ) {

(1) This condition is expressed very confusingly.

First, it is unhelpful to express the condition

  BootMode != BOOT_ON_S3_RESUME

as

  !(BootMode == BOOT_ON_S3_RESUME)

Second, we can simplify this a lot, by selecting the PCD explicitly,
dependent on boot mode, that controls shadowing.

Put differently, if the boot mode is *not* S3, and PcdShadowPeimOnBoot
is FALSE (and so we will not shadow the PEI core), then it makes no
sense to check the boot mode *again*, on the next line.

So I suggest:

  BOOLEAN Shadow;

  if (PrivateData.HobList.HandoffInformationTable->BootMode ==
      BOOT_ON_S3_RESUME) {
    Shadow = PcdGetBool (PcdShadowPeimOnS3Boot);
  } else {
    Shadow = PcdGetBool (PcdShadowPeimOnBoot);
  }

  if (Shadow) {
    //
    // ...
    //
  }


> +      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.
>      //

Thanks
Laszlo


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#62028): https://edk2.groups.io/g/devel/message/62028
Mute This Topic: https://groups.io/mt/75252660/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-

Re: [edk2-devel] [PATCH v2 1/9] MdeModulePkg/PeiCore: Enable T-RAM evacuation in PeiCore (CVE-2019-11098)
Posted by Laszlo Ersek 4 years, 4 months ago
On 07/02/20 07:15, Guomin Jiang wrote:
> From: Michael Kubacki <michael.a.kubacki@intel.com>
> 
> 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.
> 
> 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>
> ---
>  MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c | 402 ++++++++++++++++++
>  MdeModulePkg/Core/Pei/Image/Image.c           | 115 +++++
>  MdeModulePkg/Core/Pei/Memory/MemoryServices.c |  82 ++++
>  MdeModulePkg/Core/Pei/PeiMain.h               | 168 ++++++++
>  MdeModulePkg/Core/Pei/PeiMain.inf             |   1 +
>  MdeModulePkg/Core/Pei/PeiMain/PeiMain.c       |  16 +
>  MdeModulePkg/Core/Pei/Ppi/Ppi.c               | 287 +++++++++++++
>  7 files changed, 1071 insertions(+)

(2) The commit message of this patch should be extended with a
simplified call tree of *all* the functions introduced. As follows:

  PeiCore()
    DumpPpiList()
    EvacuateTempRam()
      ConvertPeiCorePpiPointers()
        PeiGetPe32Data()
        ConvertPpiPointersFv()
      MigrateSecModulesInFv()
        LoadAndRelocatePeCoffImageInPlace()
      MigratePeimsInFv()
        MigratePeim()
          PeiGetPe32Data()
          LoadAndRelocatePeCoffImageInPlace()
      ConvertPpiPointersFv()
      ConvertStatusCodeCallbacks()
      ConvertFvHob()
      RemoveFvHobsInTemporaryMemory()
    DumpPpiList()

Thanks
Laszlo


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#62032): https://edk2.groups.io/g/devel/message/62032
Mute This Topic: https://groups.io/mt/75252660/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-