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>
This commit is contained in:
Ard Biesheuvel 2020-06-09 10:34:27 +02:00 committed by mergify[bot]
parent cdc686223a
commit 493f2c6931
3 changed files with 34 additions and 3 deletions

View File

@ -71,6 +71,7 @@ typedef RETURN_STATUS (*REGION_PERMISSION_UPDATE_FUNC) (
and make further progress in the boot process. and make further progress in the boot process.
@param ImageContext Pointer to PE/COFF image context @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 SectionHeaderOffset Offset of PE/COFF image section header
@param NumberOfSections Number of Sections @param NumberOfSections Number of Sections
@param TextUpdater Function to change code permissions @param TextUpdater Function to change code permissions
@ -82,6 +83,7 @@ EFI_STATUS
EFIAPI EFIAPI
UpdateMmFoundationPeCoffPermissions ( UpdateMmFoundationPeCoffPermissions (
IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
IN EFI_PHYSICAL_ADDRESS ImageBase,
IN UINT32 SectionHeaderOffset, IN UINT32 SectionHeaderOffset,
IN CONST UINT16 NumberOfSections, IN CONST UINT16 NumberOfSections,
IN REGION_PERMISSION_UPDATE_FUNC TextUpdater, IN REGION_PERMISSION_UPDATE_FUNC TextUpdater,
@ -98,6 +100,7 @@ UpdateMmFoundationPeCoffPermissions (
@param TeData Pointer to PE/COFF image data @param TeData Pointer to PE/COFF image data
@param ImageContext Pointer to PE/COFF image context @param ImageContext Pointer to PE/COFF image context
@param ImageBase Pointer to ImageBase variable
@param SectionHeaderOffset Offset of PE/COFF image section header @param SectionHeaderOffset Offset of PE/COFF image section header
@param NumberOfSections Number of Sections @param NumberOfSections Number of Sections
@ -107,6 +110,7 @@ EFIAPI
GetStandaloneMmCorePeCoffSections ( GetStandaloneMmCorePeCoffSections (
IN VOID *TeData, IN VOID *TeData,
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
OUT EFI_PHYSICAL_ADDRESS *ImageBase,
IN OUT UINT32 *SectionHeaderOffset, IN OUT UINT32 *SectionHeaderOffset,
IN OUT UINT16 *NumberOfSections IN OUT UINT16 *NumberOfSections
); );

View File

@ -29,6 +29,7 @@ EFI_STATUS
EFIAPI EFIAPI
UpdateMmFoundationPeCoffPermissions ( UpdateMmFoundationPeCoffPermissions (
IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
IN EFI_PHYSICAL_ADDRESS ImageBase,
IN UINT32 SectionHeaderOffset, IN UINT32 SectionHeaderOffset,
IN CONST UINT16 NumberOfSections, IN CONST UINT16 NumberOfSections,
IN REGION_PERMISSION_UPDATE_FUNC TextUpdater, IN REGION_PERMISSION_UPDATE_FUNC TextUpdater,
@ -87,7 +88,7 @@ UpdateMmFoundationPeCoffPermissions (
// if it is a writeable section then mark it appropriately as well. // if it is a writeable section then mark it appropriately as well.
// //
if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) { if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) {
Base = ImageContext->ImageAddress + SectionHeader.VirtualAddress; Base = ImageBase + SectionHeader.VirtualAddress;
TextUpdater (Base, SectionHeader.Misc.VirtualSize); TextUpdater (Base, SectionHeader.Misc.VirtualSize);
@ -153,6 +154,7 @@ STATIC
EFI_STATUS EFI_STATUS
GetPeCoffSectionInformation ( GetPeCoffSectionInformation (
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
OUT EFI_PHYSICAL_ADDRESS *ImageBase,
OUT UINT32 *SectionHeaderOffset, OUT UINT32 *SectionHeaderOffset,
OUT UINT16 *NumberOfSections OUT UINT16 *NumberOfSections
) )
@ -212,6 +214,7 @@ GetPeCoffSectionInformation (
return Status; return Status;
} }
*ImageBase = ImageContext->ImageAddress;
if (!ImageContext->IsTeImage) { if (!ImageContext->IsTeImage) {
ASSERT (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE); ASSERT (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE);
@ -232,7 +235,7 @@ GetPeCoffSectionInformation (
} else { } else {
*SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER)); *SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));
*NumberOfSections = Hdr.Te->NumberOfSections; *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; return RETURN_SUCCESS;
} }
@ -242,6 +245,7 @@ EFIAPI
GetStandaloneMmCorePeCoffSections ( GetStandaloneMmCorePeCoffSections (
IN VOID *TeData, IN VOID *TeData,
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
OUT EFI_PHYSICAL_ADDRESS *ImageBase,
IN OUT UINT32 *SectionHeaderOffset, IN OUT UINT32 *SectionHeaderOffset,
IN OUT UINT16 *NumberOfSections IN OUT UINT16 *NumberOfSections
) )
@ -255,7 +259,8 @@ GetStandaloneMmCorePeCoffSections (
DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", TeData)); 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)) { if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM Core PE-COFF Section information - %r\n", Status)); DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM Core PE-COFF Section information - %r\n", Status));
return Status; return Status;

View File

@ -225,6 +225,7 @@ _ModuleEntryPoint (
VOID *HobStart; VOID *HobStart;
VOID *TeData; VOID *TeData;
UINTN TeDataSize; UINTN TeDataSize;
EFI_PHYSICAL_ADDRESS ImageBase;
// Get Secure Partition Manager Version Information // Get Secure Partition Manager Version Information
Status = GetSpmVersion (); Status = GetSpmVersion ();
@ -253,6 +254,7 @@ _ModuleEntryPoint (
Status = GetStandaloneMmCorePeCoffSections ( Status = GetStandaloneMmCorePeCoffSections (
TeData, TeData,
&ImageContext, &ImageContext,
&ImageBase,
&SectionHeaderOffset, &SectionHeaderOffset,
&NumberOfSections &NumberOfSections
); );
@ -261,10 +263,21 @@ _ModuleEntryPoint (
goto finish; 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 // Update the memory access permissions of individual sections in the
// Standalone MM core module // Standalone MM core module
Status = UpdateMmFoundationPeCoffPermissions ( Status = UpdateMmFoundationPeCoffPermissions (
&ImageContext, &ImageContext,
ImageBase,
SectionHeaderOffset, SectionHeaderOffset,
NumberOfSections, NumberOfSections,
ArmSetMemoryRegionNoExec, ArmSetMemoryRegionNoExec,
@ -276,6 +289,15 @@ _ModuleEntryPoint (
goto finish; 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 // Create Hoblist based upon boot information passed by privileged software
// //