summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library')
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/FvLib/FvLib.c379
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/FvLib/FvLib.inf52
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/CreateHobList.c205
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c322
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c413
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf58
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/X64/StandaloneMmCoreEntryPoint.c71
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/AArch64/StandaloneMmCoreHobLib.c330
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/AArch64/StandaloneMmCoreHobLibInternal.c58
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/Common.c291
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/StandaloneMmCoreHobLib.inf47
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/X64/StandaloneMmCoreHobLib.c298
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationLib.c902
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationLib.inf44
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationServices.h32
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmHobLib/StandaloneMmHobLib.c643
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmHobLib/StandaloneMmHobLib.inf40
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/AArch64/StandaloneMmMemLibInternal.c70
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.c315
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.inf55
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/X86StandaloneMmMemLibInternal.c155
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemoryAllocationLib/StandaloneMmMemoryAllocationLib.c815
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemoryAllocationLib/StandaloneMmMemoryAllocationLib.inf37
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/AArch64/StandaloneMmPeCoffExtraActionLib.c211
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.inf36
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.c47
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.inf41
27 files changed, 5967 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/FvLib/FvLib.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/FvLib/FvLib.c
new file mode 100644
index 00000000..cf3beb1f
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/FvLib/FvLib.c
@@ -0,0 +1,379 @@
+/** @file
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/FvLib.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+
+#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
+ (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1))
+
+/**
+ Returns the highest bit set of the State field
+
+ @param ErasePolarity Erase Polarity as defined by EFI_FVB_ERASE_POLARITY
+ in the Attributes field.
+ @param FfsHeader Pointer to FFS File Header.
+
+ @return the highest bit in the State field
+**/
+EFI_FFS_FILE_STATE
+GetFileState (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ EFI_FFS_FILE_STATE FileState;
+ EFI_FFS_FILE_STATE HighestBit;
+
+ FileState = FfsHeader->State;
+
+ if (ErasePolarity != 0) {
+ FileState = (EFI_FFS_FILE_STATE)~FileState;
+ }
+
+ HighestBit = 0x80;
+ while (HighestBit != 0 && (HighestBit & FileState) == 0) {
+ HighestBit >>= 1;
+ }
+
+ return HighestBit;
+}
+
+/**
+ Calculates the checksum of the header of a file.
+
+ @param FileHeader Pointer to FFS File Header.
+
+ @return Checksum of the header.
+**/
+UINT8
+CalculateHeaderChecksum (
+ IN EFI_FFS_FILE_HEADER *FileHeader
+ )
+{
+ UINT8 *ptr;
+ UINTN Index;
+ UINT8 Sum;
+
+ Sum = 0;
+ ptr = (UINT8 *) FileHeader;
+
+ for (Index = 0; Index < sizeof (EFI_FFS_FILE_HEADER) - 3; Index += 4) {
+ Sum = (UINT8) (Sum + ptr[Index]);
+ Sum = (UINT8) (Sum + ptr[Index + 1]);
+ Sum = (UINT8) (Sum + ptr[Index + 2]);
+ Sum = (UINT8) (Sum + ptr[Index + 3]);
+ }
+
+ for (; Index < sizeof (EFI_FFS_FILE_HEADER); Index++) {
+ Sum = (UINT8) (Sum + ptr[Index]);
+ }
+ //
+ // State field (since this indicates the different state of file).
+ //
+ Sum = (UINT8) (Sum - FileHeader->State);
+ //
+ // Checksum field of the file is not part of the header checksum.
+ //
+ Sum = (UINT8) (Sum - FileHeader->IntegrityCheck.Checksum.File);
+
+ return Sum;
+}
+
+/**
+ Given the input file pointer, search for the next matching file in the
+ FFS volume as defined by SearchType. The search starts from FileHeader inside
+ the Firmware Volume defined by FwVolHeader.
+
+ @param SearchType Filter to find only files of this type.
+ Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
+ @param FwVolHeader Pointer to the FV header of the volume to search.
+ This parameter must point to a valid FFS volume.
+ @param FileHeader Pointer to the current file from which to begin searching.
+ This pointer will be updated upon return to reflect the file found.
+
+ @retval EFI_NOT_FOUND No files matching the search criteria were found
+ @retval EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+FfsFindNextFile (
+ IN EFI_FV_FILETYPE SearchType,
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader,
+ IN OUT EFI_FFS_FILE_HEADER **FileHeader
+ )
+{
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
+
+ EFI_FFS_FILE_HEADER *FfsFileHeader;
+ UINT32 FileLength;
+ UINT32 FileOccupiedSize;
+ UINT32 FileOffset;
+ UINT64 FvLength;
+ UINT8 ErasePolarity;
+ UINT8 FileState;
+
+ FvLength = FwVolHeader->FvLength;
+ if (FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
+ ErasePolarity = 1;
+ } else {
+ ErasePolarity = 0;
+ }
+ //
+ // If FileHeader is not specified (NULL) start with the first file in the
+ // firmware volume. Otherwise, start from the FileHeader.
+ //
+ if (*FileHeader == NULL) {
+
+ if (FwVolHeader->ExtHeaderOffset != 0) {
+
+ FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)FwVolHeader +
+ FwVolHeader->ExtHeaderOffset);
+
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FvExtHeader +
+ FvExtHeader->ExtHeaderSize);
+
+ } else {
+
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader +
+ FwVolHeader->HeaderLength);
+
+ }
+
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FwVolHeader +
+ ALIGN_VALUE((UINTN)FfsFileHeader -
+ (UINTN)FwVolHeader, 8));
+ } else {
+ //
+ // Length is 24 bits wide so mask upper 8 bits
+ // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned.
+ //
+ FileLength = FFS_FILE_SIZE(*FileHeader);
+ FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) *FileHeader + FileOccupiedSize);
+ }
+
+ FileOffset = (UINT32) ((UINT8 *) FfsFileHeader - (UINT8 *) FwVolHeader);
+
+ while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) {
+ //
+ // Get FileState which is the highest bit of the State
+ //
+ FileState = GetFileState (ErasePolarity, FfsFileHeader);
+
+ switch (FileState) {
+
+ case EFI_FILE_HEADER_INVALID:
+ FileOffset += sizeof (EFI_FFS_FILE_HEADER);
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));
+ break;
+
+ case EFI_FILE_DATA_VALID:
+ case EFI_FILE_MARKED_FOR_UPDATE:
+ if (CalculateHeaderChecksum (FfsFileHeader) == 0) {
+ FileLength = FFS_FILE_SIZE(FfsFileHeader);
+ FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
+
+ if ((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) {
+
+ *FileHeader = FfsFileHeader;
+
+ return EFI_SUCCESS;
+ }
+
+ FileOffset += FileOccupiedSize;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + FileOccupiedSize);
+ } else {
+ return EFI_NOT_FOUND;
+ }
+ break;
+
+ case EFI_FILE_DELETED:
+ FileLength = FFS_FILE_SIZE(FfsFileHeader);
+ FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
+ FileOffset += FileOccupiedSize;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + FileOccupiedSize);
+ break;
+
+ default:
+ return EFI_NOT_FOUND;
+
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Locates a section within a series of sections
+ with the specified section type.
+
+ @param[in] Sections The sections to search
+ @param[in] SizeOfSections Total size of all sections
+ @param[in] SectionType The section type to locate
+ @param[out] FoundSection The FFS section if found
+
+ @retval EFI_SUCCESS The file and section was found
+ @retval EFI_NOT_FOUND The file and section was not found
+ @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
+**/
+EFI_STATUS
+EFIAPI
+FindFfsSectionInSections (
+ IN VOID *Sections,
+ IN UINTN SizeOfSections,
+ IN EFI_SECTION_TYPE SectionType,
+ OUT EFI_COMMON_SECTION_HEADER **FoundSection
+ )
+{
+ EFI_PHYSICAL_ADDRESS CurrentAddress;
+ UINT32 Size;
+ EFI_PHYSICAL_ADDRESS EndOfSections;
+ EFI_COMMON_SECTION_HEADER *Section;
+ EFI_PHYSICAL_ADDRESS EndOfSection;
+
+ //
+ // Loop through the FFS file sections
+ //
+ EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) Sections;
+ EndOfSections = EndOfSection + SizeOfSections;
+ for (;;) {
+ if (EndOfSection == EndOfSections) {
+ break;
+ }
+ CurrentAddress = EndOfSection;
+
+ Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
+
+ Size = SECTION_SIZE (Section);
+ if (Size < sizeof (*Section)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ EndOfSection = CurrentAddress + Size;
+ if (EndOfSection > EndOfSections) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+ Size = GET_OCCUPIED_SIZE (Size, 4);
+
+ //
+ // Look for the requested section type
+ //
+ if (Section->Type == SectionType) {
+ *FoundSection = Section;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Given the input file pointer, search for the next matching section in the
+ FFS volume.
+
+ @param SearchType Filter to find only sections of this type.
+ @param FfsFileHeader Pointer to the current file to search.
+ @param SectionHeader Pointer to the Section matching SectionType in FfsFileHeader.
+ NULL if section not found
+
+ @retval EFI_NOT_FOUND No files matching the search criteria were found
+ @retval EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+FfsFindSection (
+ IN EFI_SECTION_TYPE SectionType,
+ IN EFI_FFS_FILE_HEADER *FfsFileHeader,
+ IN OUT EFI_COMMON_SECTION_HEADER **SectionHeader
+ )
+{
+ UINT32 FileSize;
+ EFI_COMMON_SECTION_HEADER *Section;
+ EFI_STATUS Status;
+
+ //
+ // Size is 24 bits wide so mask upper 8 bits.
+ // Does not include FfsFileHeader header size
+ // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.
+ //
+ Section = (EFI_COMMON_SECTION_HEADER *) (FfsFileHeader + 1);
+ FileSize = FFS_FILE_SIZE(FfsFileHeader);
+ FileSize -= sizeof (EFI_FFS_FILE_HEADER);
+
+ Status = FindFfsSectionInSections (
+ Section,
+ FileSize,
+ SectionType,
+ SectionHeader
+ );
+ return Status;
+}
+
+/**
+ Given the input file pointer, search for the next matching section in the
+ FFS volume.
+
+ @param SearchType Filter to find only sections of this type.
+ @param FfsFileHeader Pointer to the current file to search.
+ @param SectionData Pointer to the Section matching SectionType in FfsFileHeader.
+ NULL if section not found
+ @param SectionDataSize The size of SectionData
+
+ @retval EFI_NOT_FOUND No files matching the search criteria were found
+ @retval EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+FfsFindSectionData (
+ IN EFI_SECTION_TYPE SectionType,
+ IN EFI_FFS_FILE_HEADER *FfsFileHeader,
+ IN OUT VOID **SectionData,
+ IN OUT UINTN *SectionDataSize
+ )
+{
+ UINT32 FileSize;
+ EFI_COMMON_SECTION_HEADER *Section;
+ UINT32 SectionLength;
+ UINT32 ParsedLength;
+
+ //
+ // Size is 24 bits wide so mask upper 8 bits.
+ // Does not include FfsFileHeader header size
+ // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.
+ //
+ Section = (EFI_COMMON_SECTION_HEADER *) (FfsFileHeader + 1);
+ FileSize = FFS_FILE_SIZE(FfsFileHeader);
+ FileSize -= sizeof (EFI_FFS_FILE_HEADER);
+
+ *SectionData = NULL;
+ ParsedLength = 0;
+ while (ParsedLength < FileSize) {
+ if (Section->Type == SectionType) {
+ *SectionData = (VOID *) (Section + 1);
+ *SectionDataSize = SECTION_SIZE(Section);
+ return EFI_SUCCESS;
+ }
+ //
+ // Size is 24 bits wide so mask upper 8 bits.
+ // SectionLength is adjusted it is 4 byte aligned.
+ // Go to the next section
+ //
+ SectionLength = SECTION_SIZE(Section);
+ SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
+
+ ParsedLength += SectionLength;
+ Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + SectionLength);
+ }
+
+ return EFI_NOT_FOUND;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/FvLib/FvLib.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/FvLib/FvLib.inf
new file mode 100644
index 00000000..22f71abd
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/FvLib/FvLib.inf
@@ -0,0 +1,52 @@
+## @file
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ INF_VERSION = 0x0001001A
+ BASE_NAME = FvLib
+ FILE_GUID = C20085E9-E3AB-4938-A727-C10935FEEE2B
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = FvLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32
+#
+
+################################################################################
+#
+# Sources Section - list of files that are required for the build to succeed.
+#
+################################################################################
+
+[Sources]
+ FvLib.c
+
+################################################################################
+#
+# Package Dependency Section - list of Package files that are required for
+# this module.
+#
+################################################################################
+
+[Packages]
+ MdePkg/MdePkg.dec
+ StandaloneMmPkg/StandaloneMmPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/CreateHobList.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/CreateHobList.c
new file mode 100644
index 00000000..dd2db78a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/CreateHobList.c
@@ -0,0 +1,205 @@
+/** @file
+ Creates HOB during Standalone MM Foundation entry point
+ on ARM platforms.
+
+Copyright (c) 2017 - 2021, Arm Ltd. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <PiMm.h>
+
+#include <PiPei.h>
+#include <Guid/MmramMemoryReserve.h>
+#include <Guid/MpInformation.h>
+
+#include <Library/AArch64/StandaloneMmCoreEntryPoint.h>
+#include <Library/ArmMmuLib.h>
+#include <Library/ArmSvcLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/SerialPortLib.h>
+
+#include <IndustryStandard/ArmStdSmc.h>
+
+extern EFI_HOB_HANDOFF_INFO_TABLE*
+HobConstructor (
+ IN VOID *EfiMemoryBegin,
+ IN UINTN EfiMemoryLength,
+ IN VOID *EfiFreeMemoryBottom,
+ IN VOID *EfiFreeMemoryTop
+ );
+
+// GUID to identify HOB with whereabouts of communication buffer with Normal
+// World
+extern EFI_GUID gEfiStandaloneMmNonSecureBufferGuid;
+
+// GUID to identify HOB where the entry point of the CPU driver will be
+// populated to allow this entry point driver to invoke it upon receipt of an
+// event
+extern EFI_GUID gEfiArmTfCpuDriverEpDescriptorGuid;
+
+/**
+ Use the boot information passed by privileged firmware to populate a HOB list
+ suitable for consumption by the MM Core and drivers.
+
+ @param [in, out] CpuDriverEntryPoint Address of MM CPU driver entrypoint
+ @param [in] PayloadBootInfo Boot information passed by privileged
+ firmware
+
+**/
+VOID *
+CreateHobListFromBootInfo (
+ IN OUT PI_MM_ARM_TF_CPU_DRIVER_ENTRYPOINT *CpuDriverEntryPoint,
+ IN EFI_SECURE_PARTITION_BOOT_INFO *PayloadBootInfo
+)
+{
+ EFI_HOB_HANDOFF_INFO_TABLE *HobStart;
+ EFI_RESOURCE_ATTRIBUTE_TYPE Attributes;
+ UINT32 Index;
+ UINT32 BufferSize;
+ UINT32 Flags;
+ EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *MmramRangesHob;
+ EFI_MMRAM_DESCRIPTOR *MmramRanges;
+ EFI_MMRAM_DESCRIPTOR *NsCommBufMmramRange;
+ MP_INFORMATION_HOB_DATA *MpInformationHobData;
+ EFI_PROCESSOR_INFORMATION *ProcInfoBuffer;
+ EFI_SECURE_PARTITION_CPU_INFO *CpuInfo;
+ ARM_TF_CPU_DRIVER_EP_DESCRIPTOR *CpuDriverEntryPointDesc;
+
+ // Create a hoblist with a PHIT and EOH
+ HobStart = HobConstructor (
+ (VOID *) PayloadBootInfo->SpMemBase,
+ (UINTN) PayloadBootInfo->SpMemLimit - PayloadBootInfo->SpMemBase,
+ (VOID *) PayloadBootInfo->SpHeapBase,
+ (VOID *) (PayloadBootInfo->SpHeapBase + PayloadBootInfo->SpHeapSize)
+ );
+
+ // Check that the Hoblist starts at the bottom of the Heap
+ ASSERT (HobStart == (VOID *) PayloadBootInfo->SpHeapBase);
+
+ // Build a Boot Firmware Volume HOB
+ BuildFvHob (PayloadBootInfo->SpImageBase, PayloadBootInfo->SpImageSize);
+
+ // Build a resource descriptor Hob that describes the available physical
+ // memory range
+ Attributes = (
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_TESTED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
+ );
+
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ Attributes,
+ (UINTN) PayloadBootInfo->SpMemBase,
+ PayloadBootInfo->SpMemLimit - PayloadBootInfo->SpMemBase
+ );
+
+ // Find the size of the GUIDed HOB with MP information
+ BufferSize = sizeof (MP_INFORMATION_HOB_DATA);
+ BufferSize += sizeof (EFI_PROCESSOR_INFORMATION) * PayloadBootInfo->NumCpus;
+
+ // Create a Guided MP information HOB to enable the ARM TF CPU driver to
+ // perform per-cpu allocations.
+ MpInformationHobData = BuildGuidHob (&gMpInformationHobGuid, BufferSize);
+
+ // Populate the MP information HOB with the topology information passed by
+ // privileged firmware
+ MpInformationHobData->NumberOfProcessors = PayloadBootInfo->NumCpus;
+ MpInformationHobData->NumberOfEnabledProcessors = PayloadBootInfo->NumCpus;
+ ProcInfoBuffer = MpInformationHobData->ProcessorInfoBuffer;
+ CpuInfo = PayloadBootInfo->CpuInfo;
+
+ for (Index = 0; Index < PayloadBootInfo->NumCpus; Index++) {
+ ProcInfoBuffer[Index].ProcessorId = CpuInfo[Index].Mpidr;
+ ProcInfoBuffer[Index].Location.Package = GET_CLUSTER_ID(CpuInfo[Index].Mpidr);
+ ProcInfoBuffer[Index].Location.Core = GET_CORE_ID(CpuInfo[Index].Mpidr);
+ ProcInfoBuffer[Index].Location.Thread = GET_CORE_ID(CpuInfo[Index].Mpidr);
+
+ Flags = PROCESSOR_ENABLED_BIT | PROCESSOR_HEALTH_STATUS_BIT;
+ if (CpuInfo[Index].Flags & CPU_INFO_FLAG_PRIMARY_CPU) {
+ Flags |= PROCESSOR_AS_BSP_BIT;
+ }
+ ProcInfoBuffer[Index].StatusFlag = Flags;
+ }
+
+ // Create a Guided HOB to tell the ARM TF CPU driver the location and length
+ // of the communication buffer shared with the Normal world.
+ NsCommBufMmramRange = (EFI_MMRAM_DESCRIPTOR *) BuildGuidHob (
+ &gEfiStandaloneMmNonSecureBufferGuid,
+ sizeof (EFI_MMRAM_DESCRIPTOR)
+ );
+ NsCommBufMmramRange->PhysicalStart = PayloadBootInfo->SpNsCommBufBase;
+ NsCommBufMmramRange->CpuStart = PayloadBootInfo->SpNsCommBufBase;
+ NsCommBufMmramRange->PhysicalSize = PayloadBootInfo->SpNsCommBufSize;
+ NsCommBufMmramRange->RegionState = EFI_CACHEABLE | EFI_ALLOCATED;
+
+ // Create a Guided HOB to enable the ARM TF CPU driver to share its entry
+ // point and populate it with the address of the shared buffer
+ CpuDriverEntryPointDesc = (ARM_TF_CPU_DRIVER_EP_DESCRIPTOR *) BuildGuidHob (
+ &gEfiArmTfCpuDriverEpDescriptorGuid,
+ sizeof (ARM_TF_CPU_DRIVER_EP_DESCRIPTOR)
+ );
+
+ *CpuDriverEntryPoint = NULL;
+ CpuDriverEntryPointDesc->ArmTfCpuDriverEpPtr = CpuDriverEntryPoint;
+
+ // Find the size of the GUIDed HOB with SRAM ranges
+ BufferSize = sizeof (EFI_MMRAM_HOB_DESCRIPTOR_BLOCK);
+ BufferSize += PayloadBootInfo->NumSpMemRegions * sizeof (EFI_MMRAM_DESCRIPTOR);
+
+ // Create a GUIDed HOB with SRAM ranges
+ MmramRangesHob = BuildGuidHob (&gEfiMmPeiMmramMemoryReserveGuid, BufferSize);
+
+ // Fill up the number of MMRAM memory regions
+ MmramRangesHob->NumberOfMmReservedRegions = PayloadBootInfo->NumSpMemRegions;
+ // Fill up the MMRAM ranges
+ MmramRanges = &MmramRangesHob->Descriptor[0];
+
+ // Base and size of memory occupied by the Standalone MM image
+ MmramRanges[0].PhysicalStart = PayloadBootInfo->SpImageBase;
+ MmramRanges[0].CpuStart = PayloadBootInfo->SpImageBase;
+ MmramRanges[0].PhysicalSize = PayloadBootInfo->SpImageSize;
+ MmramRanges[0].RegionState = EFI_CACHEABLE | EFI_ALLOCATED;
+
+ // Base and size of buffer shared with privileged Secure world software
+ MmramRanges[1].PhysicalStart = PayloadBootInfo->SpSharedBufBase;
+ MmramRanges[1].CpuStart = PayloadBootInfo->SpSharedBufBase;
+ MmramRanges[1].PhysicalSize = PayloadBootInfo->SpPcpuSharedBufSize * PayloadBootInfo->NumCpus;
+ MmramRanges[1].RegionState = EFI_CACHEABLE | EFI_ALLOCATED;
+
+ // Base and size of buffer used for synchronous communication with Normal
+ // world software
+ MmramRanges[2].PhysicalStart = PayloadBootInfo->SpNsCommBufBase;
+ MmramRanges[2].CpuStart = PayloadBootInfo->SpNsCommBufBase;
+ MmramRanges[2].PhysicalSize = PayloadBootInfo->SpNsCommBufSize;
+ MmramRanges[2].RegionState = EFI_CACHEABLE | EFI_ALLOCATED;
+
+ // Base and size of memory allocated for stacks for all cpus
+ MmramRanges[3].PhysicalStart = PayloadBootInfo->SpStackBase;
+ MmramRanges[3].CpuStart = PayloadBootInfo->SpStackBase;
+ MmramRanges[3].PhysicalSize = PayloadBootInfo->SpPcpuStackSize * PayloadBootInfo->NumCpus;
+ MmramRanges[3].RegionState = EFI_CACHEABLE | EFI_ALLOCATED;
+
+ // Base and size of heap memory shared by all cpus
+ MmramRanges[4].PhysicalStart = (EFI_PHYSICAL_ADDRESS) HobStart;
+ MmramRanges[4].CpuStart = (EFI_PHYSICAL_ADDRESS) HobStart;
+ MmramRanges[4].PhysicalSize = HobStart->EfiFreeMemoryBottom - (EFI_PHYSICAL_ADDRESS) HobStart;
+ MmramRanges[4].RegionState = EFI_CACHEABLE | EFI_ALLOCATED;
+
+ // Base and size of heap memory shared by all cpus
+ MmramRanges[5].PhysicalStart = HobStart->EfiFreeMemoryBottom;
+ MmramRanges[5].CpuStart = HobStart->EfiFreeMemoryBottom;
+ MmramRanges[5].PhysicalSize = HobStart->EfiFreeMemoryTop - HobStart->EfiFreeMemoryBottom;
+ MmramRanges[5].RegionState = EFI_CACHEABLE;
+
+ return HobStart;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c
new file mode 100644
index 00000000..f0db0eb5
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c
@@ -0,0 +1,322 @@
+/** @file
+ Locate, get and update PE/COFF permissions during Standalone MM
+ Foundation Entry point on ARM platforms.
+
+Copyright (c) 2017 - 2021, Arm Ltd. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <PiMm.h>
+
+#include <PiPei.h>
+#include <Guid/MmramMemoryReserve.h>
+#include <Guid/MpInformation.h>
+
+#include <Library/AArch64/StandaloneMmCoreEntryPoint.h>
+#include <Library/ArmMmuLib.h>
+#include <Library/ArmSvcLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/SerialPortLib.h>
+
+#include <IndustryStandard/ArmStdSmc.h>
+
+/**
+ Privileged firmware assigns RO & Executable attributes to all memory occupied
+ by the Boot Firmware Volume. This function sets the correct permissions of
+ sections in the Standalone MM Core module to be able to access RO and RW data
+ and make further progress in the boot process.
+
+ @param [in] ImageContext Pointer to PE/COFF image context
+ @param [in] ImageBase Base of image in memory
+ @param [in] SectionHeaderOffset Offset of PE/COFF image section header
+ @param [in] NumberOfSections Number of Sections
+ @param [in] TextUpdater Function to change code permissions
+ @param [in] ReadOnlyUpdater Function to change RO permissions
+ @param [in] ReadWriteUpdater Function to change RW permissions
+
+**/
+EFI_STATUS
+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,
+ IN REGION_PERMISSION_UPDATE_FUNC ReadOnlyUpdater,
+ IN REGION_PERMISSION_UPDATE_FUNC ReadWriteUpdater
+ )
+{
+ EFI_IMAGE_SECTION_HEADER SectionHeader;
+ RETURN_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Base;
+ UINTN Size;
+ UINTN ReadSize;
+ UINTN Index;
+
+ ASSERT (ImageContext != NULL);
+
+ //
+ // Iterate over the sections
+ //
+ for (Index = 0; Index < NumberOfSections; Index++) {
+ //
+ // Read section header from file
+ //
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);
+ ReadSize = Size;
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ SectionHeaderOffset,
+ &Size,
+ &SectionHeader
+ );
+
+ if (RETURN_ERROR (Status) || (Size != ReadSize)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: ImageContext->ImageRead () failed (Status = %r)\n",
+ __FUNCTION__, Status));
+ return Status;
+ }
+
+ DEBUG ((DEBUG_INFO,
+ "%a: Section %d of image at 0x%lx has 0x%x permissions\n",
+ __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.Characteristics));
+ DEBUG ((DEBUG_INFO,
+ "%a: Section %d of image at 0x%lx has %a name\n",
+ __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.Name));
+ DEBUG ((DEBUG_INFO,
+ "%a: Section %d of image at 0x%lx has 0x%x address\n",
+ __FUNCTION__, Index, ImageContext->ImageAddress,
+ ImageContext->ImageAddress + SectionHeader.VirtualAddress));
+ DEBUG ((DEBUG_INFO,
+ "%a: Section %d of image at 0x%lx has 0x%x data\n",
+ __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.PointerToRawData));
+
+ //
+ // If the section is marked as XN then remove the X attribute. Furthermore,
+ // if it is a writeable section then mark it appropriately as well.
+ //
+ if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) {
+ Base = ImageBase + SectionHeader.VirtualAddress;
+
+ TextUpdater (Base, SectionHeader.Misc.VirtualSize);
+
+ if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_WRITE) != 0) {
+ ReadWriteUpdater (Base, SectionHeader.Misc.VirtualSize);
+ DEBUG ((DEBUG_INFO,
+ "%a: Mapping section %d of image at 0x%lx with RW-XN permissions\n",
+ __FUNCTION__, Index, ImageContext->ImageAddress));
+ } else {
+ DEBUG ((DEBUG_INFO,
+ "%a: Mapping section %d of image at 0x%lx with RO-XN permissions\n",
+ __FUNCTION__, Index, ImageContext->ImageAddress));
+ }
+ } else {
+ DEBUG ((DEBUG_INFO,
+ "%a: Ignoring section %d of image at 0x%lx with 0x%x permissions\n",
+ __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.Characteristics));
+ }
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Privileged firmware assigns RO & Executable attributes to all memory occupied
+ by the Boot Firmware Volume. This function locates the Standalone MM Core
+ module PE/COFF image in the BFV and returns this information.
+
+ @param [in] BfvAddress Base Address of Boot Firmware Volume
+ @param [in, out] TeData Pointer to address for allocating memory
+ for PE/COFF image data
+ @param [in, out] TeDataSize Pointer to size of PE/COFF image data
+
+**/
+EFI_STATUS
+EFIAPI
+LocateStandaloneMmCorePeCoffData (
+ IN EFI_FIRMWARE_VOLUME_HEADER *BfvAddress,
+ IN OUT VOID **TeData,
+ IN OUT UINTN *TeDataSize
+ )
+{
+ EFI_FFS_FILE_HEADER *FileHeader;
+ EFI_STATUS Status;
+
+ FileHeader = NULL;
+ Status = FfsFindNextFile (
+ EFI_FV_FILETYPE_SECURITY_CORE,
+ BfvAddress,
+ &FileHeader
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM FFS file - 0x%x\n",
+ Status));
+ return Status;
+ }
+
+ Status = FfsFindSectionData (EFI_SECTION_PE32, FileHeader, TeData, TeDataSize);
+ if (EFI_ERROR (Status)) {
+ Status = FfsFindSectionData (EFI_SECTION_TE, FileHeader, TeData, TeDataSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM Section data - %r\n",
+ Status));
+ return Status;
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", *TeData));
+ return Status;
+}
+
+/**
+ Returns the PC COFF section information.
+
+ @param [in, out] ImageContext Pointer to PE/COFF image context
+ @param [out] ImageBase Base of image in memory
+ @param [out] SectionHeaderOffset Offset of PE/COFF image section header
+ @param [out] NumberOfSections Number of Sections
+
+**/
+STATIC
+EFI_STATUS
+GetPeCoffSectionInformation (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
+ OUT EFI_PHYSICAL_ADDRESS *ImageBase,
+ OUT UINT32 *SectionHeaderOffset,
+ OUT UINT16 *NumberOfSections
+ )
+{
+ RETURN_STATUS Status;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
+ UINTN Size;
+ UINTN ReadSize;
+
+ ASSERT (ImageContext != NULL);
+ ASSERT (SectionHeaderOffset != NULL);
+ ASSERT (NumberOfSections != NULL);
+
+ Status = PeCoffLoaderGetImageInfo (ImageContext);
+ if (RETURN_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: PeCoffLoaderGetImageInfo () failed (Status == %r)\n",
+ __FUNCTION__, Status));
+ return Status;
+ }
+
+ if (ImageContext->SectionAlignment < EFI_PAGE_SIZE) {
+ //
+ // The sections need to be at least 4 KB aligned, since that is the
+ // granularity at which we can tighten permissions.
+ //
+ if (!ImageContext->IsTeImage) {
+ DEBUG ((DEBUG_WARN,
+ "%a: non-TE Image at 0x%lx has SectionAlignment < 4 KB (%lu)\n",
+ __FUNCTION__, ImageContext->ImageAddress, ImageContext->SectionAlignment));
+ return RETURN_UNSUPPORTED;
+ }
+ ImageContext->SectionAlignment = EFI_PAGE_SIZE;
+ }
+
+ //
+ // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
+ // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
+ // determines if this is a PE32 or PE32+ image. The magic is in the same
+ // location in both images.
+ //
+ Hdr.Union = &HdrData;
+ Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
+ ReadSize = Size;
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ ImageContext->PeCoffHeaderOffset,
+ &Size,
+ Hdr.Pe32
+ );
+
+ if (RETURN_ERROR (Status) || (Size != ReadSize)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: TmpContext->ImageRead () failed (Status = %r)\n",
+ __FUNCTION__, Status));
+ return Status;
+ }
+
+ *ImageBase = ImageContext->ImageAddress;
+ if (!ImageContext->IsTeImage) {
+ ASSERT (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE);
+
+ *SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER);
+ *NumberOfSections = Hdr.Pe32->FileHeader.NumberOfSections;
+
+ switch (Hdr.Pe32->OptionalHeader.Magic) {
+ case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC:
+ *SectionHeaderOffset += Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
+ break;
+ case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC:
+ *SectionHeaderOffset += Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader;
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+ } else {
+ *SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));
+ *NumberOfSections = Hdr.Te->NumberOfSections;
+ *ImageBase -= (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
+ }
+ return RETURN_SUCCESS;
+}
+
+/**
+ Privileged firmware assigns RO & Executable attributes to all memory occupied
+ by the Boot Firmware Volume. This function locates the section information of
+ the Standalone MM Core module to be able to change permissions of the
+ individual sections later in the boot process.
+
+ @param [in] TeData Pointer to PE/COFF image data
+ @param [in, out] ImageContext Pointer to PE/COFF image context
+ @param [out] ImageBase Pointer to ImageBase variable
+ @param [in, out] SectionHeaderOffset Offset of PE/COFF image section header
+ @param [in, out] NumberOfSections Number of Sections
+
+**/
+EFI_STATUS
+EFIAPI
+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
+ )
+{
+ EFI_STATUS Status;
+
+ // Initialize the Image Context
+ ZeroMem (ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
+ ImageContext->Handle = TeData;
+ ImageContext->ImageRead = PeCoffLoaderImageReadFromMemory;
+
+ DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", TeData));
+
+ 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;
+ }
+
+ DEBUG ((DEBUG_INFO, "Standalone MM Core PE-COFF SectionHeaderOffset - 0x%x, NumberOfSections - %d\n",
+ *SectionHeaderOffset, *NumberOfSections));
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c
new file mode 100644
index 00000000..5f4e0f74
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c
@@ -0,0 +1,413 @@
+/** @file
+ Entry point to the Standalone MM Foundation when initialized during the SEC
+ phase on ARM platforms
+
+Copyright (c) 2017 - 2021, Arm Ltd. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <PiMm.h>
+
+#include <Library/AArch64/StandaloneMmCoreEntryPoint.h>
+
+#include <PiPei.h>
+#include <Guid/MmramMemoryReserve.h>
+#include <Guid/MpInformation.h>
+
+#include <Library/ArmMmuLib.h>
+#include <Library/ArmSvcLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/SerialPortLib.h>
+#include <Library/PcdLib.h>
+
+#include <IndustryStandard/ArmStdSmc.h>
+#include <IndustryStandard/ArmMmSvc.h>
+#include <IndustryStandard/ArmFfaSvc.h>
+
+#define SPM_MAJOR_VER_MASK 0xFFFF0000
+#define SPM_MINOR_VER_MASK 0x0000FFFF
+#define SPM_MAJOR_VER_SHIFT 16
+#define FFA_NOT_SUPPORTED -1
+
+STATIC CONST UINT32 mSpmMajorVer = SPM_MAJOR_VERSION;
+STATIC CONST UINT32 mSpmMinorVer = SPM_MINOR_VERSION;
+
+STATIC CONST UINT32 mSpmMajorVerFfa = SPM_MAJOR_VERSION_FFA;
+STATIC CONST UINT32 mSpmMinorVerFfa = SPM_MINOR_VERSION_FFA;
+
+#define BOOT_PAYLOAD_VERSION 1
+
+PI_MM_ARM_TF_CPU_DRIVER_ENTRYPOINT CpuDriverEntryPoint = NULL;
+
+/**
+ Retrieve a pointer to and print the boot information passed by privileged
+ secure firmware.
+
+ @param [in] SharedBufAddress The pointer memory shared with privileged
+ firmware.
+
+**/
+EFI_SECURE_PARTITION_BOOT_INFO *
+GetAndPrintBootinformation (
+ IN VOID *SharedBufAddress
+)
+{
+ EFI_SECURE_PARTITION_BOOT_INFO *PayloadBootInfo;
+ EFI_SECURE_PARTITION_CPU_INFO *PayloadCpuInfo;
+ UINTN Index;
+
+ PayloadBootInfo = (EFI_SECURE_PARTITION_BOOT_INFO *) SharedBufAddress;
+
+ if (PayloadBootInfo == NULL) {
+ DEBUG ((DEBUG_ERROR, "PayloadBootInfo NULL\n"));
+ return NULL;
+ }
+
+ if (PayloadBootInfo->Header.Version != BOOT_PAYLOAD_VERSION) {
+ DEBUG ((DEBUG_ERROR, "Boot Information Version Mismatch. Current=0x%x, Expected=0x%x.\n",
+ PayloadBootInfo->Header.Version, BOOT_PAYLOAD_VERSION));
+ return NULL;
+ }
+
+ DEBUG ((DEBUG_INFO, "NumSpMemRegions - 0x%x\n", PayloadBootInfo->NumSpMemRegions));
+ DEBUG ((DEBUG_INFO, "SpMemBase - 0x%lx\n", PayloadBootInfo->SpMemBase));
+ DEBUG ((DEBUG_INFO, "SpMemLimit - 0x%lx\n", PayloadBootInfo->SpMemLimit));
+ DEBUG ((DEBUG_INFO, "SpImageBase - 0x%lx\n", PayloadBootInfo->SpImageBase));
+ DEBUG ((DEBUG_INFO, "SpStackBase - 0x%lx\n", PayloadBootInfo->SpStackBase));
+ DEBUG ((DEBUG_INFO, "SpHeapBase - 0x%lx\n", PayloadBootInfo->SpHeapBase));
+ DEBUG ((DEBUG_INFO, "SpNsCommBufBase - 0x%lx\n", PayloadBootInfo->SpNsCommBufBase));
+ DEBUG ((DEBUG_INFO, "SpSharedBufBase - 0x%lx\n", PayloadBootInfo->SpSharedBufBase));
+
+ DEBUG ((DEBUG_INFO, "SpImageSize - 0x%x\n", PayloadBootInfo->SpImageSize));
+ DEBUG ((DEBUG_INFO, "SpPcpuStackSize - 0x%x\n", PayloadBootInfo->SpPcpuStackSize));
+ DEBUG ((DEBUG_INFO, "SpHeapSize - 0x%x\n", PayloadBootInfo->SpHeapSize));
+ DEBUG ((DEBUG_INFO, "SpNsCommBufSize - 0x%x\n", PayloadBootInfo->SpNsCommBufSize));
+ DEBUG ((DEBUG_INFO, "SpPcpuSharedBufSize - 0x%x\n", PayloadBootInfo->SpPcpuSharedBufSize));
+
+ DEBUG ((DEBUG_INFO, "NumCpus - 0x%x\n", PayloadBootInfo->NumCpus));
+ DEBUG ((DEBUG_INFO, "CpuInfo - 0x%p\n", PayloadBootInfo->CpuInfo));
+
+ PayloadCpuInfo = (EFI_SECURE_PARTITION_CPU_INFO *) PayloadBootInfo->CpuInfo;
+
+ if (PayloadCpuInfo == NULL) {
+ DEBUG ((DEBUG_ERROR, "PayloadCpuInfo NULL\n"));
+ return NULL;
+ }
+
+ for (Index = 0; Index < PayloadBootInfo->NumCpus; Index++) {
+ DEBUG ((DEBUG_INFO, "Mpidr - 0x%lx\n", PayloadCpuInfo[Index].Mpidr));
+ DEBUG ((DEBUG_INFO, "LinearId - 0x%x\n", PayloadCpuInfo[Index].LinearId));
+ DEBUG ((DEBUG_INFO, "Flags - 0x%x\n", PayloadCpuInfo[Index].Flags));
+ }
+
+ return PayloadBootInfo;
+}
+
+/**
+ A loop to delegated events.
+
+ @param [in] EventCompleteSvcArgs Pointer to the event completion arguments.
+
+**/
+VOID
+EFIAPI
+DelegatedEventLoop (
+ IN ARM_SVC_ARGS *EventCompleteSvcArgs
+ )
+{
+ BOOLEAN FfaEnabled;
+ EFI_STATUS Status;
+ UINTN SvcStatus;
+
+ while (TRUE) {
+ ArmCallSvc (EventCompleteSvcArgs);
+
+ DEBUG ((DEBUG_INFO, "Received delegated event\n"));
+ DEBUG ((DEBUG_INFO, "X0 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg0));
+ DEBUG ((DEBUG_INFO, "X1 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg1));
+ DEBUG ((DEBUG_INFO, "X2 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg2));
+ DEBUG ((DEBUG_INFO, "X3 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg3));
+ DEBUG ((DEBUG_INFO, "X4 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg4));
+ DEBUG ((DEBUG_INFO, "X5 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg5));
+ DEBUG ((DEBUG_INFO, "X6 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg6));
+ DEBUG ((DEBUG_INFO, "X7 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg7));
+
+ FfaEnabled = FeaturePcdGet (PcdFfaEnable);
+ if (FfaEnabled) {
+ Status = CpuDriverEntryPoint (
+ EventCompleteSvcArgs->Arg0,
+ EventCompleteSvcArgs->Arg6,
+ EventCompleteSvcArgs->Arg3
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed delegated event 0x%x, Status 0x%x\n",
+ EventCompleteSvcArgs->Arg3, Status));
+ }
+ } else {
+ Status = CpuDriverEntryPoint (
+ EventCompleteSvcArgs->Arg0,
+ EventCompleteSvcArgs->Arg3,
+ EventCompleteSvcArgs->Arg1
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed delegated event 0x%x, Status 0x%x\n",
+ EventCompleteSvcArgs->Arg0, Status));
+ }
+ }
+
+ switch (Status) {
+ case EFI_SUCCESS:
+ SvcStatus = ARM_SVC_SPM_RET_SUCCESS;
+ break;
+ case EFI_INVALID_PARAMETER:
+ SvcStatus = ARM_SVC_SPM_RET_INVALID_PARAMS;
+ break;
+ case EFI_ACCESS_DENIED:
+ SvcStatus = ARM_SVC_SPM_RET_DENIED;
+ break;
+ case EFI_OUT_OF_RESOURCES:
+ SvcStatus = ARM_SVC_SPM_RET_NO_MEMORY;
+ break;
+ case EFI_UNSUPPORTED:
+ SvcStatus = ARM_SVC_SPM_RET_NOT_SUPPORTED;
+ break;
+ default:
+ SvcStatus = ARM_SVC_SPM_RET_NOT_SUPPORTED;
+ break;
+ }
+
+ if (FfaEnabled) {
+ EventCompleteSvcArgs->Arg0 = ARM_SVC_ID_FFA_MSG_SEND_DIRECT_RESP_AARCH64;
+ EventCompleteSvcArgs->Arg1 = 0;
+ EventCompleteSvcArgs->Arg2 = 0;
+ EventCompleteSvcArgs->Arg3 = ARM_SVC_ID_SP_EVENT_COMPLETE_AARCH64;
+ EventCompleteSvcArgs->Arg4 = SvcStatus;
+ } else {
+ EventCompleteSvcArgs->Arg0 = ARM_SVC_ID_SP_EVENT_COMPLETE_AARCH64;
+ EventCompleteSvcArgs->Arg1 = SvcStatus;
+ }
+ }
+}
+
+/**
+ Query the SPM version, check compatibility and return success if compatible.
+
+ @retval EFI_SUCCESS SPM versions compatible.
+ @retval EFI_UNSUPPORTED SPM versions not compatible.
+**/
+STATIC
+EFI_STATUS
+GetSpmVersion (VOID)
+{
+ EFI_STATUS Status;
+ UINT16 CalleeSpmMajorVer;
+ UINT16 CallerSpmMajorVer;
+ UINT16 CalleeSpmMinorVer;
+ UINT16 CallerSpmMinorVer;
+ UINT32 SpmVersion;
+ ARM_SVC_ARGS SpmVersionArgs;
+
+ if (FeaturePcdGet (PcdFfaEnable)) {
+ SpmVersionArgs.Arg0 = ARM_SVC_ID_FFA_VERSION_AARCH32;
+ SpmVersionArgs.Arg1 = mSpmMajorVerFfa << SPM_MAJOR_VER_SHIFT;
+ SpmVersionArgs.Arg1 |= mSpmMinorVerFfa;
+ CallerSpmMajorVer = mSpmMajorVerFfa;
+ CallerSpmMinorVer = mSpmMinorVerFfa;
+ } else {
+ SpmVersionArgs.Arg0 = ARM_SVC_ID_SPM_VERSION_AARCH32;
+ CallerSpmMajorVer = mSpmMajorVer;
+ CallerSpmMinorVer = mSpmMinorVer;
+ }
+
+ ArmCallSvc (&SpmVersionArgs);
+
+ SpmVersion = SpmVersionArgs.Arg0;
+ if (SpmVersion == FFA_NOT_SUPPORTED) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CalleeSpmMajorVer = ((SpmVersion & SPM_MAJOR_VER_MASK) >> SPM_MAJOR_VER_SHIFT);
+ CalleeSpmMinorVer = ((SpmVersion & SPM_MINOR_VER_MASK) >> 0);
+
+ // Different major revision values indicate possibly incompatible functions.
+ // For two revisions, A and B, for which the major revision values are
+ // identical, if the minor revision value of revision B is greater than
+ // the minor revision value of revision A, then every function in
+ // revision A must work in a compatible way with revision B.
+ // However, it is possible for revision B to have a higher
+ // function count than revision A.
+ if ((CalleeSpmMajorVer == CallerSpmMajorVer) &&
+ (CalleeSpmMinorVer >= CallerSpmMinorVer))
+ {
+ DEBUG ((DEBUG_INFO, "SPM Version: Major=0x%x, Minor=0x%x\n",
+ CalleeSpmMajorVer, CalleeSpmMinorVer));
+ Status = EFI_SUCCESS;
+ }
+ else
+ {
+ DEBUG ((DEBUG_INFO, "Incompatible SPM Versions.\n Callee Version: Major=0x%x, Minor=0x%x.\n Caller: Major=0x%x, Minor>=0x%x.\n",
+ CalleeSpmMajorVer, CalleeSpmMinorVer, CallerSpmMajorVer, CallerSpmMinorVer));
+ Status = EFI_UNSUPPORTED;
+ }
+
+ return Status;
+}
+
+/**
+ Initialize parameters to be sent via SVC call.
+
+ @param[out] InitMmFoundationSvcArgs Args structure
+ @param[out] Ret Return Code
+
+**/
+STATIC
+VOID
+InitArmSvcArgs (
+ OUT ARM_SVC_ARGS *InitMmFoundationSvcArgs,
+ OUT INT32 *Ret
+ )
+{
+ if (FeaturePcdGet (PcdFfaEnable)) {
+ InitMmFoundationSvcArgs->Arg0 = ARM_SVC_ID_FFA_MSG_SEND_DIRECT_RESP_AARCH64;
+ InitMmFoundationSvcArgs->Arg1 = 0;
+ InitMmFoundationSvcArgs->Arg2 = 0;
+ InitMmFoundationSvcArgs->Arg3 = ARM_SVC_ID_SP_EVENT_COMPLETE_AARCH64;
+ InitMmFoundationSvcArgs->Arg4 = *Ret;
+ } else {
+ InitMmFoundationSvcArgs->Arg0 = ARM_SVC_ID_SP_EVENT_COMPLETE_AARCH64;
+ InitMmFoundationSvcArgs->Arg1 = *Ret;
+ }
+}
+
+/**
+ The entry point of Standalone MM Foundation.
+
+ @param [in] SharedBufAddress Pointer to the Buffer between SPM and SP.
+ @param [in] SharedBufSize Size of the shared buffer.
+ @param [in] cookie1 Cookie 1
+ @param [in] cookie2 Cookie 2
+
+**/
+VOID
+EFIAPI
+_ModuleEntryPoint (
+ IN VOID *SharedBufAddress,
+ IN UINT64 SharedBufSize,
+ IN UINT64 cookie1,
+ IN UINT64 cookie2
+ )
+{
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ EFI_SECURE_PARTITION_BOOT_INFO *PayloadBootInfo;
+ ARM_SVC_ARGS InitMmFoundationSvcArgs;
+ EFI_STATUS Status;
+ INT32 Ret;
+ UINT32 SectionHeaderOffset;
+ UINT16 NumberOfSections;
+ VOID *HobStart;
+ VOID *TeData;
+ UINTN TeDataSize;
+ EFI_PHYSICAL_ADDRESS ImageBase;
+
+ // Get Secure Partition Manager Version Information
+ Status = GetSpmVersion ();
+ if (EFI_ERROR (Status)) {
+ goto finish;
+ }
+
+ PayloadBootInfo = GetAndPrintBootinformation (SharedBufAddress);
+ if (PayloadBootInfo == NULL) {
+ Status = EFI_UNSUPPORTED;
+ goto finish;
+ }
+
+ // Locate PE/COFF File information for the Standalone MM core module
+ Status = LocateStandaloneMmCorePeCoffData (
+ (EFI_FIRMWARE_VOLUME_HEADER *) PayloadBootInfo->SpImageBase,
+ &TeData,
+ &TeDataSize
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto finish;
+ }
+
+ // Obtain the PE/COFF Section information for the Standalone MM core module
+ Status = GetStandaloneMmCorePeCoffSections (
+ TeData,
+ &ImageContext,
+ &ImageBase,
+ &SectionHeaderOffset,
+ &NumberOfSections
+ );
+
+ if (EFI_ERROR (Status)) {
+ 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,
+ ArmSetMemoryRegionReadOnly,
+ ArmClearMemoryRegionReadOnly
+ );
+
+ if (EFI_ERROR (Status)) {
+ 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
+ //
+ HobStart = CreateHobListFromBootInfo (&CpuDriverEntryPoint, PayloadBootInfo);
+
+ //
+ // Call the MM Core entry point
+ //
+ ProcessModuleEntryPointList (HobStart);
+
+ DEBUG ((DEBUG_INFO, "Shared Cpu Driver EP 0x%lx\n", (UINT64) CpuDriverEntryPoint));
+
+finish:
+ if (Status == RETURN_UNSUPPORTED) {
+ Ret = -1;
+ } else if (Status == RETURN_INVALID_PARAMETER) {
+ Ret = -2;
+ } else if (Status == EFI_NOT_FOUND) {
+ Ret = -7;
+ } else {
+ Ret = 0;
+ }
+ ZeroMem (&InitMmFoundationSvcArgs, sizeof(InitMmFoundationSvcArgs));
+ InitArmSvcArgs (&InitMmFoundationSvcArgs, &Ret);
+ DelegatedEventLoop (&InitMmFoundationSvcArgs);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf
new file mode 100644
index 00000000..c71929b7
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf
@@ -0,0 +1,58 @@
+## @file
+# Module entry point library for DXE core.
+#
+# Copyright (c) 2017 - 2021, Arm Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001A
+ BASE_NAME = StandaloneMmCoreEntryPoint
+ FILE_GUID = C97AC593-109A-4C63-905C-675FDE2689E8
+ MODULE_TYPE = MM_CORE_STANDALONE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x00010032
+ LIBRARY_CLASS = StandaloneMmCoreEntryPoint|MM_CORE_STANDALONE
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC (EBC is for build only)
+#
+
+[Sources.AARCH64]
+ AArch64/StandaloneMmCoreEntryPoint.c
+ AArch64/SetPermissions.c
+ AArch64/CreateHobList.c
+
+[Sources.X64]
+ X64/StandaloneMmCoreEntryPoint.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ StandaloneMmPkg/StandaloneMmPkg.dec
+
+[Packages.AARCH64]
+ ArmPkg/ArmPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+
+[LibraryClasses.AARCH64]
+ StandaloneMmMmuLib
+ ArmSvcLib
+
+[Guids]
+ gMpInformationHobGuid
+ gEfiMmPeiMmramMemoryReserveGuid
+ gEfiStandaloneMmNonSecureBufferGuid
+ gEfiArmTfCpuDriverEpDescriptorGuid
+
+[FeaturePcd.AARCH64]
+ gArmTokenSpaceGuid.PcdFfaEnable
+
+[BuildOptions]
+ GCC:*_*_*_CC_FLAGS = -fpie
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/X64/StandaloneMmCoreEntryPoint.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/X64/StandaloneMmCoreEntryPoint.c
new file mode 100644
index 00000000..10b3dbac
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/X64/StandaloneMmCoreEntryPoint.c
@@ -0,0 +1,71 @@
+/** @file
+ Entry point to the Standalone Mm Core.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <PiMm.h>
+
+#include <Library/StandaloneMmCoreEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+
+//
+// Cache copy of HobList pointer.
+//
+VOID *gHobList = NULL;
+
+/**
+ The entry point of PE/COFF Image for the STANDALONE MM Core.
+
+ This function is the entry point for the STANDALONE MM Core. This function is required to call
+ ProcessModuleEntryPointList() and ProcessModuleEntryPointList() is never expected to return.
+ The STANDALONE MM Core is responsible for calling ProcessLibraryConstructorList() as soon as the EFI
+ System Table and the image handle for the STANDALONE MM Core itself have been established.
+ If ProcessModuleEntryPointList() returns, then ASSERT() and halt the system.
+
+ @param HobStart Pointer to the beginning of the HOB List passed in from the PEI Phase.
+
+**/
+VOID
+EFIAPI
+_ModuleEntryPoint (
+ IN VOID *HobStart
+ )
+{
+ //
+ // Cache a pointer to the HobList
+ //
+ gHobList = HobStart;
+
+ //
+ // Call the Standalone MM Core entry point
+ //
+ ProcessModuleEntryPointList (HobStart);
+
+ //
+ // TODO: Set page table here?? AARCH64 has this step for some reason
+ //
+}
+
+
+/**
+ Required by the EBC compiler and identical in functionality to _ModuleEntryPoint().
+
+ This function is required to call _ModuleEntryPoint() passing in HobStart.
+
+ @param HobStart Pointer to the beginning of the HOB List passed in from the PEI Phase.
+
+**/
+VOID
+EFIAPI
+EfiMain (
+ IN VOID *HobStart
+ )
+{
+ _ModuleEntryPoint (HobStart);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/AArch64/StandaloneMmCoreHobLib.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/AArch64/StandaloneMmCoreHobLib.c
new file mode 100644
index 00000000..5bb77515
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/AArch64/StandaloneMmCoreHobLib.c
@@ -0,0 +1,330 @@
+/** @file
+ HOB Library implementation for Standalone MM Core.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiMm.h>
+
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#include <Guid/MemoryAllocationHob.h>
+
+//
+// Cache copy of HobList pointer.
+//
+VOID *gHobList = NULL;
+
+VOID *
+CreateHob (
+ IN UINT16 HobType,
+ IN UINT16 HobLength
+ )
+{
+ EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob;
+ EFI_HOB_GENERIC_HEADER *HobEnd;
+ EFI_PHYSICAL_ADDRESS FreeMemory;
+ VOID *Hob;
+
+ HandOffHob = GetHobList ();
+
+ HobLength = (UINT16)((HobLength + 0x7) & (~0x7));
+
+ FreeMemory = HandOffHob->EfiFreeMemoryTop - HandOffHob->EfiFreeMemoryBottom;
+
+ if (FreeMemory < HobLength) {
+ return NULL;
+ }
+
+ Hob = (VOID*) (UINTN) HandOffHob->EfiEndOfHobList;
+ ((EFI_HOB_GENERIC_HEADER*) Hob)->HobType = HobType;
+ ((EFI_HOB_GENERIC_HEADER*) Hob)->HobLength = HobLength;
+ ((EFI_HOB_GENERIC_HEADER*) Hob)->Reserved = 0;
+
+ HobEnd = (EFI_HOB_GENERIC_HEADER*) ((UINTN)Hob + HobLength);
+ HandOffHob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;
+
+ HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST;
+ HobEnd->HobLength = sizeof (EFI_HOB_GENERIC_HEADER);
+ HobEnd->Reserved = 0;
+ HobEnd++;
+ HandOffHob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;
+
+ return Hob;
+}
+
+/**
+ Builds a HOB for a loaded PE32 module.
+
+ This function builds a HOB for a loaded PE32 module.
+ If ModuleName is NULL, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param ModuleName The GUID File Name of the module.
+ @param MemoryAllocationModule The 64 bit physical address of the module.
+ @param ModuleLength The length of the module in bytes.
+ @param EntryPoint The 64 bit physical address of the module entry point.
+
+**/
+VOID
+EFIAPI
+BuildModuleHob (
+ IN CONST EFI_GUID *ModuleName,
+ IN EFI_PHYSICAL_ADDRESS MemoryAllocationModule,
+ IN UINT64 ModuleLength,
+ IN EFI_PHYSICAL_ADDRESS EntryPoint
+ )
+{
+ EFI_HOB_MEMORY_ALLOCATION_MODULE *Hob;
+
+ ASSERT (((MemoryAllocationModule & (EFI_PAGE_SIZE - 1)) == 0) &&
+ ((ModuleLength & (EFI_PAGE_SIZE - 1)) == 0));
+
+ Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION_MODULE));
+
+ CopyGuid (&(Hob->MemoryAllocationHeader.Name), &gEfiHobMemoryAllocModuleGuid);
+ Hob->MemoryAllocationHeader.MemoryBaseAddress = MemoryAllocationModule;
+ Hob->MemoryAllocationHeader.MemoryLength = ModuleLength;
+ Hob->MemoryAllocationHeader.MemoryType = EfiBootServicesCode;
+
+ //
+ // Zero the reserved space to match HOB spec
+ //
+ ZeroMem (Hob->MemoryAllocationHeader.Reserved, sizeof (Hob->MemoryAllocationHeader.Reserved));
+
+ CopyGuid (&Hob->ModuleName, ModuleName);
+ Hob->EntryPoint = EntryPoint;
+}
+
+/**
+ Builds a HOB that describes a chunk of system memory.
+
+ This function builds a HOB that describes a chunk of system memory.
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param ResourceType The type of resource described by this HOB.
+ @param ResourceAttribute The resource attributes of the memory described by this HOB.
+ @param PhysicalStart The 64 bit physical address of memory described by this HOB.
+ @param NumberOfBytes The length of the memory described by this HOB in bytes.
+
+**/
+VOID
+EFIAPI
+BuildResourceDescriptorHob (
+ IN EFI_RESOURCE_TYPE ResourceType,
+ IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute,
+ IN EFI_PHYSICAL_ADDRESS PhysicalStart,
+ IN UINT64 NumberOfBytes
+ )
+{
+ EFI_HOB_RESOURCE_DESCRIPTOR *Hob;
+
+ Hob = CreateHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, sizeof (EFI_HOB_RESOURCE_DESCRIPTOR));
+ ASSERT (Hob != NULL);
+
+ Hob->ResourceType = ResourceType;
+ Hob->ResourceAttribute = ResourceAttribute;
+ Hob->PhysicalStart = PhysicalStart;
+ Hob->ResourceLength = NumberOfBytes;
+}
+
+/**
+ Builds a GUID HOB with a certain data length.
+
+ This function builds a customized HOB tagged with a GUID for identification
+ and returns the start address of GUID HOB data so that caller can fill the customized data.
+ The HOB Header and Name field is already stripped.
+ If Guid is NULL, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+ If DataLength >= (0x10000 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT().
+
+ @param Guid The GUID to tag the customized HOB.
+ @param DataLength The size of the data payload for the GUID HOB.
+
+ @return The start address of GUID HOB data.
+
+**/
+VOID *
+EFIAPI
+BuildGuidHob (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN DataLength
+ )
+{
+ EFI_HOB_GUID_TYPE *Hob;
+
+ //
+ // Make sure that data length is not too long.
+ //
+ ASSERT (DataLength <= (0xffff - sizeof (EFI_HOB_GUID_TYPE)));
+
+ Hob = CreateHob (EFI_HOB_TYPE_GUID_EXTENSION, (UINT16) (sizeof (EFI_HOB_GUID_TYPE) + DataLength));
+ CopyGuid (&Hob->Name, Guid);
+ return Hob + 1;
+}
+
+
+/**
+ Copies a data buffer to a newly-built 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.
+ The HOB Header and Name field is already stripped.
+ If Guid is NULL, then ASSERT().
+ If Data is NULL and DataLength > 0, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+ If DataLength >= (0x10000 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT().
+
+ @param Guid The GUID to tag the customized HOB.
+ @param Data The data to be copied into the data field of the GUID HOB.
+ @param DataLength The size of the data payload for the GUID HOB.
+
+ @return The start address of GUID HOB data.
+
+**/
+VOID *
+EFIAPI
+BuildGuidDataHob (
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Data,
+ IN UINTN DataLength
+ )
+{
+ VOID *HobData;
+
+ ASSERT (Data != NULL || DataLength == 0);
+
+ HobData = BuildGuidHob (Guid, DataLength);
+
+ return CopyMem (HobData, Data, DataLength);
+}
+
+/**
+ Builds a Firmware Volume HOB.
+
+ This function builds a Firmware Volume HOB.
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The base address of the Firmware Volume.
+ @param Length The size of the Firmware Volume in bytes.
+
+**/
+VOID
+EFIAPI
+BuildFvHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ EFI_HOB_FIRMWARE_VOLUME *Hob;
+
+ Hob = CreateHob (EFI_HOB_TYPE_FV, sizeof (EFI_HOB_FIRMWARE_VOLUME));
+
+ Hob->BaseAddress = BaseAddress;
+ Hob->Length = Length;
+}
+
+
+/**
+ Builds a EFI_HOB_TYPE_FV2 HOB.
+
+ This function builds a EFI_HOB_TYPE_FV2 HOB.
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The base address of the Firmware Volume.
+ @param Length The size of the Firmware Volume in bytes.
+ @param FvName The name of the Firmware Volume.
+ @param FileName The name of the file.
+
+**/
+VOID
+EFIAPI
+BuildFv2Hob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN CONST EFI_GUID *FvName,
+ IN CONST EFI_GUID *FileName
+ )
+{
+ EFI_HOB_FIRMWARE_VOLUME2 *Hob;
+
+ Hob = CreateHob (EFI_HOB_TYPE_FV2, sizeof (EFI_HOB_FIRMWARE_VOLUME2));
+
+ Hob->BaseAddress = BaseAddress;
+ Hob->Length = Length;
+ CopyGuid (&Hob->FvName, FvName);
+ CopyGuid (&Hob->FileName, FileName);
+}
+
+
+/**
+ Builds a HOB for the CPU.
+
+ This function builds a HOB for the CPU.
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param SizeOfMemorySpace The maximum physical memory addressability of the processor.
+ @param SizeOfIoSpace The maximum physical I/O addressability of the processor.
+
+**/
+VOID
+EFIAPI
+BuildCpuHob (
+ IN UINT8 SizeOfMemorySpace,
+ IN UINT8 SizeOfIoSpace
+ )
+{
+ EFI_HOB_CPU *Hob;
+
+ Hob = CreateHob (EFI_HOB_TYPE_CPU, sizeof (EFI_HOB_CPU));
+
+ Hob->SizeOfMemorySpace = SizeOfMemorySpace;
+ Hob->SizeOfIoSpace = SizeOfIoSpace;
+
+ //
+ // Zero the reserved space to match HOB spec
+ //
+ ZeroMem (Hob->Reserved, sizeof (Hob->Reserved));
+}
+
+/**
+ Builds a HOB for the memory allocation.
+
+ This function builds a HOB for the memory allocation.
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The 64 bit physical address of the memory.
+ @param Length The length of the memory allocation in bytes.
+ @param MemoryType Type of memory allocated by this HOB.
+
+**/
+VOID
+EFIAPI
+BuildMemoryAllocationHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ EFI_HOB_MEMORY_ALLOCATION *Hob;
+
+ ASSERT (((BaseAddress & (EFI_PAGE_SIZE - 1)) == 0) &&
+ ((Length & (EFI_PAGE_SIZE - 1)) == 0));
+
+ Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION));
+
+ ZeroMem (&(Hob->AllocDescriptor.Name), sizeof (EFI_GUID));
+ Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress;
+ Hob->AllocDescriptor.MemoryLength = Length;
+ Hob->AllocDescriptor.MemoryType = MemoryType;
+ //
+ // Zero the reserved space to match HOB spec
+ //
+ ZeroMem (Hob->AllocDescriptor.Reserved, sizeof (Hob->AllocDescriptor.Reserved));
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/AArch64/StandaloneMmCoreHobLibInternal.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/AArch64/StandaloneMmCoreHobLibInternal.c
new file mode 100644
index 00000000..a9f94c1c
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/AArch64/StandaloneMmCoreHobLibInternal.c
@@ -0,0 +1,58 @@
+/** @file
+ HOB Library implementation for Standalone MM Core.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiMm.h>
+
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#include <Guid/MemoryAllocationHob.h>
+
+//
+// Cache copy of HobList pointer.
+//
+extern VOID *gHobList;
+
+EFI_HOB_HANDOFF_INFO_TABLE*
+HobConstructor (
+ IN VOID *EfiMemoryBegin,
+ IN UINTN EfiMemoryLength,
+ IN VOID *EfiFreeMemoryBottom,
+ IN VOID *EfiFreeMemoryTop
+ )
+{
+ EFI_HOB_HANDOFF_INFO_TABLE *Hob;
+ EFI_HOB_GENERIC_HEADER *HobEnd;
+
+ Hob = EfiFreeMemoryBottom;
+ HobEnd = (EFI_HOB_GENERIC_HEADER *)(Hob+1);
+
+ Hob->Header.HobType = EFI_HOB_TYPE_HANDOFF;
+ Hob->Header.HobLength = sizeof (EFI_HOB_HANDOFF_INFO_TABLE);
+ Hob->Header.Reserved = 0;
+
+ HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST;
+ HobEnd->HobLength = sizeof (EFI_HOB_GENERIC_HEADER);
+ HobEnd->Reserved = 0;
+
+ Hob->Version = EFI_HOB_HANDOFF_TABLE_VERSION;
+ Hob->BootMode = BOOT_WITH_FULL_CONFIGURATION;
+
+ Hob->EfiMemoryTop = (UINTN)EfiMemoryBegin + EfiMemoryLength;
+ Hob->EfiMemoryBottom = (UINTN)EfiMemoryBegin;
+ Hob->EfiFreeMemoryTop = (UINTN)EfiFreeMemoryTop;
+ Hob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS)(UINTN)(HobEnd+1);
+ Hob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS)(UINTN)HobEnd;
+
+ gHobList = Hob;
+
+ return Hob;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/Common.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/Common.c
new file mode 100644
index 00000000..967fe738
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/Common.c
@@ -0,0 +1,291 @@
+/** @file
+ HOB Library implementation for Standalone MM Core.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiMm.h>
+
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/StandaloneMmCoreEntryPoint.h>
+
+#include <Guid/MemoryAllocationHob.h>
+
+/**
+ Returns the pointer to the HOB list.
+
+ This function returns the pointer to first HOB in the list.
+ If the pointer to the HOB list is NULL, then ASSERT().
+
+ @return The pointer to the HOB list.
+
+**/
+VOID *
+EFIAPI
+GetHobList (
+ VOID
+ )
+{
+ ASSERT (gHobList != NULL);
+ return gHobList;
+}
+
+/**
+ Returns the next instance of a HOB type from the starting HOB.
+
+ This function searches the first instance of a HOB type from the starting HOB pointer.
+ If there does not exist such HOB type from the starting HOB pointer, it will return NULL.
+ In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer
+ unconditionally: it returns HobStart back if HobStart itself meets the requirement;
+ caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart.
+
+ If HobStart is NULL, then ASSERT().
+
+ @param Type The HOB type to return.
+ @param HobStart The starting HOB pointer to search from.
+
+ @return The next instance of a HOB type from the starting HOB.
+
+**/
+VOID *
+EFIAPI
+GetNextHob (
+ IN UINT16 Type,
+ IN CONST VOID *HobStart
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+
+ ASSERT (HobStart != NULL);
+
+ Hob.Raw = (UINT8 *) HobStart;
+ //
+ // Parse the HOB list until end of list or matching type is found.
+ //
+ while (!END_OF_HOB_LIST (Hob)) {
+ if (Hob.Header->HobType == Type) {
+ return Hob.Raw;
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+ return NULL;
+}
+
+/**
+ Returns the first instance of a HOB type among the whole HOB list.
+
+ This function searches the first instance of a HOB type among the whole HOB list.
+ If there does not exist such HOB type in the HOB list, it will return NULL.
+
+ If the pointer to the HOB list is NULL, then ASSERT().
+
+ @param Type The HOB type to return.
+
+ @return The next instance of a HOB type from the starting HOB.
+
+**/
+VOID *
+EFIAPI
+GetFirstHob (
+ IN UINT16 Type
+ )
+{
+ VOID *HobList;
+
+ HobList = GetHobList ();
+ return GetNextHob (Type, HobList);
+}
+
+/**
+ Returns the next instance of the matched GUID HOB from the starting HOB.
+
+ This function searches the first instance of a HOB from the starting HOB pointer.
+ Such HOB should satisfy two conditions:
+ its HOB type is EFI_HOB_TYPE_GUID_EXTENSION, and its GUID Name equals to the input Guid.
+ If such a HOB from the starting HOB pointer does not exist, it will return NULL.
+ Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE ()
+ to extract the data section and its size information, respectively.
+ In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer
+ unconditionally: it returns HobStart back if HobStart itself meets the requirement;
+ caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart.
+
+ If Guid is NULL, then ASSERT().
+ If HobStart is NULL, then ASSERT().
+
+ @param Guid The GUID to match with in the HOB list.
+ @param HobStart A pointer to a Guid.
+
+ @return The next instance of the matched GUID HOB from the starting HOB.
+
+**/
+VOID *
+EFIAPI
+GetNextGuidHob (
+ IN CONST EFI_GUID *Guid,
+ IN CONST VOID *HobStart
+ )
+{
+ EFI_PEI_HOB_POINTERS GuidHob;
+
+ GuidHob.Raw = (UINT8 *) HobStart;
+ while ((GuidHob.Raw = GetNextHob (EFI_HOB_TYPE_GUID_EXTENSION, GuidHob.Raw)) != NULL) {
+ if (CompareGuid (Guid, &GuidHob.Guid->Name)) {
+ break;
+ }
+ GuidHob.Raw = GET_NEXT_HOB (GuidHob);
+ }
+ return GuidHob.Raw;
+}
+
+/**
+ Returns the first instance of the matched GUID HOB among the whole HOB list.
+
+ This function searches the first instance of a HOB among the whole HOB list.
+ Such HOB should satisfy two conditions:
+ its HOB type is EFI_HOB_TYPE_GUID_EXTENSION and its GUID Name equals to the input Guid.
+ If such a HOB from the starting HOB pointer does not exist, it will return NULL.
+ Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE ()
+ to extract the data section and its size information, respectively.
+
+ If the pointer to the HOB list is NULL, then ASSERT().
+ If Guid is NULL, then ASSERT().
+
+ @param Guid The GUID to match with in the HOB list.
+
+ @return The first instance of the matched GUID HOB among the whole HOB list.
+
+**/
+VOID *
+EFIAPI
+GetFirstGuidHob (
+ IN CONST EFI_GUID *Guid
+ )
+{
+ VOID *HobList;
+
+ HobList = GetHobList ();
+ return GetNextGuidHob (Guid, HobList);
+}
+
+/**
+ Get the system boot mode from the HOB list.
+
+ This function returns the system boot mode information from the
+ PHIT HOB in HOB list.
+
+ If the pointer to the HOB list is NULL, then ASSERT().
+
+ @param VOID
+
+ @return The Boot Mode.
+
+**/
+EFI_BOOT_MODE
+EFIAPI
+GetBootModeHob (
+ VOID
+ )
+{
+ EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob;
+
+ HandOffHob = (EFI_HOB_HANDOFF_INFO_TABLE *) GetHobList ();
+
+ return HandOffHob->BootMode;
+}
+
+
+/**
+ Builds a HOB that describes a chunk of system memory with Owner GUID.
+
+ This function builds a HOB that describes a chunk of system memory.
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param ResourceType The type of resource described by this HOB.
+ @param ResourceAttribute The resource attributes of the memory described by this HOB.
+ @param PhysicalStart The 64 bit physical address of memory described by this HOB.
+ @param NumberOfBytes The length of the memory described by this HOB in bytes.
+ @param OwnerGUID GUID for the owner of this resource.
+
+**/
+VOID
+EFIAPI
+BuildResourceDescriptorWithOwnerHob (
+ IN EFI_RESOURCE_TYPE ResourceType,
+ IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute,
+ IN EFI_PHYSICAL_ADDRESS PhysicalStart,
+ IN UINT64 NumberOfBytes,
+ IN EFI_GUID *OwnerGUID
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a Capsule Volume HOB.
+
+ This function builds a Capsule Volume HOB.
+ If the platform does not support Capsule Volume HOBs, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The base address of the Capsule Volume.
+ @param Length The size of the Capsule Volume in bytes.
+
+**/
+VOID
+EFIAPI
+BuildCvHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ ASSERT (FALSE);
+}
+
+
+/**
+ Builds a HOB for the BSP store.
+
+ This function builds a HOB for BSP store.
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The 64 bit physical address of the BSP.
+ @param Length The length of the BSP store in bytes.
+ @param MemoryType Type of memory allocated by this HOB.
+
+**/
+VOID
+EFIAPI
+BuildBspStoreHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a HOB for the Stack.
+
+ This function builds a HOB for the stack.
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The 64 bit physical address of the Stack.
+ @param Length The length of the stack in bytes.
+
+**/
+VOID
+EFIAPI
+BuildStackHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ ASSERT (FALSE);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/StandaloneMmCoreHobLib.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/StandaloneMmCoreHobLib.inf
new file mode 100644
index 00000000..4f77414d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/StandaloneMmCoreHobLib.inf
@@ -0,0 +1,47 @@
+## @file
+# Instance of HOB Library for Standalone MM Core.
+#
+# HOB Library implementation for the Standalone MM Core. Does not have a constructor.
+# Uses gHobList defined in the Standalone MM Core Entry Point Library.
+#
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001A
+ BASE_NAME = HobLib
+ FILE_GUID = CF56EF2C-68D8-4BD5-9A8B-8A7BFCFF751C
+ MODULE_TYPE = MM_CORE_STANDALONE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x00010032
+ LIBRARY_CLASS = HobLib|MM_CORE_STANDALONE
+
+#
+# VALID_ARCHITECTURES = X64 AARCH64
+#
+[Sources.common]
+ Common.c
+
+[Sources.X64]
+ X64/StandaloneMmCoreHobLib.c
+
+[Sources.AARCH64]
+ AArch64/StandaloneMmCoreHobLib.c
+ AArch64/StandaloneMmCoreHobLibInternal.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ StandaloneMmPkg/StandaloneMmPkg.dec
+
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+
+[Guids]
+ gEfiHobListGuid ## CONSUMES ## SystemTable
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/X64/StandaloneMmCoreHobLib.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/X64/StandaloneMmCoreHobLib.c
new file mode 100644
index 00000000..bb440da4
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/X64/StandaloneMmCoreHobLib.c
@@ -0,0 +1,298 @@
+/** @file
+ HOB Library implementation for Standalone MM Core.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiMm.h>
+
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#include <Guid/MemoryAllocationHob.h>
+
+/**
+ 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;
+ for MM phase, it will ASSERT() because PEI HOB is read-only for MM phase.
+
+ If ModuleName is NULL, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param ModuleName The GUID File Name of the module.
+ @param MemoryAllocationModule The 64 bit physical address of the module.
+ @param ModuleLength The length of the module in bytes.
+ @param EntryPoint The 64 bit physical address of the module entry point.
+
+**/
+VOID
+EFIAPI
+BuildModuleHob (
+ IN CONST EFI_GUID *ModuleName,
+ IN EFI_PHYSICAL_ADDRESS MemoryAllocationModule,
+ IN UINT64 ModuleLength,
+ IN EFI_PHYSICAL_ADDRESS EntryPoint
+ )
+{
+ //
+ // PEI HOB is read only for MM phase
+ //
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a HOB that describes a chunk of system memory.
+
+ This function builds a HOB that describes a chunk of system memory.
+ It can only be invoked during PEI phase;
+ for MM phase, it will ASSERT() because PEI HOB is read-only for MM phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param ResourceType The type of resource described by this HOB.
+ @param ResourceAttribute The resource attributes of the memory described by this HOB.
+ @param PhysicalStart The 64 bit physical address of memory described by this HOB.
+ @param NumberOfBytes The length of the memory described by this HOB in bytes.
+
+**/
+VOID
+EFIAPI
+BuildResourceDescriptorHob (
+ IN EFI_RESOURCE_TYPE ResourceType,
+ IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute,
+ IN EFI_PHYSICAL_ADDRESS PhysicalStart,
+ IN UINT64 NumberOfBytes
+ )
+{
+ //
+ // PEI HOB is read only for MM phase
+ //
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a customized HOB tagged with a GUID for identification and returns
+ the start address of GUID HOB data.
+
+ This function builds a customized HOB tagged with a GUID for identification
+ and returns the start address of GUID HOB data so that caller can fill the customized data.
+ The HOB Header and Name field is already stripped.
+ It can only be invoked during PEI phase.
+ For MM phase, it will ASSERT() because PEI HOB is read-only for MM phase.
+
+ If Guid is NULL, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+ If DataLength > (0xFFF8 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT().
+ HobLength is UINT16 and multiples of 8 bytes, so the max HobLength is 0xFFF8.
+
+ @param Guid The GUID to tag the customized HOB.
+ @param DataLength The size of the data payload for the GUID HOB.
+
+ @retval NULL The GUID HOB could not be allocated.
+ @retval others The start address of GUID HOB data.
+
+**/
+VOID *
+EFIAPI
+BuildGuidHob (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN DataLength
+ )
+{
+ //
+ // PEI HOB is read only for MM phase
+ //
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ 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.
+
+ This function builds a customized HOB tagged with a GUID for identification and copies the input
+ data to the HOB data field and returns the start address of the GUID HOB data. It can only be
+ invoked during PEI phase; for MM phase, it will ASSERT() because PEI HOB is read-only for MM phase.
+ The HOB Header and Name field is already stripped.
+ It can only be invoked during PEI phase.
+ For MM phase, it will ASSERT() because PEI HOB is read-only for MM phase.
+
+ If Guid is NULL, then ASSERT().
+ If Data is NULL and DataLength > 0, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+ If DataLength > (0xFFF8 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT().
+ HobLength is UINT16 and multiples of 8 bytes, so the max HobLength is 0xFFF8.
+
+ @param Guid The GUID to tag the customized HOB.
+ @param Data The data to be copied into the data field of the GUID HOB.
+ @param DataLength The size of the data payload for the GUID HOB.
+
+ @retval NULL The GUID HOB could not be allocated.
+ @retval others The start address of GUID HOB data.
+
+**/
+VOID *
+EFIAPI
+BuildGuidDataHob (
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Data,
+ IN UINTN DataLength
+ )
+{
+ //
+ // PEI HOB is read only for MM phase
+ //
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Builds a Firmware Volume HOB.
+
+ This function builds a Firmware Volume HOB.
+ It can only be invoked during PEI phase;
+ for MM phase, it will ASSERT() because PEI HOB is read-only for MM phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+ If the FvImage buffer is not at its required alignment, then ASSERT().
+
+ @param BaseAddress The base address of the Firmware Volume.
+ @param Length The size of the Firmware Volume in bytes.
+
+**/
+VOID
+EFIAPI
+BuildFvHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ //
+ // PEI HOB is read only for MM phase
+ //
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a EFI_HOB_TYPE_FV2 HOB.
+
+ This function builds a EFI_HOB_TYPE_FV2 HOB.
+ It can only be invoked during PEI phase;
+ for MM phase, it will ASSERT() because PEI HOB is read-only for MM phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+ If the FvImage buffer is not at its required alignment, then ASSERT().
+
+ @param BaseAddress The base address of the Firmware Volume.
+ @param Length The size of the Firmware Volume in bytes.
+ @param FvName The name of the Firmware Volume.
+ @param FileName The name of the file.
+
+**/
+VOID
+EFIAPI
+BuildFv2Hob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN CONST EFI_GUID *FvName,
+ IN CONST EFI_GUID *FileName
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a EFI_HOB_TYPE_FV3 HOB.
+
+ This function builds a EFI_HOB_TYPE_FV3 HOB.
+ It can only be invoked during PEI phase;
+ for MM phase, it will ASSERT() since PEI HOB is read-only for MM phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+ If the FvImage buffer is not at its required alignment, then ASSERT().
+
+ @param BaseAddress The base address of the Firmware Volume.
+ @param Length The size of the Firmware Volume in bytes.
+ @param AuthenticationStatus The authentication status.
+ @param ExtractedFv TRUE if the FV was extracted as a file within
+ another firmware volume. FALSE otherwise.
+ @param FvName The name of the Firmware Volume.
+ Valid only if IsExtractedFv is TRUE.
+ @param FileName The name of the file.
+ Valid only if IsExtractedFv is TRUE.
+
+**/
+VOID
+EFIAPI
+BuildFv3Hob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT32 AuthenticationStatus,
+ IN BOOLEAN ExtractedFv,
+ IN CONST EFI_GUID *FvName, OPTIONAL
+ IN CONST EFI_GUID *FileName OPTIONAL
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a HOB for the CPU.
+
+ This function builds a HOB for the CPU.
+ It can only be invoked during PEI phase;
+ for MM phase, it will ASSERT() because PEI HOB is read-only for MM phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param SizeOfMemorySpace The maximum physical memory addressability of the processor.
+ @param SizeOfIoSpace The maximum physical I/O addressability of the processor.
+
+**/
+VOID
+EFIAPI
+BuildCpuHob (
+ IN UINT8 SizeOfMemorySpace,
+ IN UINT8 SizeOfIoSpace
+ )
+{
+ //
+ // PEI HOB is read only for MM phase
+ //
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a HOB for the memory allocation.
+
+ This function builds a HOB for the memory allocation.
+ It can only be invoked during PEI phase;
+ for MM phase, it will ASSERT() because PEI HOB is read-only for MM phase.
+
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The 64 bit physical address of the memory.
+ @param Length The length of the memory allocation in bytes.
+ @param MemoryType Type of memory allocated by this HOB.
+
+**/
+VOID
+EFIAPI
+BuildMemoryAllocationHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ //
+ // PEI HOB is read only for MM phase
+ //
+ ASSERT (FALSE);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationLib.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationLib.c
new file mode 100644
index 00000000..bdf33f62
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationLib.c
@@ -0,0 +1,902 @@
+/** @file
+ Support routines for memory allocation routines based on Standalone MM Core internal functions.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2021, ARM Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiMm.h>
+
+#include <Guid/MmramMemoryReserve.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include "StandaloneMmCoreMemoryAllocationServices.h"
+
+EFI_MM_SYSTEM_TABLE *gMmst = NULL;
+
+/**
+ Allocates one or more 4KB pages of a certain memory type.
+
+ Allocates the number of 4KB pages of a certain memory type and returns a pointer to the allocated
+ buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL is returned.
+ If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocatePages (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Memory;
+
+ if (Pages == 0) {
+ return NULL;
+ }
+
+ Status = gMmst->MmAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ return (VOID *) (UINTN) Memory;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiBootServicesData.
+
+ Allocates the number of 4KB pages of type EfiBootServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePages (
+ IN UINTN Pages
+ )
+{
+ return InternalAllocatePages (EfiRuntimeServicesData, Pages);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData.
+
+ Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePages (
+ IN UINTN Pages
+ )
+{
+ return InternalAllocatePages (EfiRuntimeServicesData, Pages);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType.
+
+ Allocates the number of 4KB pages of type EfiReservedMemoryType and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPages (
+ IN UINTN Pages
+ )
+{
+ return NULL;
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the page allocation
+ functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
+ must have been allocated on a previous call to the page allocation services of the Memory
+ Allocation Library. If it is not possible to free allocated pages, then this function will
+ perform no actions.
+
+ If Buffer was not allocated with a page allocation function in the Memory Allocation Library,
+ then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer Pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreePages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Pages != 0);
+ Status = gMmst->MmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Allocates one or more 4KB pages of a certain memory type at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of a certain memory type with an alignment
+ specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is returned.
+ If there is not enough memory at the specified alignment remaining to satisfy the request, then
+ NULL is returned.
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateAlignedPages (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Memory;
+ UINTN AlignedMemory;
+ UINTN AlignmentMask;
+ UINTN UnalignedPages;
+ UINTN RealPages;
+
+ //
+ // Alignment must be a power of two or zero.
+ //
+ ASSERT ((Alignment & (Alignment - 1)) == 0);
+
+ if (Pages == 0) {
+ return NULL;
+ }
+ if (Alignment > EFI_PAGE_SIZE) {
+ //
+ // Calculate the total number of pages since alignment is larger than page size.
+ //
+ AlignmentMask = Alignment - 1;
+ RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);
+ //
+ // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
+ //
+ ASSERT (RealPages > Pages);
+
+ Status = gMmst->MmAllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;
+ UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);
+ if (UnalignedPages > 0) {
+ //
+ // Free first unaligned page(s).
+ //
+ Status = gMmst->MmFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+ Memory = (EFI_PHYSICAL_ADDRESS) (AlignedMemory + EFI_PAGES_TO_SIZE (Pages));
+ UnalignedPages = RealPages - Pages - UnalignedPages;
+ if (UnalignedPages > 0) {
+ //
+ // Free last unaligned page(s).
+ //
+ Status = gMmst->MmFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+ } else {
+ //
+ // Do not over-allocate pages in this case.
+ //
+ Status = gMmst->MmAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ AlignedMemory = (UINTN) Memory;
+ }
+ return (VOID *) AlignedMemory;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ return InternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedRuntimePages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ return InternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiReservedMemoryType with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedReservedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ return NULL;
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the aligned page
+ allocation functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
+ must have been allocated on a previous call to the aligned page allocation services of the Memory
+ Allocation Library. If it is not possible to free allocated pages, then this function will
+ perform no actions.
+
+ If Buffer was not allocated with an aligned page allocation function in the Memory Allocation
+ Library, then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer Pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreeAlignedPages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Pages != 0);
+ Status = gMmst->MmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Allocates a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocatePool (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN AllocationSize
+ )
+{
+ EFI_STATUS Status;
+ VOID *Memory;
+
+ Memory = NULL;
+
+ Status = gMmst->MmAllocatePool (MemoryType, AllocationSize, &Memory);
+ if (EFI_ERROR (Status)) {
+ Memory = NULL;
+ }
+ return Memory;
+}
+
+/**
+ Allocates a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePool (
+ IN UINTN AllocationSize
+ )
+{
+ return InternalAllocatePool (EfiRuntimeServicesData, AllocationSize);
+}
+
+/**
+ Allocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePool (
+ IN UINTN AllocationSize
+ )
+{
+ return InternalAllocatePool (EfiRuntimeServicesData, AllocationSize);
+}
+
+/**
+ Allocates a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPool (
+ IN UINTN AllocationSize
+ )
+{
+ return NULL;
+}
+
+/**
+ Allocates and zeros a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type, clears the buffer
+ with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a valid
+ buffer of 0 size is returned. If there is not enough memory remaining to satisfy the request,
+ then NULL is returned.
+
+ @param PoolType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateZeroPool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Memory;
+
+ Memory = InternalAllocatePool (PoolType, AllocationSize);
+ if (Memory != NULL) {
+ Memory = ZeroMem (Memory, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ return InternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize);
+}
+
+/**
+ Allocates and zeros a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ return InternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize);
+}
+
+/**
+ Allocates and zeros a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ return NULL;
+}
+
+/**
+ Copies a buffer to an allocated buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param PoolType The type of pool to allocate.
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateCopyPool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *Memory;
+
+ ASSERT (Buffer != NULL);
+ ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1));
+
+ Memory = InternalAllocatePool (PoolType, AllocationSize);
+ if (Memory != NULL) {
+ Memory = CopyMem (Memory, Buffer, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ return InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ return InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ return NULL;
+}
+
+/**
+ Reallocates a buffer of a specified memory type.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of the type
+ specified by PoolType. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param PoolType The type of pool to allocate.
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalReallocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalAllocateZeroPool (PoolType, NewSize);
+ if (NewBuffer != NULL && OldBuffer != NULL) {
+ CopyMem (NewBuffer, OldBuffer, MIN (OldSize, NewSize));
+ FreePool (OldBuffer);
+ }
+ return NewBuffer;
+}
+
+/**
+ Reallocates a buffer of type EfiBootServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiBootServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocatePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ return InternalReallocatePool (EfiRuntimeServicesData, OldSize, NewSize, OldBuffer);
+}
+
+/**
+ Reallocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateRuntimePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ return InternalReallocatePool (EfiRuntimeServicesData, OldSize, NewSize, OldBuffer);
+}
+
+/**
+ Reallocates a buffer of type EfiReservedMemoryType.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiReservedMemoryType. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateReservedPool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ return NULL;
+}
+
+/**
+ Frees a buffer that was previously allocated with one of the pool allocation functions in the
+ Memory Allocation Library.
+
+ Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the
+ pool allocation services of the Memory Allocation Library. If it is not possible to free pool
+ resources, then this function will perform no actions.
+
+ If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
+ then ASSERT().
+
+ @param Buffer Pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+FreePool (
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gMmst->MmFreePool (Buffer);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ The constructor function calls MmInitializeMemoryServices to initialize
+ memory in MMRAM and caches EFI_MM_SYSTEM_TABLE pointer.
+
+ @param [in] ImageHandle The firmware allocated handle for the EFI image.
+ @param [in] MmSystemTable A pointer to the Management mode System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+MemoryAllocationLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_MM_SYSTEM_TABLE *MmSystemTable
+ )
+{
+ MM_CORE_PRIVATE_DATA *MmCorePrivate;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ MM_CORE_DATA_HOB_DATA *DataInHob;
+ VOID *HobStart;
+ EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *MmramRangesHobData;
+ EFI_MMRAM_DESCRIPTOR *MmramRanges;
+ UINTN MmramRangeCount;
+ EFI_HOB_GUID_TYPE *MmramRangesHob;
+
+ HobStart = GetHobList ();
+ DEBUG ((DEBUG_INFO, "StandaloneMmCoreMemoryAllocationLibConstructor - 0x%x\n", HobStart));
+
+ //
+ // Extract MM Core Private context from the Hob. If absent search for
+ // a Hob containing the MMRAM ranges
+ //
+ GuidHob = GetNextGuidHob (&gMmCoreDataHobGuid, HobStart);
+ if (GuidHob == NULL) {
+ MmramRangesHob = GetNextGuidHob (&gEfiMmPeiMmramMemoryReserveGuid, HobStart);
+ if (MmramRangesHob == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ MmramRangesHobData = GET_GUID_HOB_DATA (MmramRangesHob);
+ if (MmramRangesHobData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ MmramRanges = MmramRangesHobData->Descriptor;
+ if (MmramRanges == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ MmramRangeCount = (UINTN) MmramRangesHobData->NumberOfMmReservedRegions;
+ if (MmramRanges == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ } else {
+ DataInHob = GET_GUID_HOB_DATA (GuidHob);
+ MmCorePrivate = (MM_CORE_PRIVATE_DATA *)(UINTN)DataInHob->Address;
+ MmramRanges = (EFI_MMRAM_DESCRIPTOR *)(UINTN)MmCorePrivate->MmramRanges;
+ MmramRangeCount = (UINTN) MmCorePrivate->MmramRangeCount;
+ }
+
+ {
+ UINTN Index;
+
+ DEBUG ((DEBUG_INFO, "MmramRangeCount - 0x%x\n", MmramRangeCount));
+ for (Index = 0; Index < MmramRangeCount; Index++) {
+ DEBUG ((DEBUG_INFO, "MmramRanges[%d]: 0x%016lx - 0x%016lx\n",
+ Index, MmramRanges[Index].CpuStart, MmramRanges[Index].PhysicalSize));
+ }
+ }
+
+ //
+ // Initialize memory service using free MMRAM
+ //
+ DEBUG ((DEBUG_INFO, "MmInitializeMemoryServices\n"));
+ MmInitializeMemoryServices ((UINTN)MmramRangeCount, (VOID *)(UINTN)MmramRanges);
+
+ // Initialize MM Services Table
+ gMmst = MmSystemTable;
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationLib.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationLib.inf
new file mode 100644
index 00000000..b0bbe28f
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationLib.inf
@@ -0,0 +1,44 @@
+## @file
+# Memory Allocation Library instance dedicated to MM Core.
+# The implementation borrows the MM Core Memory Allocation services as the primitive
+# for memory allocation instead of using MM System Table services in an indirect way.
+# It is assumed that this library instance must be linked with MM Core in this package.
+#
+# Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001A
+ BASE_NAME = MemoryAllocationLib
+ FILE_GUID = DCDCBE1D-E760-4E1D-85B4-96E3F0439C41
+ MODULE_TYPE = MM_CORE_STANDALONE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x00010032
+ LIBRARY_CLASS = MemoryAllocationLib|MM_CORE_STANDALONE
+ CONSTRUCTOR = MemoryAllocationLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ StandaloneMmCoreMemoryAllocationLib.c
+ StandaloneMmCoreMemoryAllocationServices.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ StandaloneMmPkg/StandaloneMmPkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ HobLib
+
+[Guids]
+ gEfiMmPeiMmramMemoryReserveGuid
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationServices.h b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationServices.h
new file mode 100644
index 00000000..1bfecbc9
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationServices.h
@@ -0,0 +1,32 @@
+/** @file
+ Contains function prototypes for Memory Services in the MM Core.
+
+ This header file borrows the StandaloneMmCore Memory Allocation services as the primitive
+ for memory allocation.
+
+ Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PI_MM_CORE_MEMORY_ALLOCATION_SERVICES_H_
+#define _PI_MM_CORE_MEMORY_ALLOCATION_SERVICES_H_
+
+#include <Guid/MmCoreData.h>
+
+/**
+ Called to initialize the memory service.
+
+ @param MmramRangeCount Number of MMRAM Regions
+ @param MmramRanges Pointer to MMRAM Descriptors
+
+**/
+VOID
+MmInitializeMemoryServices (
+ IN UINTN MmramRangeCount,
+ IN EFI_MMRAM_DESCRIPTOR *MmramRanges
+ );
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmHobLib/StandaloneMmHobLib.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmHobLib/StandaloneMmHobLib.c
new file mode 100644
index 00000000..d444855f
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmHobLib/StandaloneMmHobLib.c
@@ -0,0 +1,643 @@
+/** @file
+ HOB Library implementation for Standalone MM Core.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.<BR>
+Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiMm.h>
+
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MmServicesTableLib.h>
+
+//
+// Cache copy of HobList pointer.
+//
+STATIC VOID *gHobList = NULL;
+
+/**
+ The constructor function caches the pointer to HOB list.
+
+ The constructor function gets the start address of HOB list from system configuration table.
+ It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
+
+ @param ImageHandle The firmware allocated handle for the image.
+ @param MmSystemTable A pointer to the MM System Table.
+
+ @retval EFI_SUCCESS The constructor successfully gets HobList.
+ @retval Other value The constructor can't get HobList.
+
+**/
+EFI_STATUS
+EFIAPI
+HobLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_MM_SYSTEM_TABLE *MmSystemTable
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < gMmst->NumberOfTableEntries; Index++) {
+ if (CompareGuid (&gEfiHobListGuid, &gMmst->MmConfigurationTable[Index].VendorGuid)) {
+ gHobList = gMmst->MmConfigurationTable[Index].VendorTable;
+ break;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Returns the pointer to the HOB list.
+
+ This function returns the pointer to first HOB in the list.
+ If the pointer to the HOB list is NULL, then ASSERT().
+
+ @return The pointer to the HOB list.
+
+**/
+VOID *
+EFIAPI
+GetHobList (
+ VOID
+ )
+{
+ UINTN Index;
+
+ if (gHobList == NULL) {
+ for (Index = 0; Index < gMmst->NumberOfTableEntries; Index++) {
+ if (CompareGuid (&gEfiHobListGuid, &gMmst->MmConfigurationTable[Index].VendorGuid)) {
+ gHobList = gMmst->MmConfigurationTable[Index].VendorTable;
+ break;
+ }
+ }
+ }
+ ASSERT (gHobList != NULL);
+ return gHobList;
+}
+
+/**
+ Returns the next instance of a HOB type from the starting HOB.
+
+ This function searches the first instance of a HOB type from the starting HOB pointer.
+ If there does not exist such HOB type from the starting HOB pointer, it will return NULL.
+ In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer
+ unconditionally: it returns HobStart back if HobStart itself meets the requirement;
+ caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart.
+
+ If HobStart is NULL, then ASSERT().
+
+ @param Type The HOB type to return.
+ @param HobStart The starting HOB pointer to search from.
+
+ @return The next instance of a HOB type from the starting HOB.
+
+**/
+VOID *
+EFIAPI
+GetNextHob (
+ IN UINT16 Type,
+ IN CONST VOID *HobStart
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+
+ ASSERT (HobStart != NULL);
+
+ Hob.Raw = (UINT8 *) HobStart;
+ //
+ // Parse the HOB list until end of list or matching type is found.
+ //
+ while (!END_OF_HOB_LIST (Hob)) {
+ if (Hob.Header->HobType == Type) {
+ return Hob.Raw;
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+ return NULL;
+}
+
+/**
+ Returns the first instance of a HOB type among the whole HOB list.
+
+ This function searches the first instance of a HOB type among the whole HOB list.
+ If there does not exist such HOB type in the HOB list, it will return NULL.
+
+ If the pointer to the HOB list is NULL, then ASSERT().
+
+ @param Type The HOB type to return.
+
+ @return The next instance of a HOB type from the starting HOB.
+
+**/
+VOID *
+EFIAPI
+GetFirstHob (
+ IN UINT16 Type
+ )
+{
+ VOID *HobList;
+
+ HobList = GetHobList ();
+ return GetNextHob (Type, HobList);
+}
+
+/**
+ Returns the next instance of the matched GUID HOB from the starting HOB.
+
+ This function searches the first instance of a HOB from the starting HOB pointer.
+ Such HOB should satisfy two conditions:
+ its HOB type is EFI_HOB_TYPE_GUID_EXTENSION, and its GUID Name equals to the input Guid.
+ If such a HOB from the starting HOB pointer does not exist, it will return NULL.
+ Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE ()
+ to extract the data section and its size information, respectively.
+ In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer
+ unconditionally: it returns HobStart back if HobStart itself meets the requirement;
+ caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart.
+
+ If Guid is NULL, then ASSERT().
+ If HobStart is NULL, then ASSERT().
+
+ @param Guid The GUID to match with in the HOB list.
+ @param HobStart A pointer to a Guid.
+
+ @return The next instance of the matched GUID HOB from the starting HOB.
+
+**/
+VOID *
+EFIAPI
+GetNextGuidHob (
+ IN CONST EFI_GUID *Guid,
+ IN CONST VOID *HobStart
+ )
+{
+ EFI_PEI_HOB_POINTERS GuidHob;
+
+ GuidHob.Raw = (UINT8 *) HobStart;
+ while ((GuidHob.Raw = GetNextHob (EFI_HOB_TYPE_GUID_EXTENSION, GuidHob.Raw)) != NULL) {
+ if (CompareGuid (Guid, &GuidHob.Guid->Name)) {
+ break;
+ }
+ GuidHob.Raw = GET_NEXT_HOB (GuidHob);
+ }
+ return GuidHob.Raw;
+}
+
+/**
+ Returns the first instance of the matched GUID HOB among the whole HOB list.
+
+ This function searches the first instance of a HOB among the whole HOB list.
+ Such HOB should satisfy two conditions:
+ its HOB type is EFI_HOB_TYPE_GUID_EXTENSION and its GUID Name equals to the input Guid.
+ If such a HOB from the starting HOB pointer does not exist, it will return NULL.
+ Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE ()
+ to extract the data section and its size information, respectively.
+
+ If the pointer to the HOB list is NULL, then ASSERT().
+ If Guid is NULL, then ASSERT().
+
+ @param Guid The GUID to match with in the HOB list.
+
+ @return The first instance of the matched GUID HOB among the whole HOB list.
+
+**/
+VOID *
+EFIAPI
+GetFirstGuidHob (
+ IN CONST EFI_GUID *Guid
+ )
+{
+ VOID *HobList;
+
+ HobList = GetHobList ();
+ return GetNextGuidHob (Guid, HobList);
+}
+
+/**
+ Get the system boot mode from the HOB list.
+
+ This function returns the system boot mode information from the
+ PHIT HOB in HOB list.
+
+ If the pointer to the HOB list is NULL, then ASSERT().
+
+ @param VOID
+
+ @return The Boot Mode.
+
+**/
+EFI_BOOT_MODE
+EFIAPI
+GetBootModeHob (
+ VOID
+ )
+{
+ EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob;
+
+ HandOffHob = (EFI_HOB_HANDOFF_INFO_TABLE *) GetHobList ();
+
+ return HandOffHob->BootMode;
+}
+
+VOID *
+CreateHob (
+ IN UINT16 HobType,
+ IN UINT16 HobLength
+ )
+{
+ EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob;
+ EFI_HOB_GENERIC_HEADER *HobEnd;
+ EFI_PHYSICAL_ADDRESS FreeMemory;
+ VOID *Hob;
+
+ HandOffHob = GetHobList ();
+
+ HobLength = (UINT16)((HobLength + 0x7) & (~0x7));
+
+ FreeMemory = HandOffHob->EfiFreeMemoryTop - HandOffHob->EfiFreeMemoryBottom;
+
+ if (FreeMemory < HobLength) {
+ return NULL;
+ }
+
+ Hob = (VOID*) (UINTN) HandOffHob->EfiEndOfHobList;
+ ((EFI_HOB_GENERIC_HEADER*) Hob)->HobType = HobType;
+ ((EFI_HOB_GENERIC_HEADER*) Hob)->HobLength = HobLength;
+ ((EFI_HOB_GENERIC_HEADER*) Hob)->Reserved = 0;
+
+ HobEnd = (EFI_HOB_GENERIC_HEADER*) ((UINTN)Hob + HobLength);
+ HandOffHob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;
+
+ HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST;
+ HobEnd->HobLength = sizeof(EFI_HOB_GENERIC_HEADER);
+ HobEnd->Reserved = 0;
+ HobEnd++;
+ HandOffHob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;
+
+ return Hob;
+}
+
+/**
+ Builds a HOB for a loaded PE32 module.
+
+ This function builds a HOB for a loaded PE32 module.
+ If ModuleName is NULL, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param ModuleName The GUID File Name of the module.
+ @param MemoryAllocationModule The 64 bit physical address of the module.
+ @param ModuleLength The length of the module in bytes.
+ @param EntryPoint The 64 bit physical address of the module entry point.
+
+**/
+VOID
+EFIAPI
+BuildModuleHob (
+ IN CONST EFI_GUID *ModuleName,
+ IN EFI_PHYSICAL_ADDRESS MemoryAllocationModule,
+ IN UINT64 ModuleLength,
+ IN EFI_PHYSICAL_ADDRESS EntryPoint
+ )
+{
+ EFI_HOB_MEMORY_ALLOCATION_MODULE *Hob;
+
+ ASSERT (((MemoryAllocationModule & (EFI_PAGE_SIZE - 1)) == 0) &&
+ ((ModuleLength & (EFI_PAGE_SIZE - 1)) == 0));
+
+ Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION_MODULE));
+
+ CopyGuid (&(Hob->MemoryAllocationHeader.Name), &gEfiHobMemoryAllocModuleGuid);
+ Hob->MemoryAllocationHeader.MemoryBaseAddress = MemoryAllocationModule;
+ Hob->MemoryAllocationHeader.MemoryLength = ModuleLength;
+ Hob->MemoryAllocationHeader.MemoryType = EfiBootServicesCode;
+
+ //
+ // Zero the reserved space to match HOB spec
+ //
+ ZeroMem (Hob->MemoryAllocationHeader.Reserved, sizeof (Hob->MemoryAllocationHeader.Reserved));
+
+ CopyGuid (&Hob->ModuleName, ModuleName);
+ Hob->EntryPoint = EntryPoint;
+}
+
+/**
+ Builds a HOB that describes a chunk of system memory.
+
+ This function builds a HOB that describes a chunk of system memory.
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param ResourceType The type of resource described by this HOB.
+ @param ResourceAttribute The resource attributes of the memory described by this HOB.
+ @param PhysicalStart The 64 bit physical address of memory described by this HOB.
+ @param NumberOfBytes The length of the memory described by this HOB in bytes.
+
+**/
+VOID
+EFIAPI
+BuildResourceDescriptorHob (
+ IN EFI_RESOURCE_TYPE ResourceType,
+ IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute,
+ IN EFI_PHYSICAL_ADDRESS PhysicalStart,
+ IN UINT64 NumberOfBytes
+ )
+{
+ EFI_HOB_RESOURCE_DESCRIPTOR *Hob;
+
+ Hob = CreateHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, sizeof (EFI_HOB_RESOURCE_DESCRIPTOR));
+ ASSERT(Hob != NULL);
+
+ Hob->ResourceType = ResourceType;
+ Hob->ResourceAttribute = ResourceAttribute;
+ Hob->PhysicalStart = PhysicalStart;
+ Hob->ResourceLength = NumberOfBytes;
+}
+
+/**
+ Builds a GUID HOB with a certain data length.
+
+ This function builds a customized HOB tagged with a GUID for identification
+ and returns the start address of GUID HOB data so that caller can fill the customized data.
+ The HOB Header and Name field is already stripped.
+ If Guid is NULL, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+ If DataLength >= (0x10000 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT().
+
+ @param Guid The GUID to tag the customized HOB.
+ @param DataLength The size of the data payload for the GUID HOB.
+
+ @return The start address of GUID HOB data.
+
+**/
+VOID *
+EFIAPI
+BuildGuidHob (
+ IN CONST EFI_GUID *Guid,
+ IN UINTN DataLength
+ )
+{
+ EFI_HOB_GUID_TYPE *Hob;
+
+ //
+ // Make sure that data length is not too long.
+ //
+ ASSERT (DataLength <= (0xffff - sizeof (EFI_HOB_GUID_TYPE)));
+
+ Hob = CreateHob (EFI_HOB_TYPE_GUID_EXTENSION, (UINT16) (sizeof (EFI_HOB_GUID_TYPE) + DataLength));
+ CopyGuid (&Hob->Name, Guid);
+ return Hob + 1;
+}
+
+
+/**
+ Copies a data buffer to a newly-built 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.
+ The HOB Header and Name field is already stripped.
+ If Guid is NULL, then ASSERT().
+ If Data is NULL and DataLength > 0, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+ If DataLength >= (0x10000 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT().
+
+ @param Guid The GUID to tag the customized HOB.
+ @param Data The data to be copied into the data field of the GUID HOB.
+ @param DataLength The size of the data payload for the GUID HOB.
+
+ @return The start address of GUID HOB data.
+
+**/
+VOID *
+EFIAPI
+BuildGuidDataHob (
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Data,
+ IN UINTN DataLength
+ )
+{
+ VOID *HobData;
+
+ ASSERT (Data != NULL || DataLength == 0);
+
+ HobData = BuildGuidHob (Guid, DataLength);
+
+ return CopyMem (HobData, Data, DataLength);
+}
+
+/**
+ Builds a Firmware Volume HOB.
+
+ This function builds a Firmware Volume HOB.
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The base address of the Firmware Volume.
+ @param Length The size of the Firmware Volume in bytes.
+
+**/
+VOID
+EFIAPI
+BuildFvHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ EFI_HOB_FIRMWARE_VOLUME *Hob;
+
+ Hob = CreateHob (EFI_HOB_TYPE_FV, sizeof (EFI_HOB_FIRMWARE_VOLUME));
+
+ Hob->BaseAddress = BaseAddress;
+ Hob->Length = Length;
+}
+
+
+/**
+ Builds a EFI_HOB_TYPE_FV2 HOB.
+
+ This function builds a EFI_HOB_TYPE_FV2 HOB.
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The base address of the Firmware Volume.
+ @param Length The size of the Firmware Volume in bytes.
+ @param FvName The name of the Firmware Volume.
+ @param FileName The name of the file.
+
+**/
+VOID
+EFIAPI
+BuildFv2Hob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN CONST EFI_GUID *FvName,
+ IN CONST EFI_GUID *FileName
+ )
+{
+ EFI_HOB_FIRMWARE_VOLUME2 *Hob;
+
+ Hob = CreateHob (EFI_HOB_TYPE_FV2, sizeof (EFI_HOB_FIRMWARE_VOLUME2));
+
+ Hob->BaseAddress = BaseAddress;
+ Hob->Length = Length;
+ CopyGuid (&Hob->FvName, FvName);
+ CopyGuid (&Hob->FileName, FileName);
+}
+
+
+/**
+ Builds a HOB for the CPU.
+
+ This function builds a HOB for the CPU.
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param SizeOfMemorySpace The maximum physical memory addressability of the processor.
+ @param SizeOfIoSpace The maximum physical I/O addressability of the processor.
+
+**/
+VOID
+EFIAPI
+BuildCpuHob (
+ IN UINT8 SizeOfMemorySpace,
+ IN UINT8 SizeOfIoSpace
+ )
+{
+ EFI_HOB_CPU *Hob;
+
+ Hob = CreateHob (EFI_HOB_TYPE_CPU, sizeof (EFI_HOB_CPU));
+
+ Hob->SizeOfMemorySpace = SizeOfMemorySpace;
+ Hob->SizeOfIoSpace = SizeOfIoSpace;
+
+ //
+ // Zero the reserved space to match HOB spec
+ //
+ ZeroMem (Hob->Reserved, sizeof (Hob->Reserved));
+}
+
+/**
+ Builds a HOB for the memory allocation.
+
+ This function builds a HOB for the memory allocation.
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The 64 bit physical address of the memory.
+ @param Length The length of the memory allocation in bytes.
+ @param MemoryType Type of memory allocated by this HOB.
+
+**/
+VOID
+EFIAPI
+BuildMemoryAllocationHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ EFI_HOB_MEMORY_ALLOCATION *Hob;
+
+ ASSERT (((BaseAddress & (EFI_PAGE_SIZE - 1)) == 0) &&
+ ((Length & (EFI_PAGE_SIZE - 1)) == 0));
+
+ Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION));
+
+ ZeroMem (&(Hob->AllocDescriptor.Name), sizeof (EFI_GUID));
+ Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress;
+ Hob->AllocDescriptor.MemoryLength = Length;
+ Hob->AllocDescriptor.MemoryType = MemoryType;
+ //
+ // Zero the reserved space to match HOB spec
+ //
+ ZeroMem (Hob->AllocDescriptor.Reserved, sizeof (Hob->AllocDescriptor.Reserved));
+}
+
+/**
+ Builds a HOB that describes a chunk of system memory with Owner GUID.
+
+ This function builds a HOB that describes a chunk of system memory.
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param ResourceType The type of resource described by this HOB.
+ @param ResourceAttribute The resource attributes of the memory described by this HOB.
+ @param PhysicalStart The 64 bit physical address of memory described by this HOB.
+ @param NumberOfBytes The length of the memory described by this HOB in bytes.
+ @param OwnerGUID GUID for the owner of this resource.
+
+**/
+VOID
+EFIAPI
+BuildResourceDescriptorWithOwnerHob (
+ IN EFI_RESOURCE_TYPE ResourceType,
+ IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute,
+ IN EFI_PHYSICAL_ADDRESS PhysicalStart,
+ IN UINT64 NumberOfBytes,
+ IN EFI_GUID *OwnerGUID
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a Capsule Volume HOB.
+
+ This function builds a Capsule Volume HOB.
+ If the platform does not support Capsule Volume HOBs, then ASSERT().
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The base address of the Capsule Volume.
+ @param Length The size of the Capsule Volume in bytes.
+
+**/
+VOID
+EFIAPI
+BuildCvHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ ASSERT (FALSE);
+}
+
+
+/**
+ Builds a HOB for the BSP store.
+
+ This function builds a HOB for BSP store.
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The 64 bit physical address of the BSP.
+ @param Length The length of the BSP store in bytes.
+ @param MemoryType Type of memory allocated by this HOB.
+
+**/
+VOID
+EFIAPI
+BuildBspStoreHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Builds a HOB for the Stack.
+
+ This function builds a HOB for the stack.
+ If there is no additional space for HOB creation, then ASSERT().
+
+ @param BaseAddress The 64 bit physical address of the Stack.
+ @param Length The length of the stack in bytes.
+
+**/
+VOID
+EFIAPI
+BuildStackHob (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ ASSERT (FALSE);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmHobLib/StandaloneMmHobLib.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmHobLib/StandaloneMmHobLib.inf
new file mode 100644
index 00000000..764d5573
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmHobLib/StandaloneMmHobLib.inf
@@ -0,0 +1,40 @@
+## @file
+# Instance of HOB Library for Standalone MM modules.
+#
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+# Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = HobLib
+ FILE_GUID = 8262551B-AB2D-4E76-99FC-5EBB83F4988E
+ MODULE_TYPE = MM_STANDALONE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x00010032
+ LIBRARY_CLASS = HobLib|MM_STANDALONE
+ CONSTRUCTOR = HobLibConstructor
+
+#
+# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+ StandaloneMmHobLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ MmServicesTableLib
+
+[Guids]
+ gEfiHobListGuid ## CONSUMES ## SystemTable
+ gEfiHobMemoryAllocModuleGuid ## CONSUMES
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/AArch64/StandaloneMmMemLibInternal.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/AArch64/StandaloneMmMemLibInternal.c
new file mode 100644
index 00000000..8f92a997
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/AArch64/StandaloneMmMemLibInternal.c
@@ -0,0 +1,70 @@
+/** @file
+ Internal ARCH Specific file of MM memory check library.
+
+ MM memory check library implementation. This library consumes MM_ACCESS_PROTOCOL
+ to get MMRAM information. In order to use this library instance, the platform should produce
+ all MMRAM range via MM_ACCESS_PROTOCOL, including the range for firmware (like MM Core
+ and MM driver) and/or specific dedicated hardware.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+//
+// Maximum support address used to check input buffer
+//
+extern EFI_PHYSICAL_ADDRESS mMmMemLibInternalMaximumSupportAddress;
+
+/**
+ Calculate and save the maximum support address.
+
+**/
+VOID
+MmMemLibInternalCalculateMaximumSupportAddress (
+ VOID
+ )
+{
+ UINT8 PhysicalAddressBits;
+
+ PhysicalAddressBits = 36;
+
+ //
+ // Save the maximum support address in one global variable
+ //
+ mMmMemLibInternalMaximumSupportAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)(LShiftU64 (1, PhysicalAddressBits) - 1);
+ DEBUG ((DEBUG_INFO, "mMmMemLibInternalMaximumSupportAddress = 0x%lx\n", mMmMemLibInternalMaximumSupportAddress));
+}
+
+/**
+ Initialize cached Mmram Ranges from HOB.
+
+ @retval EFI_UNSUPPORTED The routine is unable to extract MMRAM information.
+ @retval EFI_SUCCESS MmRanges are populated successfully.
+
+**/
+EFI_STATUS
+MmMemLibInternalPopulateMmramRanges (
+ VOID
+ )
+{
+ // Not implemented for AARCH64.
+ return EFI_SUCCESS;
+}
+
+/**
+ Deinitialize cached Mmram Ranges.
+
+**/
+VOID
+MmMemLibInternalFreeMmramRanges (
+ VOID
+ )
+{
+ // Not implemented for AARCH64.
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.c
new file mode 100644
index 00000000..38117ea6
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.c
@@ -0,0 +1,315 @@
+/** @file
+ Instance of MM memory check library.
+
+ MM memory check library library implementation. This library consumes MM_ACCESS_PROTOCOL
+ to get MMRAM information. In order to use this library instance, the platform should produce
+ all MMRAM range via MM_ACCESS_PROTOCOL, including the range for firmware (like MM Core
+ and MM driver) and/or specific dedicated hardware.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <PiMm.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+
+EFI_MMRAM_DESCRIPTOR *mMmMemLibInternalMmramRanges;
+UINTN mMmMemLibInternalMmramCount;
+
+//
+// Maximum support address used to check input buffer
+//
+EFI_PHYSICAL_ADDRESS mMmMemLibInternalMaximumSupportAddress = 0;
+
+/**
+ Calculate and save the maximum support address.
+
+**/
+VOID
+MmMemLibInternalCalculateMaximumSupportAddress (
+ VOID
+ );
+
+/**
+ Initialize cached Mmram Ranges from HOB.
+
+ @retval EFI_UNSUPPORTED The routine is unable to extract MMRAM information.
+ @retval EFI_SUCCESS MmRanges are populated successfully.
+
+**/
+EFI_STATUS
+MmMemLibInternalPopulateMmramRanges (
+ VOID
+ );
+
+/**
+ Deinitialize cached Mmram Ranges.
+
+**/
+VOID
+MmMemLibInternalFreeMmramRanges (
+ VOID
+ );
+
+/**
+ This function check if the buffer is valid per processor architecture and not overlap with MMRAM.
+
+ @param Buffer The buffer start address to be checked.
+ @param Length The buffer length to be checked.
+
+ @retval TRUE This buffer is valid per processor architecture and not overlap with MMRAM.
+ @retval FALSE This buffer is not valid per processor architecture or overlap with MMRAM.
+**/
+BOOLEAN
+EFIAPI
+MmIsBufferOutsideMmValid (
+ IN EFI_PHYSICAL_ADDRESS Buffer,
+ IN UINT64 Length
+ )
+{
+ UINTN Index;
+
+ //
+ // Check override.
+ // NOTE: (B:0->L:4G) is invalid for IA32, but (B:1->L:4G-1)/(B:4G-1->L:1) is valid.
+ //
+ if ((Length > mMmMemLibInternalMaximumSupportAddress) ||
+ (Buffer > mMmMemLibInternalMaximumSupportAddress) ||
+ ((Length != 0) && (Buffer > (mMmMemLibInternalMaximumSupportAddress - (Length - 1)))) ) {
+ //
+ // Overflow happen
+ //
+ DEBUG ((
+ DEBUG_ERROR,
+ "MmIsBufferOutsideMmValid: Overflow: Buffer (0x%lx) - Length (0x%lx), MaximumSupportAddress (0x%lx)\n",
+ Buffer,
+ Length,
+ mMmMemLibInternalMaximumSupportAddress
+ ));
+ return FALSE;
+ }
+
+ for (Index = 0; Index < mMmMemLibInternalMmramCount; Index ++) {
+ if (((Buffer >= mMmMemLibInternalMmramRanges[Index].CpuStart) &&
+ (Buffer < mMmMemLibInternalMmramRanges[Index].CpuStart + mMmMemLibInternalMmramRanges[Index].PhysicalSize)) ||
+ ((mMmMemLibInternalMmramRanges[Index].CpuStart >= Buffer) &&
+ (mMmMemLibInternalMmramRanges[Index].CpuStart < Buffer + Length))) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "MmIsBufferOutsideMmValid: Overlap: Buffer (0x%lx) - Length (0x%lx), ",
+ Buffer,
+ Length
+ ));
+ DEBUG ((
+ DEBUG_ERROR,
+ "CpuStart (0x%lx) - PhysicalSize (0x%lx)\n",
+ mMmMemLibInternalMmramRanges[Index].CpuStart,
+ mMmMemLibInternalMmramRanges[Index].PhysicalSize
+ ));
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Copies a source buffer (non-MMRAM) to a destination buffer (MMRAM).
+
+ This function copies a source buffer (non-MMRAM) to a destination buffer (MMRAM).
+ It checks if source buffer is valid per processor architecture and not overlap with MMRAM.
+ If the check passes, it copies memory and returns EFI_SUCCESS.
+ If the check fails, it return EFI_SECURITY_VIOLATION.
+ The implementation must be reentrant.
+
+ @param DestinationBuffer The pointer to the destination buffer of the memory copy.
+ @param SourceBuffer The pointer to the source buffer of the memory copy.
+ @param Length The number of bytes to copy from SourceBuffer to DestinationBuffer.
+
+ @retval EFI_SECURITY_VIOLATION The SourceBuffer is invalid per processor architecture or overlap with MMRAM.
+ @retval EFI_SUCCESS Memory is copied.
+
+**/
+EFI_STATUS
+EFIAPI
+MmCopyMemToMmram (
+ OUT VOID *DestinationBuffer,
+ IN CONST VOID *SourceBuffer,
+ IN UINTN Length
+ )
+{
+ if (!MmIsBufferOutsideMmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)SourceBuffer, Length)) {
+ DEBUG ((DEBUG_ERROR, "MmCopyMemToMmram: Security Violation: Source (0x%x), Length (0x%x)\n", SourceBuffer, Length));
+ return EFI_SECURITY_VIOLATION;
+ }
+ CopyMem (DestinationBuffer, SourceBuffer, Length);
+ return EFI_SUCCESS;
+}
+
+/**
+ Copies a source buffer (MMRAM) to a destination buffer (NON-MMRAM).
+
+ This function copies a source buffer (non-MMRAM) to a destination buffer (MMRAM).
+ It checks if destination buffer is valid per processor architecture and not overlap with MMRAM.
+ If the check passes, it copies memory and returns EFI_SUCCESS.
+ If the check fails, it returns EFI_SECURITY_VIOLATION.
+ The implementation must be reentrant.
+
+ @param DestinationBuffer The pointer to the destination buffer of the memory copy.
+ @param SourceBuffer The pointer to the source buffer of the memory copy.
+ @param Length The number of bytes to copy from SourceBuffer to DestinationBuffer.
+
+ @retval EFI_SECURITY_VIOLATION The DestinationBuffer is invalid per processor architecture or overlap with MMRAM.
+ @retval EFI_SUCCESS Memory is copied.
+
+**/
+EFI_STATUS
+EFIAPI
+MmCopyMemFromMmram (
+ OUT VOID *DestinationBuffer,
+ IN CONST VOID *SourceBuffer,
+ IN UINTN Length
+ )
+{
+ if (!MmIsBufferOutsideMmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)DestinationBuffer, Length)) {
+ DEBUG ((DEBUG_ERROR, "MmCopyMemFromMmram: Security Violation: Destination (0x%x), Length (0x%x)\n",
+ DestinationBuffer, Length));
+ return EFI_SECURITY_VIOLATION;
+ }
+ CopyMem (DestinationBuffer, SourceBuffer, Length);
+ return EFI_SUCCESS;
+}
+
+/**
+ Copies a source buffer (NON-MMRAM) to a destination buffer (NON-MMRAM).
+
+ This function copies a source buffer (non-MMRAM) to a destination buffer (MMRAM).
+ It checks if source buffer and destination buffer are valid per processor architecture and not overlap with MMRAM.
+ If the check passes, it copies memory and returns EFI_SUCCESS.
+ If the check fails, it returns EFI_SECURITY_VIOLATION.
+ The implementation must be reentrant, and it must handle the case where source buffer overlaps destination buffer.
+
+ @param DestinationBuffer The pointer to the destination buffer of the memory copy.
+ @param SourceBuffer The pointer to the source buffer of the memory copy.
+ @param Length The number of bytes to copy from SourceBuffer to DestinationBuffer.
+
+ @retval EFI_SECURITY_VIOLATION The DestinationBuffer is invalid per processor architecture or overlap with MMRAM.
+ @retval EFI_SECURITY_VIOLATION The SourceBuffer is invalid per processor architecture or overlap with MMRAM.
+ @retval EFI_SUCCESS Memory is copied.
+
+**/
+EFI_STATUS
+EFIAPI
+MmCopyMem (
+ OUT VOID *DestinationBuffer,
+ IN CONST VOID *SourceBuffer,
+ IN UINTN Length
+ )
+{
+ if (!MmIsBufferOutsideMmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)DestinationBuffer, Length)) {
+ DEBUG ((DEBUG_ERROR, "MmCopyMem: Security Violation: Destination (0x%x), Length (0x%x)\n",
+ DestinationBuffer, Length));
+ return EFI_SECURITY_VIOLATION;
+ }
+ if (!MmIsBufferOutsideMmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)SourceBuffer, Length)) {
+ DEBUG ((DEBUG_ERROR, "MmCopyMem: Security Violation: Source (0x%x), Length (0x%x)\n", SourceBuffer, Length));
+ return EFI_SECURITY_VIOLATION;
+ }
+ CopyMem (DestinationBuffer, SourceBuffer, Length);
+ return EFI_SUCCESS;
+}
+
+/**
+ Fills a target buffer (NON-MMRAM) with a byte value.
+
+ This function fills a target buffer (non-MMRAM) with a byte value.
+ It checks if target buffer is valid per processor architecture and not overlap with MMRAM.
+ If the check passes, it fills memory and returns EFI_SUCCESS.
+ If the check fails, it returns EFI_SECURITY_VIOLATION.
+
+ @param Buffer The memory to set.
+ @param Length The number of bytes to set.
+ @param Value The value with which to fill Length bytes of Buffer.
+
+ @retval EFI_SECURITY_VIOLATION The Buffer is invalid per processor architecture or overlap with MMRAM.
+ @retval EFI_SUCCESS Memory is set.
+
+**/
+EFI_STATUS
+EFIAPI
+MmSetMem (
+ OUT VOID *Buffer,
+ IN UINTN Length,
+ IN UINT8 Value
+ )
+{
+ if (!MmIsBufferOutsideMmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, Length)) {
+ DEBUG ((DEBUG_ERROR, "MmSetMem: Security Violation: Source (0x%x), Length (0x%x)\n", Buffer, Length));
+ return EFI_SECURITY_VIOLATION;
+ }
+ SetMem (Buffer, Length, Value);
+ return EFI_SUCCESS;
+}
+
+/**
+ The constructor function initializes the Mm Mem library
+
+ @param [in] ImageHandle The firmware allocated handle for the EFI image.
+ @param [in] MmSystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+MemLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_MM_SYSTEM_TABLE *MmSystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Calculate and save maximum support address
+ //
+ MmMemLibInternalCalculateMaximumSupportAddress ();
+
+ //
+ // Initialize cached Mmram Ranges from HOB.
+ //
+ Status = MmMemLibInternalPopulateMmramRanges ();
+
+ return Status;
+}
+
+/**
+ Destructor for Mm Mem library.
+
+ @param ImageHandle The image handle of the process.
+ @param MmSystemTable The EFI System Table pointer.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+MemLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_MM_SYSTEM_TABLE *MmSystemTable
+ )
+{
+
+ //
+ // Deinitialize cached Mmram Ranges.
+ //
+ MmMemLibInternalFreeMmramRanges ();
+
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.inf
new file mode 100644
index 00000000..bc2f3eea
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.inf
@@ -0,0 +1,55 @@
+## @file
+# Instance of MM memory check library.
+#
+# MM memory check library library implementation. This library consumes MM_ACCESS_PROTOCOL
+# to get MMRAM information. In order to use this library instance, the platform should produce
+# all MMRAM range via MM_ACCESS_PROTOCOL, including the range for firmware (like MM Core
+# and MM driver) and/or specific dedicated hardware.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+# Copyright (c) Microsoft Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001A
+ BASE_NAME = MemLib
+ FILE_GUID = EA355F14-6409-4716-829F-37B3BC7C7F26
+ MODULE_TYPE = MM_STANDALONE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x00010032
+ LIBRARY_CLASS = MemLib|MM_STANDALONE MM_CORE_STANDALONE
+ CONSTRUCTOR = MemLibConstructor
+ DESTRUCTOR = MemLibDestructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 AARCH64
+#
+
+[Sources.Common]
+ StandaloneMmMemLib.c
+
+[Sources.IA32, Sources.X64]
+ X86StandaloneMmMemLibInternal.c
+
+[Sources.AARCH64]
+ AArch64/StandaloneMmMemLibInternal.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ StandaloneMmPkg/StandaloneMmPkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ HobLib
+ MemoryAllocationLib
+
+[Guids]
+ gMmCoreDataHobGuid ## SOMETIMES_CONSUMES ## HOB
+ gEfiMmPeiMmramMemoryReserveGuid ## SOMETIMES_CONSUMES ## HOB
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/X86StandaloneMmMemLibInternal.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/X86StandaloneMmMemLibInternal.c
new file mode 100644
index 00000000..530105a6
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/X86StandaloneMmMemLibInternal.c
@@ -0,0 +1,155 @@
+/** @file
+ Internal ARCH Specific file of MM memory check library.
+
+ MM memory check library implementation. This library consumes MM_ACCESS_PROTOCOL
+ to get MMRAM information. In order to use this library instance, the platform should produce
+ all MMRAM range via MM_ACCESS_PROTOCOL, including the range for firmware (like MM Core
+ and MM driver) and/or specific dedicated hardware.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+ Copyright (c) Microsoft Corporation.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <PiMm.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+
+#include <Guid/MmCoreData.h>
+#include <Guid/MmramMemoryReserve.h>
+
+//
+// Maximum support address used to check input buffer
+//
+extern EFI_PHYSICAL_ADDRESS mMmMemLibInternalMaximumSupportAddress;
+extern EFI_MMRAM_DESCRIPTOR *mMmMemLibInternalMmramRanges;
+extern UINTN mMmMemLibInternalMmramCount;
+
+/**
+ Calculate and save the maximum support address.
+
+**/
+VOID
+MmMemLibInternalCalculateMaximumSupportAddress (
+ VOID
+ )
+{
+ VOID *Hob;
+ UINT32 RegEax;
+ UINT8 PhysicalAddressBits;
+
+ //
+ // Get physical address bits supported.
+ //
+ Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
+ if (Hob != NULL) {
+ PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
+ } else {
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= 0x80000008) {
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
+ PhysicalAddressBits = (UINT8) RegEax;
+ } else {
+ PhysicalAddressBits = 36;
+ }
+ }
+ //
+ // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
+ //
+ ASSERT (PhysicalAddressBits <= 52);
+ if (PhysicalAddressBits > 48) {
+ PhysicalAddressBits = 48;
+ }
+
+ //
+ // Save the maximum support address in one global variable
+ //
+ mMmMemLibInternalMaximumSupportAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)(LShiftU64 (1, PhysicalAddressBits) - 1);
+ DEBUG ((DEBUG_INFO, "mMmMemLibInternalMaximumSupportAddress = 0x%lx\n", mMmMemLibInternalMaximumSupportAddress));
+}
+
+/**
+ Initialize cached Mmram Ranges from HOB.
+
+ @retval EFI_UNSUPPORTED The routine is unable to extract MMRAM information.
+ @retval EFI_SUCCESS MmRanges are populated successfully.
+
+**/
+EFI_STATUS
+MmMemLibInternalPopulateMmramRanges (
+ VOID
+ )
+{
+ VOID *HobStart;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ MM_CORE_DATA_HOB_DATA *DataInHob;
+ MM_CORE_PRIVATE_DATA *MmCorePrivateData;
+ EFI_HOB_GUID_TYPE *MmramRangesHob;
+ EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *MmramRangesHobData;
+ EFI_MMRAM_DESCRIPTOR *MmramDescriptors;
+
+ HobStart = GetHobList ();
+ DEBUG ((DEBUG_INFO, "%a - 0x%x\n", __FUNCTION__, HobStart));
+
+ //
+ // Extract MM Core Private context from the Hob. If absent search for
+ // a Hob containing the MMRAM ranges
+ //
+ GuidHob = GetNextGuidHob (&gMmCoreDataHobGuid, HobStart);
+ if (GuidHob == NULL) {
+ MmramRangesHob = GetFirstGuidHob (&gEfiMmPeiMmramMemoryReserveGuid);
+ if (MmramRangesHob == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ MmramRangesHobData = GET_GUID_HOB_DATA (MmramRangesHob);
+ if (MmramRangesHobData == NULL || MmramRangesHobData->Descriptor == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ mMmMemLibInternalMmramCount = MmramRangesHobData->NumberOfMmReservedRegions;
+ MmramDescriptors = MmramRangesHobData->Descriptor;
+ } else {
+ DataInHob = GET_GUID_HOB_DATA (GuidHob);
+ if (DataInHob == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ MmCorePrivateData = (MM_CORE_PRIVATE_DATA *) (UINTN) DataInHob->Address;
+ if (MmCorePrivateData == NULL || MmCorePrivateData->MmramRanges == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ mMmMemLibInternalMmramCount = (UINTN) MmCorePrivateData->MmramRangeCount;
+ MmramDescriptors = (EFI_MMRAM_DESCRIPTOR *) (UINTN) MmCorePrivateData->MmramRanges;
+ }
+
+ mMmMemLibInternalMmramRanges = AllocatePool (mMmMemLibInternalMmramCount * sizeof (EFI_MMRAM_DESCRIPTOR));
+ if (mMmMemLibInternalMmramRanges) {
+ CopyMem (mMmMemLibInternalMmramRanges,
+ MmramDescriptors,
+ mMmMemLibInternalMmramCount * sizeof (EFI_MMRAM_DESCRIPTOR));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Deinitialize cached Mmram Ranges.
+
+**/
+VOID
+MmMemLibInternalFreeMmramRanges (
+ VOID
+ )
+{
+ if (mMmMemLibInternalMmramRanges != NULL) {
+ FreePool (mMmMemLibInternalMmramRanges);
+ }
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemoryAllocationLib/StandaloneMmMemoryAllocationLib.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemoryAllocationLib/StandaloneMmMemoryAllocationLib.c
new file mode 100644
index 00000000..2ee32dc4
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemoryAllocationLib/StandaloneMmMemoryAllocationLib.c
@@ -0,0 +1,815 @@
+/** @file
+ Support routines for memory allocation routines based on Standalone MM Core internal functions.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiMm.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/MmServicesTableLib.h>
+
+/**
+ Allocates one or more 4KB pages of a certain memory type.
+
+ Allocates the number of 4KB pages of a certain memory type and returns a pointer to the allocated
+ buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL is returned.
+ If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocatePages (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Memory;
+
+ if (Pages == 0) {
+ return NULL;
+ }
+
+ Status = gMmst->MmAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ return (VOID *)(UINTN)Memory;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiBootServicesData.
+
+ Allocates the number of 4KB pages of type EfiBootServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePages (
+ IN UINTN Pages
+ )
+{
+ return InternalAllocatePages (EfiRuntimeServicesData, Pages);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData.
+
+ Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePages (
+ IN UINTN Pages
+ )
+{
+ return InternalAllocatePages (EfiRuntimeServicesData, Pages);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType.
+
+ Allocates the number of 4KB pages of type EfiReservedMemoryType and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPages (
+ IN UINTN Pages
+ )
+{
+ return NULL;
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the page allocation
+ functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
+ must have been allocated on a previous call to the page allocation services of the Memory
+ Allocation Library. If it is not possible to free allocated pages, then this function will
+ perform no actions.
+
+ If Buffer was not allocated with a page allocation function in the Memory Allocation Library,
+ then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer Pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreePages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Pages != 0);
+ Status = gMmst->MmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN)Buffer, Pages);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Allocates one or more 4KB pages of a certain memory type at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of a certain memory type with an alignment
+ specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is returned.
+ If there is not enough memory at the specified alignment remaining to satisfy the request, then
+ NULL is returned.
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateAlignedPages (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Memory;
+ UINTN AlignedMemory;
+ UINTN AlignmentMask;
+ UINTN UnalignedPages;
+ UINTN RealPages;
+
+ //
+ // Alignment must be a power of two or zero.
+ //
+ ASSERT ((Alignment & (Alignment - 1)) == 0);
+
+ if (Pages == 0) {
+ return NULL;
+ }
+ if (Alignment > EFI_PAGE_SIZE) {
+ //
+ // Calculate the total number of pages since alignment is larger than page size.
+ //
+ AlignmentMask = Alignment - 1;
+ RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);
+ //
+ // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
+ //
+ ASSERT (RealPages > Pages);
+
+ Status = gMmst->MmAllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ AlignedMemory = ((UINTN)Memory + AlignmentMask) & ~AlignmentMask;
+ UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);
+ if (UnalignedPages > 0) {
+ //
+ // Free first unaligned page(s).
+ //
+ Status = gMmst->MmFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+ Memory = (EFI_PHYSICAL_ADDRESS)(AlignedMemory + EFI_PAGES_TO_SIZE (Pages));
+ UnalignedPages = RealPages - Pages - UnalignedPages;
+ if (UnalignedPages > 0) {
+ //
+ // Free last unaligned page(s).
+ //
+ Status = gMmst->MmFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+ } else {
+ //
+ // Do not over-allocate pages in this case.
+ //
+ Status = gMmst->MmAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ AlignedMemory = (UINTN) Memory;
+ }
+ return (VOID *) AlignedMemory;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ return InternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedRuntimePages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ return InternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiReservedMemoryType with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedReservedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ return NULL;
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the aligned page
+ allocation functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
+ must have been allocated on a previous call to the aligned page allocation services of the Memory
+ Allocation Library. If it is not possible to free allocated pages, then this function will
+ perform no actions.
+
+ If Buffer was not allocated with an aligned page allocation function in the Memory Allocation
+ Library, then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer Pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreeAlignedPages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Pages != 0);
+ Status = gMmst->MmFreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, Pages);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Allocates a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocatePool (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN AllocationSize
+ )
+{
+ EFI_STATUS Status;
+ VOID *Memory;
+
+ Memory = NULL;
+
+ Status = gMmst->MmAllocatePool (MemoryType, AllocationSize, &Memory);
+ if (EFI_ERROR (Status)) {
+ Memory = NULL;
+ }
+ return Memory;
+}
+
+/**
+ Allocates a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePool (
+ IN UINTN AllocationSize
+ )
+{
+ return InternalAllocatePool (EfiRuntimeServicesData, AllocationSize);
+}
+
+/**
+ Allocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePool (
+ IN UINTN AllocationSize
+ )
+{
+ return InternalAllocatePool (EfiRuntimeServicesData, AllocationSize);
+}
+
+/**
+ Allocates a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPool (
+ IN UINTN AllocationSize
+ )
+{
+ return NULL;
+}
+
+/**
+ Allocates and zeros a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type, clears the buffer
+ with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a valid
+ buffer of 0 size is returned. If there is not enough memory remaining to satisfy the request,
+ then NULL is returned.
+
+ @param PoolType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateZeroPool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Memory;
+
+ Memory = InternalAllocatePool (PoolType, AllocationSize);
+ if (Memory != NULL) {
+ Memory = ZeroMem (Memory, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ return InternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize);
+}
+
+/**
+ Allocates and zeros a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ return InternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize);
+}
+
+/**
+ Allocates and zeros a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ return NULL;
+}
+
+/**
+ Copies a buffer to an allocated buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param PoolType The type of pool to allocate.
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateCopyPool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *Memory;
+
+ ASSERT (Buffer != NULL);
+ ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1));
+
+ Memory = InternalAllocatePool (PoolType, AllocationSize);
+ if (Memory != NULL) {
+ Memory = CopyMem (Memory, Buffer, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ return InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ return InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ return NULL;
+}
+
+/**
+ Reallocates a buffer of a specified memory type.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of the type
+ specified by PoolType. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param PoolType The type of pool to allocate.
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalReallocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalAllocateZeroPool (PoolType, NewSize);
+ if (NewBuffer != NULL && OldBuffer != NULL) {
+ CopyMem (NewBuffer, OldBuffer, MIN (OldSize, NewSize));
+ FreePool (OldBuffer);
+ }
+ return NewBuffer;
+}
+
+/**
+ Reallocates a buffer of type EfiBootServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiBootServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocatePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ return InternalReallocatePool (EfiRuntimeServicesData, OldSize, NewSize, OldBuffer);
+}
+
+/**
+ Reallocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateRuntimePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ return InternalReallocatePool (EfiRuntimeServicesData, OldSize, NewSize, OldBuffer);
+}
+
+/**
+ Reallocates a buffer of type EfiReservedMemoryType.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiReservedMemoryType. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateReservedPool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ return NULL;
+}
+
+/**
+ Frees a buffer that was previously allocated with one of the pool allocation functions in the
+ Memory Allocation Library.
+
+ Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the
+ pool allocation services of the Memory Allocation Library. If it is not possible to free pool
+ resources, then this function will perform no actions.
+
+ If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
+ then ASSERT().
+
+ @param Buffer Pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+FreePool (
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gMmst->MmFreePool (Buffer);
+ ASSERT_EFI_ERROR (Status);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemoryAllocationLib/StandaloneMmMemoryAllocationLib.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemoryAllocationLib/StandaloneMmMemoryAllocationLib.inf
new file mode 100644
index 00000000..51fce073
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemoryAllocationLib/StandaloneMmMemoryAllocationLib.inf
@@ -0,0 +1,37 @@
+## @file
+# Memory Allocation Library instance standalone MM modules.
+#
+# Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+# Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = MemoryAllocationLib
+ FILE_GUID = 54646378-A9DC-473F-9BE1-BD027C4C76DE
+ MODULE_TYPE = MM_STANDALONE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x00010032
+ LIBRARY_CLASS = MemoryAllocationLib|MM_STANDALONE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+ StandaloneMmMemoryAllocationLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ StandaloneMmPkg/StandaloneMmPkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ MmServicesTableLib
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/AArch64/StandaloneMmPeCoffExtraActionLib.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/AArch64/StandaloneMmPeCoffExtraActionLib.c
new file mode 100644
index 00000000..2db7551d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/AArch64/StandaloneMmPeCoffExtraActionLib.c
@@ -0,0 +1,211 @@
+/**@file
+
+Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
+Portions copyright (c) 2011 - 2018, ARM Ltd. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Library/ArmMmuLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/PeCoffExtraActionLib.h>
+
+typedef RETURN_STATUS (*REGION_PERMISSION_UPDATE_FUNC) (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+STATIC
+RETURN_STATUS
+UpdatePeCoffPermissions (
+ IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
+ IN REGION_PERMISSION_UPDATE_FUNC NoExecUpdater,
+ IN REGION_PERMISSION_UPDATE_FUNC ReadOnlyUpdater
+ )
+{
+ RETURN_STATUS Status;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
+ UINTN Size;
+ UINTN ReadSize;
+ UINT32 SectionHeaderOffset;
+ UINTN NumberOfSections;
+ UINTN Index;
+ EFI_IMAGE_SECTION_HEADER SectionHeader;
+ PE_COFF_LOADER_IMAGE_CONTEXT TmpContext;
+ EFI_PHYSICAL_ADDRESS Base;
+
+ //
+ // We need to copy ImageContext since PeCoffLoaderGetImageInfo ()
+ // will mangle the ImageAddress field
+ //
+ CopyMem (&TmpContext, ImageContext, sizeof (TmpContext));
+
+ if (TmpContext.PeCoffHeaderOffset == 0) {
+ Status = PeCoffLoaderGetImageInfo (&TmpContext);
+ if (RETURN_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: PeCoffLoaderGetImageInfo () failed (Status = %r)\n",
+ __FUNCTION__, Status));
+ return Status;
+ }
+ }
+
+ if (TmpContext.IsTeImage &&
+ TmpContext.ImageAddress == ImageContext->ImageAddress) {
+ DEBUG ((DEBUG_INFO, "%a: ignoring XIP TE image at 0x%lx\n", __FUNCTION__,
+ ImageContext->ImageAddress));
+ return RETURN_SUCCESS;
+ }
+
+ if (TmpContext.SectionAlignment < EFI_PAGE_SIZE) {
+ //
+ // The sections need to be at least 4 KB aligned, since that is the
+ // granularity at which we can tighten permissions. So just clear the
+ // noexec permissions on the entire region.
+ //
+ if (!TmpContext.IsTeImage) {
+ DEBUG ((DEBUG_WARN,
+ "%a: non-TE Image at 0x%lx has SectionAlignment < 4 KB (%lu)\n",
+ __FUNCTION__, ImageContext->ImageAddress, TmpContext.SectionAlignment));
+ }
+ Base = ImageContext->ImageAddress & ~(EFI_PAGE_SIZE - 1);
+ Size = ImageContext->ImageAddress - Base + ImageContext->ImageSize;
+ return NoExecUpdater (Base, ALIGN_VALUE (Size, EFI_PAGE_SIZE));
+ }
+
+ //
+ // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
+ // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
+ // determines if this is a PE32 or PE32+ image. The magic is in the same
+ // location in both images.
+ //
+ Hdr.Union = &HdrData;
+ Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
+ ReadSize = Size;
+ Status = TmpContext.ImageRead (TmpContext.Handle,
+ TmpContext.PeCoffHeaderOffset, &Size, Hdr.Pe32);
+ if (RETURN_ERROR (Status) || (Size != ReadSize)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: TmpContext.ImageRead () failed (Status = %r)\n",
+ __FUNCTION__, Status));
+ return Status;
+ }
+
+ ASSERT (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE);
+
+ SectionHeaderOffset = TmpContext.PeCoffHeaderOffset + sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER);
+ NumberOfSections = (UINTN)(Hdr.Pe32->FileHeader.NumberOfSections);
+
+ switch (Hdr.Pe32->OptionalHeader.Magic) {
+ case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC:
+ SectionHeaderOffset += Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
+ break;
+ case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC:
+ SectionHeaderOffset += Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader;
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+
+ //
+ // Iterate over the sections
+ //
+ for (Index = 0; Index < NumberOfSections; Index++) {
+ //
+ // Read section header from file
+ //
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);
+ ReadSize = Size;
+ Status = TmpContext.ImageRead (TmpContext.Handle, SectionHeaderOffset,
+ &Size, &SectionHeader);
+ if (RETURN_ERROR (Status) || (Size != ReadSize)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: TmpContext.ImageRead () failed (Status = %r)\n",
+ __FUNCTION__, Status));
+ return Status;
+ }
+
+ Base = TmpContext.ImageAddress + SectionHeader.VirtualAddress;
+
+ if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) {
+
+ if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_WRITE) == 0) {
+
+ DEBUG ((DEBUG_INFO,
+ "%a: Mapping section %d of image at 0x%lx with RO-XN permissions and size 0x%x\n",
+ __FUNCTION__, Index, Base, SectionHeader.Misc.VirtualSize));
+ ReadOnlyUpdater (Base, SectionHeader.Misc.VirtualSize);
+ } else {
+ DEBUG ((DEBUG_WARN,
+ "%a: Mapping section %d of image at 0x%lx with RW-XN permissions and size 0x%x\n",
+ __FUNCTION__, Index, Base, SectionHeader.Misc.VirtualSize));
+ }
+ } else {
+ DEBUG ((DEBUG_INFO,
+ "%a: Mapping section %d of image at 0x%lx with RO-X permissions and size 0x%x\n",
+ __FUNCTION__, Index, Base, SectionHeader.Misc.VirtualSize));
+ ReadOnlyUpdater (Base, SectionHeader.Misc.VirtualSize);
+ NoExecUpdater (Base, SectionHeader.Misc.VirtualSize);
+ }
+
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
+ }
+ return RETURN_SUCCESS;
+}
+
+/**
+ Performs additional actions after a PE/COFF image has been loaded and relocated.
+
+ If ImageContext is NULL, then ASSERT().
+
+ @param ImageContext Pointer to the image context structure that describes the
+ PE/COFF image that has already been loaded and relocated.
+
+**/
+VOID
+EFIAPI
+PeCoffLoaderRelocateImageExtraAction (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ UpdatePeCoffPermissions (
+ ImageContext,
+ ArmClearMemoryRegionNoExec,
+ ArmSetMemoryRegionReadOnly
+ );
+}
+
+
+
+/**
+ Performs additional actions just before a PE/COFF image is unloaded. Any resources
+ that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed.
+
+ If ImageContext is NULL, then ASSERT().
+
+ @param ImageContext Pointer to the image context structure that describes the
+ PE/COFF image that is being unloaded.
+
+**/
+VOID
+EFIAPI
+PeCoffLoaderUnloadImageExtraAction (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ UpdatePeCoffPermissions (
+ ImageContext,
+ ArmSetMemoryRegionNoExec,
+ ArmClearMemoryRegionReadOnly
+ );
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.inf
new file mode 100644
index 00000000..0b4a4509
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.inf
@@ -0,0 +1,36 @@
+#/** @file
+# PeCoff extra action library for DXE phase that run Unix emulator.
+#
+# Lib to provide memory journal status code reporting Routines
+# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
+# Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x0001000A
+ BASE_NAME = StandaloneMmPeCoffExtraActionLib
+ FILE_GUID = 8B40543B-9588-48F8-840C-5A60E6DB1B03
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PeCoffExtraActionLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = ARM
+#
+
+[Sources.common]
+ AArch64/StandaloneMmPeCoffExtraActionLib.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ MdePkg/MdePkg.dec
+ StandaloneMmPkg/StandaloneMmPkg.dec
+
+[LibraryClasses]
+ StandaloneMmMmuLib
+ PcdLib
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.c
new file mode 100644
index 00000000..b09cfd24
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.c
@@ -0,0 +1,47 @@
+/** @file
+ Runtime DXE part corresponding to StandaloneMM variable module.
+
+This module installs variable arch protocol and variable write arch protocol
+to StandaloneMM runtime variable service.
+
+Copyright (c) 2019 - 2021, Arm Ltd. All rights reserved.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+/**
+ The constructor function installs variable arch protocol and variable
+ write arch protocol to StandaloneMM runtime variable service
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the Management mode System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableMmDependencyLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiSmmVariableProtocolGuid,
+ NULL,
+ &gSmmVariableWriteGuid,
+ NULL,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.inf
new file mode 100644
index 00000000..7e23987f
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.inf
@@ -0,0 +1,41 @@
+## @file
+# Runtime DXE part corresponding to StandaloneMM variable module.
+#
+# This module installs variable arch protocol and variable write arch protocol
+# to StandaloneMM runtime variable service.
+#
+# Copyright (c) 2019 - 2021, Arm Ltd. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001A
+ BASE_NAME = VariableMmDependency
+ FILE_GUID = 64BC4129-778E-4867-BA07-13999A4DEC3F
+ MODULE_TYPE = DXE_DRIVER
+ LIBRARY_CLASS = NULL
+ CONSTRUCTOR = VariableMmDependencyLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = AARCH64
+#
+#
+
+[Sources]
+ VariableMmDependency.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[Protocols]
+ gEfiSmmVariableProtocolGuid ## PRODUCES
+
+[Guids]
+ gSmmVariableWriteGuid ## PRODUCES ## GUID # Install protocol
+
+[Depex]
+ TRUE