diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/MmFoundationHob.c b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/MmFoundationHob.c new file mode 100644 index 0000000000..df3355f3fc --- /dev/null +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/MmFoundationHob.c @@ -0,0 +1,292 @@ +/** @file + + Copyright (c) 2024, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +/** + Add a new HOB to the HOB List. + + @param[in] Hob The pointer of new HOB buffer. + @param[in] HobType Type of the new HOB. + @param[in] HobLength Length of the new HOB to allocate. + + @return NULL if there is no space to create a hob. + @return The address point to the new created hob. + +**/ +VOID * +MmIplCreateHob ( + IN VOID *Hob, + IN UINT16 HobType, + IN UINT16 HobLength + ) +{ + // + // Check Length to avoid data overflow. + // + ASSERT (HobLength < MAX_UINT16 - 0x7); + + HobLength = (UINT16)ALIGN_VALUE (HobLength, 8); + + ((EFI_HOB_GENERIC_HEADER *)Hob)->HobType = HobType; + ((EFI_HOB_GENERIC_HEADER *)Hob)->HobLength = HobLength; + ((EFI_HOB_GENERIC_HEADER *)Hob)->Reserved = 0; + + return Hob; +} + +/** + Builds a Firmware Volume HOB. + + This function builds a Firmware Volume HOB. + It can only be invoked during PEI phase; + If new HOB buffer is NULL, then ASSERT(). + + @param[in] Hob The pointer of new HOB buffer. + @param[in, out] HobBufferSize The available size of the HOB buffer when as input. + The used size of when as output. + @param[in] BaseAddress The base address of the Firmware Volume. + @param[in] Length The size of the Firmware Volume in bytes. + +**/ +VOID +MmIplBuildFvHob ( + IN UINT8 *Hob, + IN OUT UINTN *HobBufferSize, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + EFI_HOB_FIRMWARE_VOLUME *FvHob; + UINT16 HobLength; + + ASSERT (Hob != NULL); + + HobLength = ALIGN_VALUE (sizeof (EFI_HOB_FIRMWARE_VOLUME), 8); + if (*HobBufferSize >= HobLength) { + MmIplCreateHob (Hob, EFI_HOB_TYPE_FV, sizeof (EFI_HOB_FIRMWARE_VOLUME)); + + FvHob = (EFI_HOB_FIRMWARE_VOLUME *)Hob; + FvHob->BaseAddress = BaseAddress; + FvHob->Length = Length; + } + + *HobBufferSize = HobLength; +} + +/** + Copies a data buffer to a newly-built HOB for GUID HOB + + This function builds a customized HOB tagged with a GUID for identification, copies the + input data to the HOB data field and returns the start address of the GUID HOB data. + If new HOB buffer is NULL or the GUID HOB could not found, then ASSERT(). + + @param[in] HobBuffer The pointer of HOB buffer. + @param[in, out] HobBufferSize The available size of the HOB buffer when as input. + The used size of when as output. + @param[in] Guid The GUID of the GUID type HOB. + @param[in] MultiInstances TRUE indicating copying multiple HOBs with the same Guid. +**/ +VOID +MmIplCopyGuidHob ( + IN UINT8 *HobBuffer, + IN OUT UINTN *HobBufferSize, + IN EFI_GUID *Guid, + IN BOOLEAN MultiInstances + ) +{ + EFI_HOB_GENERIC_HEADER *GuidHob; + UINTN UsedSize; + + UsedSize = 0; + GuidHob = GetFirstGuidHob (Guid); + ASSERT (GuidHob != NULL); + + while (GuidHob != NULL) { + if (*HobBufferSize >= UsedSize + GuidHob->HobLength) { + CopyMem (HobBuffer + UsedSize, GuidHob, GuidHob->HobLength); + } + + UsedSize += GuidHob->HobLength; + + if (!MultiInstances) { + break; + } + + GuidHob = GetNextGuidHob (Guid, GET_NEXT_HOB (GuidHob)); + } + + *HobBufferSize = UsedSize; +} + +/** + Builds a HOB for a loaded PE32 module. + + This function builds a HOB for a loaded PE32 module. + It can only be invoked during PEI phase; + If physical address of the Module is not 4K aligned, then ASSERT(). + If new HOB buffer is NULL, then ASSERT(). + + @param[in] Hob The pointer of new HOB buffer. + @param[in, out] HobBufferSize The available size of the HOB buffer when as input. + The used size of when as output. + @param[in] ModuleName The GUID File Name of the module. + @param[in] Base The 64 bit physical address of the module. + @param[in] Length The length of the module in bytes. + @param[in] EntryPoint The 64 bit physical address of the module entry point. + +**/ +VOID +MmIplBuildMmCoreModuleHob ( + IN UINT8 *Hob, + IN OUT UINTN *HobBufferSize, + IN CONST EFI_GUID *ModuleName, + IN EFI_PHYSICAL_ADDRESS Base, + IN UINT64 Length, + IN EFI_PHYSICAL_ADDRESS EntryPoint + ) +{ + UINT16 HobLength; + EFI_HOB_MEMORY_ALLOCATION_MODULE *MmCoreModuleHob; + + ASSERT (Hob != NULL); + ASSERT (ADDRESS_IS_ALIGNED (Base, EFI_PAGE_SIZE)); + ASSERT (IS_ALIGNED (Length, EFI_PAGE_SIZE)); + ASSERT (EntryPoint >= Base && EntryPoint < Base + Length); + + HobLength = ALIGN_VALUE (sizeof (EFI_HOB_MEMORY_ALLOCATION_MODULE), 8); + if (*HobBufferSize >= HobLength) { + MmIplCreateHob (Hob, EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION_MODULE)); + + MmCoreModuleHob = (EFI_HOB_MEMORY_ALLOCATION_MODULE *)Hob; + CopyGuid (&MmCoreModuleHob->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid); + MmCoreModuleHob->MemoryAllocationHeader.MemoryBaseAddress = Base; + MmCoreModuleHob->MemoryAllocationHeader.MemoryLength = Length; + MmCoreModuleHob->MemoryAllocationHeader.MemoryType = EfiReservedMemoryType; + ZeroMem (MmCoreModuleHob->MemoryAllocationHeader.Reserved, sizeof (MmCoreModuleHob->MemoryAllocationHeader.Reserved)); + + CopyGuid (&MmCoreModuleHob->ModuleName, ModuleName); + MmCoreModuleHob->EntryPoint = EntryPoint; + } + + *HobBufferSize = HobLength; +} + +/** + Get remaining size for building HOBs. + + @param[in] TotalHobSize Total size of foundation HOBs. + @param[in] UsedSize Required HOBs' size. + + @retval MAX remaining size for building HOBs +**/ +UINTN +GetRemainingHobSize ( + IN UINTN TotalHobSize, + IN UINTN UsedSize + ) +{ + if (TotalHobSize > UsedSize) { + return TotalHobSize - UsedSize; + } else { + return 0; + } +} + +/** + Create the MM foundation specific HOB list which StandaloneMm Core needed. + + This function build the MM foundation specific HOB list needed by StandaloneMm Core + based on the PEI HOB list. + + @param[in] FoundationHobList The foundation HOB list to be used for HOB creation. + @param[in, out] FoundationHobSize The foundation HOB size. + On return, the expected/used size. + @param[in] PlatformHobList Platform HOB list. + @param[in] PlatformHobSize Platform HOB size. + @param[in] MmFvBase Base of firmare volume which included MM core dirver. + @param[in] MmFvSize Size of firmare volume which included MM core dirver. + @param[in] MmCoreFileName File name of MM core dirver. + @param[in] MmCoreImageAddress Image address of MM core dirver. + @param[in] MmCoreImageSize Image size of MM core dirver. + @param[in] MmCoreEntryPoint Entry pinter of MM core dirver. + @param[in] Block Pointer of MMRAM descriptor block. + + @retval RETURN_BUFFER_TOO_SMALL The buffer is too small for HOB creation. + BufferSize is updated to indicate the expected buffer size. + When the input BufferSize is bigger than the expected buffer size, + the BufferSize value will be changed the used buffer size. + @retval RETURN_SUCCESS HOB List is created/updated successfully or the input Length is 0. + +**/ +RETURN_STATUS +CreateMmFoundationHobList ( + IN UINT8 *FoundationHobList, + IN OUT UINTN *FoundationHobSize, + IN UINT8 *PlatformHobList, + IN UINTN PlatformHobSize, + IN EFI_PHYSICAL_ADDRESS MmFvBase, + IN UINT64 MmFvSize, + IN EFI_GUID *MmCoreFileName, + IN EFI_PHYSICAL_ADDRESS MmCoreImageAddress, + IN UINT64 MmCoreImageSize, + IN EFI_PHYSICAL_ADDRESS MmCoreEntryPoint, + IN EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *Block + ) +{ + UINTN UsedSize; + RETURN_STATUS Status; + UINTN HobLength; + + ASSERT (FoundationHobSize != NULL); + + ASSERT ( + ((*FoundationHobSize != 0) && (FoundationHobList != NULL)) || + ((*FoundationHobSize == 0) && (FoundationHobList == NULL)) + ); + + UsedSize = 0; + + // + // Build communication buffer HOB in MM HOB list + // + HobLength = *FoundationHobSize; + MmIplCopyGuidHob (FoundationHobList + UsedSize, &HobLength, &gMmCommBufferHobGuid, FALSE); + UsedSize += HobLength; + + // + // Build MmCore module HOB in MM HOB list + // + HobLength = GetRemainingHobSize (*FoundationHobSize, UsedSize); + MmIplBuildMmCoreModuleHob ( + FoundationHobList + UsedSize, + &HobLength, + MmCoreFileName, + MmCoreImageAddress, + MmCoreImageSize, + MmCoreEntryPoint + ); + + UsedSize += HobLength; + + // + // BFV address for StandaloneMm Core + // + HobLength = GetRemainingHobSize (*FoundationHobSize, UsedSize); + MmIplBuildFvHob (FoundationHobList + UsedSize, &HobLength, MmFvBase, MmFvSize); + UsedSize += HobLength; + + if (*FoundationHobSize < UsedSize) { + Status = RETURN_BUFFER_TOO_SMALL; + } else { + Status = RETURN_SUCCESS; + } + + *FoundationHobSize = UsedSize; + return Status; +} diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c index d6406784b7..89dd05c1b7 100644 --- a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c @@ -208,6 +208,132 @@ LocateMmCoreFv ( return EFI_NOT_FOUND; } +/** + Create HOB list for Standalone MM core. + + @param[out] HobSize HOB size of fundation and platform HOB list. + @param[in] MmCommBuffer Pointer of MM communication buffer. + @param[in] MmFvBase Base of MM FV which included MM core driver. + @param[in] MmFvSize Size of MM FV which included MM core driver. + @param[in] MmCoreFileName File GUID of MM core driver. + @param[in] MmCoreImageAddress Address of MM core image. + @param[in] MmCoreImageSize Size of MM core image. + @param[in] MmCoreEntryPoint Entry point of MM core driver. + @param[in] Block Pointer of MMRAM descriptor block. + + @retval HobList If fundation and platform HOBs not existed, + it is pointed to PEI HOB List. If existed, + it is pointed to fundation and platform HOB list. +**/ +VOID * +CreatMmHobList ( + OUT UINTN *HobSize, + IN MM_COMM_BUFFER *MmCommBuffer, + IN EFI_PHYSICAL_ADDRESS MmFvBase, + IN UINT64 MmFvSize, + IN EFI_GUID *MmCoreFileName, + IN PHYSICAL_ADDRESS MmCoreImageAddress, + IN UINT64 MmCoreImageSize, + IN PHYSICAL_ADDRESS MmCoreEntryPoint, + IN EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *Block + ) +{ + EFI_STATUS Status; + VOID *HobList; + VOID *PlatformHobList; + UINTN PlatformHobSize; + UINTN BufferSize; + UINTN FoundationHobSize; + + // + // Get platform HOBs + // + PlatformHobSize = 0; + Status = CreateMmPlatformHob (NULL, &PlatformHobSize); + if (Status == RETURN_BUFFER_TOO_SMALL) { + ASSERT (PlatformHobSize != 0); + // + // Create platform HOBs for MM foundation to get MMIO HOB data. + // + PlatformHobList = AllocatePages (EFI_SIZE_TO_PAGES (PlatformHobSize)); + ASSERT (PlatformHobList != NULL); + if (PlatformHobList == NULL) { + DEBUG ((DEBUG_ERROR, "%a: Out of resource to create platform MM HOBs\n", __func__)); + CpuDeadLoop (); + } + + BufferSize = PlatformHobSize; + Status = CreateMmPlatformHob (PlatformHobList, &PlatformHobSize); + ASSERT_EFI_ERROR (Status); + ASSERT (BufferSize == PlatformHobSize); + } + + ASSERT_EFI_ERROR (Status); + + // + // Get size of foundation HOBs + // + FoundationHobSize = 0; + Status = CreateMmFoundationHobList ( + NULL, + &FoundationHobSize, + PlatformHobList, + PlatformHobSize, + MmFvBase, + MmFvSize, + MmCoreFileName, + MmCoreImageAddress, + MmCoreImageSize, + MmCoreEntryPoint, + Block + ); + FreePages (PlatformHobList, EFI_SIZE_TO_PAGES (PlatformHobSize)); + ASSERT (Status == RETURN_BUFFER_TOO_SMALL); + ASSERT (FoundationHobSize != 0); + + // + // Final result includes platform HOBs, foundation HOBs and a END node. + // + *HobSize = PlatformHobSize + FoundationHobSize + sizeof (EFI_HOB_GENERIC_HEADER); + HobList = AllocatePages (EFI_SIZE_TO_PAGES (*HobSize)); + ASSERT (HobList != NULL); + if (HobList == NULL) { + DEBUG ((DEBUG_ERROR, "Out of resource to create MM HOBs\n")); + CpuDeadLoop (); + } + + // + // Get platform HOBs + // + Status = CreateMmPlatformHob (HobList, &PlatformHobSize); + ASSERT_EFI_ERROR (Status); + + // + // Get foundation HOBs + // + Status = CreateMmFoundationHobList ( + (UINT8 *)HobList + PlatformHobSize, + &FoundationHobSize, + HobList, + PlatformHobSize, + MmFvBase, + MmFvSize, + MmCoreFileName, + MmCoreImageAddress, + MmCoreImageSize, + MmCoreEntryPoint, + Block + ); + ASSERT_EFI_ERROR (Status); + + // + // Create MM HOB list end. + // + MmIplCreateHob ((UINT8 *)HobList + PlatformHobSize + FoundationHobSize, EFI_HOB_TYPE_END_OF_HOB_LIST, sizeof (EFI_HOB_GENERIC_HEADER)); + + return HobList; +} + /** Find largest unallocated MMRAM in current MMRAM descriptor block @@ -360,6 +486,7 @@ ExecuteMmCoreFromMmram ( EFI_STATUS Status; UINTN PageCount; VOID *MmHobList; + UINTN MmHobSize; EFI_GUID MmCoreFileName; UINTN MmFvSize; EFI_PHYSICAL_ADDRESS MmFvBase; @@ -438,7 +565,18 @@ ExecuteMmCoreFromMmram ( // // Get HOB list for Standalone MM Core. // - MmHobList = GetHobList (); + MmHobSize = 0; + MmHobList = CreatMmHobList ( + &MmHobSize, + MmCommBuffer, + MmFvBase, + MmFvSize, + &MmCoreFileName, + ImageContext.ImageAddress, + ImageContext.ImageSize, + ImageContext.EntryPoint, + Block + ); // // Print debug message showing Standalone MM Core entry point address. @@ -451,6 +589,7 @@ ExecuteMmCoreFromMmram ( Entry = (STANDALONE_MM_FOUNDATION_ENTRY_POINT)(UINTN)ImageContext.EntryPoint; Status = Entry (MmHobList); ASSERT_EFI_ERROR (Status); + FreePages (MmHobList, EFI_SIZE_TO_PAGES (MmHobSize)); } } diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h index e9be3f5568..d99a64ec08 100644 --- a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h @@ -24,6 +24,7 @@ #include #include #include +#include /** Communicates with a registered handler. @@ -66,4 +67,63 @@ EndOfPeiCallback ( IN VOID *Ppi ); +/** + Add a new HOB to the HOB List. + + @param[in] Hob The pointer of new HOB buffer. + @param[in] HobType Type of the new HOB. + @param[in] HobLength Length of the new HOB to allocate. + + @return NULL if there is no space to create a hob. + @return The address point to the new created hob. + +**/ +VOID * +MmIplCreateHob ( + IN VOID *Hob, + IN UINT16 HobType, + IN UINT16 HobLength + ); + +/** + Create the MM foundation specific HOB list which StandaloneMm Core needed. + + This function build the MM foundation specific HOB list needed by StandaloneMm Core + based on the PEI HOB list. + + @param[in] FoundationHobList The foundation HOB list to be used for HOB creation. + @param[in, out] FoundationHobSize The foundation HOB size. + On return, the expected/used size. + @param[in] PlatformHobList Platform HOB list. + @param[in] PlatformHobSize Platform HOB size. + @param[in] MmFvBase Base of firmare volume which included MM core dirver. + @param[in] MmFvSize Size of firmare volume which included MM core dirver. + @param[in] MmCoreFileName File name of MM core dirver. + @param[in] MmCoreImageAddress Image address of MM core dirver. + @param[in] MmCoreImageSize Image size of MM core dirver. + @param[in] MmCoreEntryPoint Entry pinter of MM core dirver. + @param[in] Block Pointer of MMRAM descriptor block. + + @retval RETURN_BUFFER_TOO_SMALL The buffer is too small for HOB creation. + BufferSize is updated to indicate the expected buffer size. + When the input BufferSize is bigger than the expected buffer size, + the BufferSize value will be changed the used buffer size. + @retval RETURN_SUCCESS HOB List is created/updated successfully or the input Length is 0. + +**/ +RETURN_STATUS +CreateMmFoundationHobList ( + IN UINT8 *FoundationHobList, + IN OUT UINTN *FoundationHobSize, + IN UINT8 *PlatformHobList, + IN UINTN PlatformHobSize, + IN EFI_PHYSICAL_ADDRESS MmFvBase, + IN UINT64 MmFvSize, + IN EFI_GUID *MmCoreFileName, + IN EFI_PHYSICAL_ADDRESS MmCoreImageAddress, + IN UINT64 MmCoreImageSize, + IN EFI_PHYSICAL_ADDRESS MmCoreEntryPoint, + IN EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *Block + ); + #endif diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf index a873efb0df..94abe6eee7 100644 --- a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf @@ -25,6 +25,7 @@ [Sources] StandaloneMmIplPei.c StandaloneMmIplPei.h + MmFoundationHob.c [Packages] MdePkg/MdePkg.dec @@ -41,6 +42,7 @@ BaseMemoryLib PeCoffLib CacheMaintenanceLib + MmPlatformHobProducerLib [Guids] gMmCommBufferHobGuid