From 8d764088ea3a182174d36caa9131198301515a89 Mon Sep 17 00:00:00 2001 From: Hongbin1 Zhang Date: Tue, 7 May 2024 15:46:49 +0800 Subject: [PATCH] StandaloneMmPkg/MmIpl: load MM Core and execute MM Core in MM RAM StandaloneMmIplPei will search the MM Core driver in all FV and relocate it to MM RAM, and enter MM Core entrypoint to run MM Core. Signed-off-by: Hongbin1 Zhang Cc: Jiewen Yao Cc: Ray Ni Cc: Star Zeng Cc: Jiaxin Wu Cc: Wei6 Xu Cc: Sami Mujawar Cc: Ard Biesheuvel Cc: Supreeth Venkatesh --- .../StandaloneMmIplPei/StandaloneMmIplPei.c | 337 ++++++++++++++++++ .../StandaloneMmIplPei/StandaloneMmIplPei.h | 6 + .../StandaloneMmIplPei/StandaloneMmIplPei.inf | 5 + StandaloneMmPkg/StandaloneMmPkg.dsc | 2 + 4 files changed, 350 insertions(+) diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c index 659c546d71..197e33cc3b 100644 --- a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c @@ -8,6 +8,336 @@ #include "StandaloneMmIplPei.h" +/** + Search all the available firmware volumes for MM Core driver. + + @param MmFvBase Base address of FV which included MM Core driver. + @param MmFvSize Size of FV which included MM Core driver. + @param MmCoreFileName GUID of MM Core. + @param MmCoreImageAddress MM Core image address. + + @retval EFI_SUCCESS The specified FFS section was returned. + @retval EFI_NOT_FOUND The specified FFS section could not be found. + +**/ +EFI_STATUS +LocateMmCoreFv ( + OUT EFI_PHYSICAL_ADDRESS *MmFvBase, + OUT UINTN *MmFvSize, + OUT EFI_GUID *MmCoreFileName, + OUT VOID **MmCoreImageAddress + ) +{ + EFI_STATUS Status; + UINTN FvIndex; + EFI_PEI_FV_HANDLE VolumeHandle; + EFI_PEI_FILE_HANDLE FileHandle; + EFI_PE32_SECTION *SectionData; + EFI_FV_INFO VolumeInfo; + + // + // Search all FV + // + VolumeHandle = NULL; + for (FvIndex = 0; ; FvIndex++) { + Status = PeiServicesFfsFindNextVolume (FvIndex, &VolumeHandle); + if (EFI_ERROR (Status)) { + break; + } + + // + // Search MM Core FFS + // + FileHandle = NULL; + Status = PeiServicesFfsFindNextFile (EFI_FV_FILETYPE_MM_CORE_STANDALONE, VolumeHandle, &FileHandle); + if (EFI_ERROR (Status)) { + continue; + } + + ASSERT (FileHandle != NULL); + if (FileHandle != NULL) { + CopyGuid (MmCoreFileName, &((EFI_FFS_FILE_HEADER *)FileHandle)->Name); + } + + // + // Search Section + // + Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, MmCoreImageAddress); + if (EFI_ERROR (Status)) { + continue; + } + + // + // Get MM Core section data. + // + SectionData = (EFI_PE32_SECTION *)((UINT8 *)*MmCoreImageAddress - sizeof (EFI_PE32_SECTION)); + ASSERT (SectionData->Type == EFI_SECTION_PE32); + + // + // This is the FV that contains MM Core. + // + Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo); + if (!EFI_ERROR (Status)) { + *MmFvBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VolumeInfo.FvStart; + *MmFvSize = VolumeInfo.FvSize; + return EFI_SUCCESS; + } else { + return EFI_NOT_FOUND; + } + } + + return EFI_NOT_FOUND; +} + +/** + Find largest unallocated MMRAM in current MMRAM descriptor block + + @param[in, out] LagestMmramRangeIndex Lagest mmram range index. + @param[in] CurrentBlock Current MMRAM descriptor block. + +**/ +VOID +FindLargestMmramRange ( + IN OUT UINTN *LagestMmramRangeIndex, + IN EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *CurrentBlock + ) +{ + UINTN Index; + UINT64 MaxSize; + BOOLEAN Found; + EFI_MMRAM_DESCRIPTOR *MmramRanges; + + MmramRanges = CurrentBlock->Descriptor; + + // + // Find largest Mmram range. + // + Found = FALSE; + for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < CurrentBlock->NumberOfMmReservedRegions; Index++) { + // + // Skip any MMRAM region that is already allocated, needs testing, or needs ECC initialization + // + if ((MmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) { + continue; + } + + if (MmramRanges[Index].CpuStart >= BASE_1MB) { + if ((MmramRanges[Index].CpuStart + MmramRanges[Index].PhysicalSize) <= BASE_4GB) { + if (MmramRanges[Index].PhysicalSize >= MaxSize) { + Found = TRUE; + *LagestMmramRangeIndex = Index; + MaxSize = MmramRanges[Index].PhysicalSize; + } + } + } + } + + if (Found == FALSE) { + DEBUG ((DEBUG_ERROR, "Not found largest unlocated MMRAM\n")); + ASSERT (FALSE); + CpuDeadLoop (); + } + + return; +} + +/** + Allocate available MMRAM for MM core image. + + @param[in] Pages Page count of MM core image. + @param[out] NewBlock Pointer of new mmram block HOB. + + @return EFI_PHYSICAL_ADDRESS Address for MM core image to be loaded in MMRAM. +**/ +EFI_PHYSICAL_ADDRESS +MmIplAllocateMmramPage ( + IN UINTN Pages, + OUT EFI_MMRAM_HOB_DESCRIPTOR_BLOCK **NewBlock + ) +{ + UINTN LagestMmramRangeIndex; + UINT32 FullMmramRangeCount; + EFI_HOB_GUID_TYPE *MmramInfoHob; + EFI_MMRAM_DESCRIPTOR *Largest; + EFI_MMRAM_DESCRIPTOR *Allocated; + EFI_MMRAM_DESCRIPTOR *FullMmramRanges; + EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *CurrentBlock; + EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *NewDescriptorBlock; + + MmramInfoHob = GetFirstGuidHob (&gEfiSmmSmramMemoryGuid); + ASSERT (MmramInfoHob != NULL); + if (MmramInfoHob == NULL) { + DEBUG ((DEBUG_WARN, "SmramMemoryReserve HOB not found\n")); + return 0; + } + + CurrentBlock = (EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *)(GET_GUID_HOB_DATA (MmramInfoHob)); + + // + // 1. Find largest unallocated MMRAM region + // + FindLargestMmramRange (&LagestMmramRangeIndex, CurrentBlock); + ASSERT (LagestMmramRangeIndex < CurrentBlock->NumberOfMmReservedRegions); + + // + // 2. Split the largest region and mark the allocated region as ALLOCATED + // + FullMmramRangeCount = CurrentBlock->NumberOfMmReservedRegions + 1; + NewDescriptorBlock = (EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *)BuildGuidHob ( + &gEfiSmmSmramMemoryGuid, + sizeof (EFI_MMRAM_HOB_DESCRIPTOR_BLOCK) + ((FullMmramRangeCount - 1) * sizeof (EFI_MMRAM_DESCRIPTOR)) + ); + ASSERT (NewDescriptorBlock != NULL); + + NewDescriptorBlock->NumberOfMmReservedRegions = FullMmramRangeCount; + FullMmramRanges = NewDescriptorBlock->Descriptor; + + // + // Get current MMRAM descriptors and fill to the full MMRAM ranges + // + CopyMem (NewDescriptorBlock->Descriptor, CurrentBlock->Descriptor, CurrentBlock->NumberOfMmReservedRegions * sizeof (EFI_MMRAM_DESCRIPTOR)); + + Largest = &FullMmramRanges[LagestMmramRangeIndex]; + ASSERT ((Largest->PhysicalSize & EFI_PAGE_MASK) == 0); + ASSERT (Largest->PhysicalSize > EFI_PAGES_TO_SIZE (Pages)); + + Allocated = &NewDescriptorBlock->Descriptor[NewDescriptorBlock->NumberOfMmReservedRegions - 1]; + + // + // Allocate MMRAM + // + Largest->PhysicalSize -= EFI_PAGES_TO_SIZE (Pages); + Allocated->CpuStart = Largest->CpuStart + Largest->PhysicalSize; + Allocated->PhysicalStart = Largest->PhysicalStart + Largest->PhysicalSize; + Allocated->RegionState = Largest->RegionState | EFI_ALLOCATED; + Allocated->PhysicalSize = EFI_PAGES_TO_SIZE (Pages); + + // + // Scrub old one + // + ZeroMem (&MmramInfoHob->Name, sizeof (MmramInfoHob->Name)); + + // + // New MMRAM descriptor block + // + *NewBlock = NewDescriptorBlock; + + return Allocated->CpuStart; +} + +/** + Load the MM Core image into MMRAM and executes the MM Core from MMRAM. + + @param[in] MmCommBuffer MM communicate buffer + + @return EFI_STATUS Execute MM core successfully. + Other Execute MM core failed. +**/ +EFI_STATUS +ExecuteMmCoreFromMmram ( + IN MM_COMM_BUFFER *MmCommBuffer + ) +{ + EFI_STATUS Status; + UINTN PageCount; + VOID *MmHobList; + EFI_GUID MmCoreFileName; + UINTN MmFvSize; + EFI_PHYSICAL_ADDRESS MmFvBase; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + STANDALONE_MM_FOUNDATION_ENTRY_POINT Entry; + EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *Block; + + MmFvBase = 0; + MmFvSize = 0; + // + // Search all Firmware Volumes for a PE/COFF image in a file of type MM_CORE_STANDALONE. + // + Status = LocateMmCoreFv (&MmFvBase, &MmFvSize, &MmCoreFileName, &ImageContext.Handle); + ASSERT_EFI_ERROR (Status); + + // + // Unblock the MM FV range to be accessible from inside MM + // + if ((MmFvBase != 0) && (MmFvSize != 0)) { + Status = MmUnblockMemoryRequest (MmFvBase, EFI_SIZE_TO_PAGES (MmFvSize)); + ASSERT_EFI_ERROR (Status); + } + + // + // Initialize ImageContext + // + ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; + + // + // Get information about the image being loaded + // + Status = PeCoffLoaderGetImageInfo (&ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + + PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); + + // + // Allocate memory for the image being loaded from unallocated mmram range + // + ImageContext.ImageAddress = MmIplAllocateMmramPage (PageCount, &Block); + if (ImageContext.ImageAddress == 0) { + return EFI_NOT_FOUND; + } + + // + // Align buffer on section boundary + // + ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; + ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1); + + // + // Print debug message showing MM Core load address. + // + DEBUG ((DEBUG_INFO, "StandaloneMM IPL loading MM Core at MMRAM address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress)); + + // + // Load the image to our new buffer + // + Status = PeCoffLoaderLoadImage (&ImageContext); + if (!EFI_ERROR (Status)) { + // + // Relocate the image in our new buffer + // + Status = PeCoffLoaderRelocateImage (&ImageContext); + if (!EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "MmCoreImageBase - 0x%016lx\n", ImageContext.ImageAddress)); + DEBUG ((DEBUG_INFO, "MmCoreImageSize - 0x%016lx\n", ImageContext.ImageSize)); + + // + // Flush the instruction cache so the image data are written before we execute it + // + InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); + + // + // Get HOB list for Standalone MM Core. + // + MmHobList = GetHobList (); + + // + // Print debug message showing Standalone MM Core entry point address. + // + DEBUG ((DEBUG_INFO, "StandaloneMM IPL calling Standalone MM Core at MMRAM address - 0x%016lx\n", ImageContext.EntryPoint)); + + // + // Execute image + // + Entry = (STANDALONE_MM_FOUNDATION_ENTRY_POINT)(UINTN)ImageContext.EntryPoint; + Status = Entry (MmHobList); + ASSERT_EFI_ERROR (Status); + } + } + + return Status; +} + /** Build communication buffer HOB. @@ -86,6 +416,7 @@ StandaloneMmIplPeiEntry ( IN CONST EFI_PEI_SERVICES **PeiServices ) { + EFI_STATUS Status; MM_COMM_BUFFER *MmCommBuffer; // @@ -94,5 +425,11 @@ StandaloneMmIplPeiEntry ( MmCommBuffer = MmIplBuildCommBufferHob (); ASSERT (MmCommBuffer != NULL); + // + // Locate and execute Mm Core to dispatch MM drivers. + // + Status = ExecuteMmCoreFromMmram (MmCommBuffer); + ASSERT_EFI_ERROR (Status); + return EFI_SUCCESS; } diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h index e827852c31..f099af5feb 100644 --- a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h @@ -9,10 +9,16 @@ #ifndef STANDALONE_MM_IPL_PEI_H_ #define STANDALONE_MM_IPL_PEI_H_ +#include #include +#include #include #include #include +#include #include +#include +#include +#include #endif diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf index 8811cc9e36..0a03aa0af1 100644 --- a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf @@ -33,13 +33,18 @@ [LibraryClasses] PeimEntryPoint + PeiServicesLib DebugLib HobLib MemoryAllocationLib MmUnblockMemoryLib + BaseMemoryLib + PeCoffLib + CacheMaintenanceLib [Guids] gMmCommBufferHobGuid + gEfiSmmSmramMemoryGuid [Ppis] diff --git a/StandaloneMmPkg/StandaloneMmPkg.dsc b/StandaloneMmPkg/StandaloneMmPkg.dsc index e42a161947..a2410f37d3 100644 --- a/StandaloneMmPkg/StandaloneMmPkg.dsc +++ b/StandaloneMmPkg/StandaloneMmPkg.dsc @@ -66,6 +66,8 @@ HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf + PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf + PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf MmUnblockMemoryLib|MdePkg/Library/MmUnblockMemoryLib/MmUnblockMemoryLibNull.inf [LibraryClasses.AARCH64, LibraryClasses.ARM]