StandaloneMmPkg/StandaloneMmCoreEntryPoint: relocate StMM core on the fly

Apply PE/COFF fixups when starting up the standalone MM core, so that
it can execute at any address regardless of the link time address.

Note that this requires the PE/COFF image to be emitted with its
relocation section preserved. Special care is taken to ensure that
TE images are dealt with correctly as well.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
Acked-by: Jiewen Yao <Jiewen.yao@intel.com>
Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>
Tested-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
diff --git a/StandaloneMmPkg/Include/Library/AArch64/StandaloneMmCoreEntryPoint.h b/StandaloneMmPkg/Include/Library/AArch64/StandaloneMmCoreEntryPoint.h
index 494bcf3..0f9a032 100644
--- a/StandaloneMmPkg/Include/Library/AArch64/StandaloneMmCoreEntryPoint.h
+++ b/StandaloneMmPkg/Include/Library/AArch64/StandaloneMmCoreEntryPoint.h
@@ -71,6 +71,7 @@
   and make further progress in the boot process.

 

   @param  ImageContext           Pointer to PE/COFF image context

+  @param  ImageBase              Base of image in memory

   @param  SectionHeaderOffset    Offset of PE/COFF image section header

   @param  NumberOfSections       Number of Sections

   @param  TextUpdater            Function to change code permissions

@@ -82,6 +83,7 @@
 EFIAPI

 UpdateMmFoundationPeCoffPermissions (

   IN  CONST PE_COFF_LOADER_IMAGE_CONTEXT      *ImageContext,

+  IN  EFI_PHYSICAL_ADDRESS                    ImageBase,

   IN  UINT32                                  SectionHeaderOffset,

   IN  CONST  UINT16                           NumberOfSections,

   IN  REGION_PERMISSION_UPDATE_FUNC           TextUpdater,

@@ -98,6 +100,7 @@
 

   @param  TeData                 Pointer to PE/COFF image data

   @param  ImageContext           Pointer to PE/COFF image context

+  @param  ImageBase              Pointer to ImageBase variable

   @param  SectionHeaderOffset    Offset of PE/COFF image section header

   @param  NumberOfSections       Number of Sections

 

@@ -107,6 +110,7 @@
 GetStandaloneMmCorePeCoffSections (

   IN        VOID                            *TeData,

   IN  OUT   PE_COFF_LOADER_IMAGE_CONTEXT    *ImageContext,

+      OUT   EFI_PHYSICAL_ADDRESS            *ImageBase,

   IN  OUT   UINT32                          *SectionHeaderOffset,

   IN  OUT   UINT16                          *NumberOfSections

   );

diff --git a/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c b/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c
index 00f49c9..bf9650d 100644
--- a/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c
+++ b/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c
@@ -29,6 +29,7 @@
 EFIAPI

 UpdateMmFoundationPeCoffPermissions (

   IN  CONST PE_COFF_LOADER_IMAGE_CONTEXT      *ImageContext,

+  IN  EFI_PHYSICAL_ADDRESS                    ImageBase,

   IN  UINT32                                  SectionHeaderOffset,

   IN  CONST  UINT16                           NumberOfSections,

   IN  REGION_PERMISSION_UPDATE_FUNC           TextUpdater,

@@ -87,7 +88,7 @@
     // if it is a writeable section then mark it appropriately as well.

     //

     if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) {

-      Base = ImageContext->ImageAddress + SectionHeader.VirtualAddress;

+      Base = ImageBase + SectionHeader.VirtualAddress;

 

       TextUpdater (Base, SectionHeader.Misc.VirtualSize);

 

@@ -153,6 +154,7 @@
 EFI_STATUS

 GetPeCoffSectionInformation (

   IN  OUT   PE_COFF_LOADER_IMAGE_CONTEXT      *ImageContext,

+      OUT   EFI_PHYSICAL_ADDRESS              *ImageBase,

       OUT   UINT32                            *SectionHeaderOffset,

       OUT   UINT16                            *NumberOfSections

   )

@@ -212,6 +214,7 @@
     return Status;

   }

 

+  *ImageBase = ImageContext->ImageAddress;

   if (!ImageContext->IsTeImage) {

     ASSERT (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE);

 

@@ -232,7 +235,7 @@
   } else {

     *SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));

     *NumberOfSections = Hdr.Te->NumberOfSections;

-    ImageContext->ImageAddress -= (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);

+    *ImageBase -= (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);

   }

   return RETURN_SUCCESS;

 }

@@ -242,6 +245,7 @@
 GetStandaloneMmCorePeCoffSections (

   IN        VOID                            *TeData,

   IN  OUT   PE_COFF_LOADER_IMAGE_CONTEXT    *ImageContext,

+      OUT   EFI_PHYSICAL_ADDRESS            *ImageBase,

   IN  OUT   UINT32                          *SectionHeaderOffset,

   IN  OUT   UINT16                          *NumberOfSections

   )

@@ -255,7 +259,8 @@
 

   DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", TeData));

 

-  Status = GetPeCoffSectionInformation (ImageContext, SectionHeaderOffset, NumberOfSections);

+  Status = GetPeCoffSectionInformation (ImageContext, ImageBase,

+             SectionHeaderOffset, NumberOfSections);

   if (EFI_ERROR (Status)) {

     DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM Core PE-COFF Section information - %r\n", Status));

     return Status;

diff --git a/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c b/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c
index 2072338..9cecfa6 100644
--- a/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c
+++ b/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c
@@ -225,6 +225,7 @@
   VOID                                    *HobStart;

   VOID                                    *TeData;

   UINTN                                   TeDataSize;

+  EFI_PHYSICAL_ADDRESS                    ImageBase;

 

   // Get Secure Partition Manager Version Information

   Status = GetSpmVersion ();

@@ -253,6 +254,7 @@
   Status = GetStandaloneMmCorePeCoffSections (

              TeData,

              &ImageContext,

+             &ImageBase,

              &SectionHeaderOffset,

              &NumberOfSections

              );

@@ -261,10 +263,21 @@
     goto finish;

   }

 

+  //

+  // ImageBase may deviate from ImageContext.ImageAddress if we are dealing

+  // with a TE image, in which case the latter points to the actual offset

+  // of the image, whereas ImageBase refers to the address where the image

+  // would start if the stripped PE headers were still in place. In either

+  // case, we need to fix up ImageBase so it refers to the actual current

+  // load address.

+  //

+  ImageBase += (UINTN)TeData - ImageContext.ImageAddress;

+

   // Update the memory access permissions of individual sections in the

   // Standalone MM core module

   Status = UpdateMmFoundationPeCoffPermissions (

              &ImageContext,

+             ImageBase,

              SectionHeaderOffset,

              NumberOfSections,

              ArmSetMemoryRegionNoExec,

@@ -276,6 +289,15 @@
     goto finish;

   }

 

+  if (ImageContext.ImageAddress != (UINTN)TeData) {

+    ImageContext.ImageAddress = (UINTN)TeData;

+    ArmSetMemoryRegionNoExec (ImageBase, SIZE_4KB);

+    ArmClearMemoryRegionReadOnly (ImageBase, SIZE_4KB);

+

+    Status = PeCoffLoaderRelocateImage (&ImageContext);

+    ASSERT_EFI_ERROR (Status);

+  }

+

   //

   // Create Hoblist based upon boot information passed by privileged software

   //