summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/StandaloneMmPkg')
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Dependency.c383
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Dispatcher.c902
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/FwVol.c181
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Handle.c527
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/InstallConfigurationTable.c172
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Locate.c490
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Mmi.c331
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Notify.c197
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Page.c378
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Pool.c287
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/StandaloneMmCore.c661
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/StandaloneMmCore.h853
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/StandaloneMmCore.inf81
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/StandaloneMmCorePrivateData.h60
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/EventHandle.c250
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/StandaloneMmCpu.c250
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/StandaloneMmCpu.h81
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/StandaloneMmCpu.inf52
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Guid/MmCoreData.h127
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Guid/MmFvDispatch.h33
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Guid/MmramMemoryReserve.h56
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Guid/MpInformation.h35
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Library/AArch64/StandaloneMmCoreEntryPoint.h216
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Library/FvLib.h104
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Library/StandaloneMmCoreEntryPoint.h95
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Library/StandaloneMmMemLib.h134
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/StandaloneMm.h29
-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
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/StandaloneMmPkg.ci.yaml84
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/StandaloneMmPkg.dec50
-rw-r--r--src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/StandaloneMmPkg.dsc140
57 files changed, 13206 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Dependency.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Dependency.c
new file mode 100644
index 00000000..7c2c44cb
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Dependency.c
@@ -0,0 +1,383 @@
+/** @file
+ MM Driver Dispatcher Dependency Evaluator
+
+ This routine evaluates a dependency expression (DEPENDENCY_EXPRESSION) to determine
+ if a driver can be scheduled for execution. The criteria for
+ scheduling is that the dependency expression is satisfied.
+
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "StandaloneMmCore.h"
+
+///
+/// EFI_DEP_REPLACE_TRUE - Used to dynamically patch the dependency expression
+/// to save time. A EFI_DEP_PUSH is evaluated one an
+/// replaced with EFI_DEP_REPLACE_TRUE. If PI spec's Vol 2
+/// Driver Execution Environment Core Interface use 0xff
+/// as new DEPEX opcode. EFI_DEP_REPLACE_TRUE should be
+/// defined to a new value that is not conflicting with PI spec.
+///
+#define EFI_DEP_REPLACE_TRUE 0xff
+
+///
+/// Define the initial size of the dependency expression evaluation stack
+///
+#define DEPEX_STACK_SIZE_INCREMENT 0x1000
+
+//
+// Global stack used to evaluate dependency expressions
+//
+BOOLEAN *mDepexEvaluationStack = NULL;
+BOOLEAN *mDepexEvaluationStackEnd = NULL;
+BOOLEAN *mDepexEvaluationStackPointer = NULL;
+
+/**
+ Grow size of the Depex stack
+
+ @retval EFI_SUCCESS Stack successfully growed.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+GrowDepexStack (
+ VOID
+ )
+{
+ BOOLEAN *NewStack;
+ UINTN Size;
+
+ Size = DEPEX_STACK_SIZE_INCREMENT;
+ if (mDepexEvaluationStack != NULL) {
+ Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack);
+ }
+
+ NewStack = AllocatePool (Size * sizeof (BOOLEAN));
+ if (NewStack == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (mDepexEvaluationStack != NULL) {
+ //
+ // Copy to Old Stack to the New Stack
+ //
+ CopyMem (
+ NewStack,
+ mDepexEvaluationStack,
+ (mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof (BOOLEAN)
+ );
+
+ //
+ // Free The Old Stack
+ //
+ FreePool (mDepexEvaluationStack);
+ }
+
+ //
+ // Make the Stack pointer point to the old data in the new stack
+ //
+ mDepexEvaluationStackPointer = NewStack + (mDepexEvaluationStackPointer - mDepexEvaluationStack);
+ mDepexEvaluationStack = NewStack;
+ mDepexEvaluationStackEnd = NewStack + Size;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Push an element onto the Boolean Stack.
+
+ @param Value BOOLEAN to push.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushBool (
+ IN BOOLEAN Value
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Check for a stack overflow condition
+ //
+ if (mDepexEvaluationStackPointer == mDepexEvaluationStackEnd) {
+ //
+ // Grow the stack
+ //
+ Status = GrowDepexStack ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Push the item onto the stack
+ //
+ *mDepexEvaluationStackPointer = Value;
+ mDepexEvaluationStackPointer++;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Pop an element from the Boolean stack.
+
+ @param Value BOOLEAN to pop.
+
+ @retval EFI_SUCCESS The value was popped onto the stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack.
+
+**/
+EFI_STATUS
+PopBool (
+ OUT BOOLEAN *Value
+ )
+{
+ //
+ // Check for a stack underflow condition
+ //
+ if (mDepexEvaluationStackPointer == mDepexEvaluationStack) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Pop the item off the stack
+ //
+ mDepexEvaluationStackPointer--;
+ *Value = *mDepexEvaluationStackPointer;
+ return EFI_SUCCESS;
+}
+
+/**
+ This is the POSTFIX version of the dependency evaluator. This code does
+ not need to handle Before or After, as it is not valid to call this
+ routine in this case. POSTFIX means all the math is done on top of the stack.
+
+ @param DriverEntry DriverEntry element to update.
+
+ @retval TRUE If driver is ready to run.
+ @retval FALSE If driver is not ready to run or some fatal error
+ was found.
+
+**/
+BOOLEAN
+MmIsSchedulable (
+ IN EFI_MM_DRIVER_ENTRY *DriverEntry
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Iterator;
+ BOOLEAN Operator;
+ BOOLEAN Operator2;
+ EFI_GUID DriverGuid;
+ VOID *Interface;
+
+ Operator = FALSE;
+ Operator2 = FALSE;
+
+ if (DriverEntry->After || DriverEntry->Before) {
+ //
+ // If Before or After Depex skip as MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter ()
+ // processes them.
+ //
+ return FALSE;
+ }
+
+ DEBUG ((DEBUG_DISPATCH, "Evaluate MM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+
+ if (DriverEntry->Depex == NULL) {
+ //
+ // A NULL Depex means that the MM driver is not built correctly.
+ // All MM drivers must have a valid depex expression.
+ //
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Depex is empty)\n"));
+ ASSERT (FALSE);
+ return FALSE;
+ }
+
+ //
+ // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by
+ // incorrectly formed DEPEX expressions
+ //
+ mDepexEvaluationStackPointer = mDepexEvaluationStack;
+
+
+ Iterator = DriverEntry->Depex;
+
+ while (TRUE) {
+ //
+ // Check to see if we are attempting to fetch dependency expression instructions
+ // past the end of the dependency expression.
+ //
+ if (((UINTN)Iterator - (UINTN)DriverEntry->Depex) >= DriverEntry->DepexSize) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Attempt to fetch past end of depex)\n"));
+ return FALSE;
+ }
+
+ //
+ // Look at the opcode of the dependency expression instruction.
+ //
+ switch (*Iterator) {
+ case EFI_DEP_BEFORE:
+ case EFI_DEP_AFTER:
+ //
+ // For a well-formed Dependency Expression, the code should never get here.
+ // The BEFORE and AFTER are processed prior to this routine's invocation.
+ // If the code flow arrives at this point, there was a BEFORE or AFTER
+ // that were not the first opcodes.
+ //
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected BEFORE or AFTER opcode)\n"));
+ ASSERT (FALSE);
+
+ case EFI_DEP_PUSH:
+ //
+ // Push operator is followed by a GUID. Test to see if the GUID protocol
+ // is installed and push the boolean result on the stack.
+ //
+ CopyMem (&DriverGuid, Iterator + 1, sizeof (EFI_GUID));
+
+ Status = MmLocateProtocol (&DriverGuid, NULL, &Interface);
+ if (EFI_ERROR (Status) && (mEfiSystemTable != NULL)) {
+ //
+ // For MM Driver, it may depend on uefi protocols
+ //
+ Status = mEfiSystemTable->BootServices->LocateProtocol (&DriverGuid, NULL, &Interface);
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = FALSE\n", &DriverGuid));
+ Status = PushBool (FALSE);
+ } else {
+ DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = TRUE\n", &DriverGuid));
+ *Iterator = EFI_DEP_REPLACE_TRUE;
+ Status = PushBool (TRUE);
+ }
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Iterator += sizeof (EFI_GUID);
+ break;
+
+ case EFI_DEP_AND:
+ DEBUG ((DEBUG_DISPATCH, " AND\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PopBool (&Operator2);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PushBool ((BOOLEAN)(Operator && Operator2));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_OR:
+ DEBUG ((DEBUG_DISPATCH, " OR\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PopBool (&Operator2);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PushBool ((BOOLEAN)(Operator || Operator2));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_NOT:
+ DEBUG ((DEBUG_DISPATCH, " NOT\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PushBool ((BOOLEAN)(!Operator));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_TRUE:
+ DEBUG ((DEBUG_DISPATCH, " TRUE\n"));
+ Status = PushBool (TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_FALSE:
+ DEBUG ((DEBUG_DISPATCH, " FALSE\n"));
+ Status = PushBool (FALSE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_END:
+ DEBUG ((DEBUG_DISPATCH, " END\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ DEBUG ((DEBUG_DISPATCH, " RESULT = %a\n", Operator ? "TRUE" : "FALSE"));
+ return Operator;
+
+ case EFI_DEP_REPLACE_TRUE:
+ CopyMem (&DriverGuid, Iterator + 1, sizeof (EFI_GUID));
+ DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = TRUE\n", &DriverGuid));
+ Status = PushBool (TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Iterator += sizeof (EFI_GUID);
+ break;
+
+ default:
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unknown opcode)\n"));
+ goto Done;
+ }
+
+ //
+ // Skip over the Dependency Op Code we just processed in the switch.
+ // The math is done out of order, but it should not matter. That is
+ // we may add in the sizeof (EFI_GUID) before we account for the OP Code.
+ // This is not an issue, since we just need the correct end result. You
+ // need to be careful using Iterator in the loop as its intermediate value
+ // may be strange.
+ //
+ Iterator++;
+ }
+
+Done:
+ return FALSE;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Dispatcher.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Dispatcher.c
new file mode 100644
index 00000000..4888c136
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Dispatcher.c
@@ -0,0 +1,902 @@
+/** @file
+ MM Driver Dispatcher.
+
+ Step #1 - When a FV protocol is added to the system every driver in the FV
+ is added to the mDiscoveredList. The Before, and After Depex are
+ pre-processed as drivers are added to the mDiscoveredList. If an Apriori
+ file exists in the FV those drivers are addeded to the
+ mScheduledQueue. The mFwVolList is used to make sure a
+ FV is only processed once.
+
+ Step #2 - Dispatch. Remove driver from the mScheduledQueue and load and
+ start it. After mScheduledQueue is drained check the
+ mDiscoveredList to see if any item has a Depex that is ready to
+ be placed on the mScheduledQueue.
+
+ Step #3 - Adding to the mScheduledQueue requires that you process Before
+ and After dependencies. This is done recursively as the call to add
+ to the mScheduledQueue checks for Before Depexes and recursively
+ adds all Before Depexes. It then adds the item that was passed in
+ and then processess the After dependencies by recursively calling
+ the routine.
+
+ Dispatcher Rules:
+ The rules for the dispatcher are similar to the DXE dispatcher.
+
+ The rules for DXE dispatcher are in chapter 10 of the DXE CIS. Figure 10-3
+ is the state diagram for the DXE dispatcher
+
+ Depex - Dependency Expresion.
+
+ Copyright (c) 2014, Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "StandaloneMmCore.h"
+
+//
+// MM Dispatcher Data structures
+//
+#define KNOWN_FWVOL_SIGNATURE SIGNATURE_32('k','n','o','w')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link; // mFwVolList
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+} KNOWN_FWVOL;
+
+//
+// Function Prototypes
+//
+
+EFI_STATUS
+MmCoreFfsFindMmDriver (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
+ );
+
+/**
+ Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
+ must add any driver with a before dependency on InsertedDriverEntry first.
+ You do this by recursively calling this routine. After all the Before Depexes
+ are processed you can add InsertedDriverEntry to the mScheduledQueue.
+ Then you can add any driver with an After dependency on InsertedDriverEntry
+ by recursively calling this routine.
+
+ @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
+
+**/
+VOID
+MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
+ IN EFI_MM_DRIVER_ENTRY *InsertedDriverEntry
+ );
+
+//
+// The Driver List contains one copy of every driver that has been discovered.
+// Items are never removed from the driver list. List of EFI_MM_DRIVER_ENTRY
+//
+LIST_ENTRY mDiscoveredList = INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList);
+
+//
+// Queue of drivers that are ready to dispatch. This queue is a subset of the
+// mDiscoveredList.list of EFI_MM_DRIVER_ENTRY.
+//
+LIST_ENTRY mScheduledQueue = INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue);
+
+//
+// List of firmware volume headers whose containing firmware volumes have been
+// parsed and added to the mFwDriverList.
+//
+LIST_ENTRY mFwVolList = INITIALIZE_LIST_HEAD_VARIABLE (mFwVolList);
+
+//
+// Flag for the MM Dispacher. TRUE if dispatcher is executing.
+//
+BOOLEAN gDispatcherRunning = FALSE;
+
+//
+// Flag for the MM Dispacher. TRUE if there is one or more MM drivers ready to be dispatched
+//
+BOOLEAN gRequestDispatch = FALSE;
+
+//
+// The global variable is defined for Loading modules at fixed address feature to track the MM code
+// memory range usage. It is a bit mapped array in which every bit indicates the correspoding
+// memory page available or not.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT64 *mMmCodeMemoryRangeUsageBitMap=NULL;
+
+/**
+ To check memory usage bit map array to figure out if the memory range in which the image will be loaded
+ is available or not. If memory range is avaliable, the function will mark the corresponding bits to 1
+ which indicates the memory range is used. The function is only invoked when load modules at fixed address
+ feature is enabled.
+
+ @param ImageBase The base addres the image will be loaded at.
+ @param ImageSize The size of the image
+
+ @retval EFI_SUCCESS The memory range the image will be loaded in is available
+ @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available
+**/
+EFI_STATUS
+CheckAndMarkFixLoadingMemoryUsageBitMap (
+ IN EFI_PHYSICAL_ADDRESS ImageBase,
+ IN UINTN ImageSize
+ )
+{
+ UINT32 MmCodePageNumber;
+ UINT64 MmCodeSize;
+ EFI_PHYSICAL_ADDRESS MmCodeBase;
+ UINTN BaseOffsetPageNumber;
+ UINTN TopOffsetPageNumber;
+ UINTN Index;
+
+ //
+ // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressMmCodePageNumber
+ //
+ MmCodePageNumber = 0;
+ MmCodeSize = EFI_PAGES_TO_SIZE (MmCodePageNumber);
+ MmCodeBase = gLoadModuleAtFixAddressMmramBase;
+
+ //
+ // If the memory usage bit map is not initialized, do it. Every bit in the array
+ // indicate the status of the corresponding memory page, available or not
+ //
+ if (mMmCodeMemoryRangeUsageBitMap == NULL) {
+ mMmCodeMemoryRangeUsageBitMap = AllocateZeroPool (((MmCodePageNumber / 64) + 1) * sizeof (UINT64));
+ }
+
+ //
+ // If the Dxe code memory range is not allocated or the bit map array allocation failed, return EFI_NOT_FOUND
+ //
+ if (mMmCodeMemoryRangeUsageBitMap == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // see if the memory range for loading the image is in the MM code range.
+ //
+ if (MmCodeBase + MmCodeSize < ImageBase + ImageSize || MmCodeBase > ImageBase) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Test if the memory is available or not.
+ //
+ BaseOffsetPageNumber = (UINTN)EFI_SIZE_TO_PAGES ((UINT32)(ImageBase - MmCodeBase));
+ TopOffsetPageNumber = (UINTN)EFI_SIZE_TO_PAGES ((UINT32)(ImageBase + ImageSize - MmCodeBase));
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
+ if ((mMmCodeMemoryRangeUsageBitMap[Index / 64] & LShiftU64 (1, (Index % 64))) != 0) {
+ //
+ // This page is already used.
+ //
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Being here means the memory range is available. So mark the bits for the memory range
+ //
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
+ mMmCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64 (1, (Index % 64));
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the fixed loading address from image header assigned by build tool. This function only be called
+ when Loading module at Fixed address feature enabled.
+
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF
+ image that needs to be examined by this function.
+ @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
+ @retval EFI_NOT_FOUND The image has no assigned fixed loadding address.
+
+**/
+EFI_STATUS
+GetPeCoffImageFixLoadingAssignedAddress(
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ UINTN SectionHeaderOffset;
+ EFI_STATUS Status;
+ EFI_IMAGE_SECTION_HEADER SectionHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ EFI_PHYSICAL_ADDRESS FixLoadingAddress;
+ UINT16 Index;
+ UINTN Size;
+ UINT16 NumberOfSections;
+ UINT64 ValueInSectionHeader;
+
+ FixLoadingAddress = 0;
+ Status = EFI_NOT_FOUND;
+
+ //
+ // Get PeHeader pointer
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
+ SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) +
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;
+ NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
+
+ //
+ // Get base address from the first section header that doesn't point to code section.
+ //
+ for (Index = 0; Index < NumberOfSections; Index++) {
+ //
+ // Read section header from file
+ //
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ SectionHeaderOffset,
+ &Size,
+ &SectionHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EFI_NOT_FOUND;
+
+ if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
+ //
+ // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields
+ // in the first section header that doesn't point to code section in image header. So there
+ // is an assumption that when the feature is enabled, if a module with a loading address
+ // assigned by tools, the PointerToRelocations & PointerToLineNumbers fields should not be
+ // Zero, or else, these 2 fields should be set to Zero
+ //
+ ValueInSectionHeader = ReadUnaligned64 ((UINT64*)&SectionHeader.PointerToRelocations);
+ if (ValueInSectionHeader != 0) {
+ //
+ // Found first section header that doesn't point to code section in which build tool saves the
+ // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields
+ //
+ FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressMmramBase + (INT64)ValueInSectionHeader);
+ //
+ // Check if the memory range is available.
+ //
+ Status = CheckAndMarkFixLoadingMemoryUsageBitMap (FixLoadingAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment));
+ if (!EFI_ERROR(Status)) {
+ //
+ // The assigned address is valid. Return the specified loading address
+ //
+ ImageContext->ImageAddress = FixLoadingAddress;
+ }
+ }
+ break;
+ }
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
+ }
+ DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %x, Status = %r\n",
+ FixLoadingAddress, Status));
+ return Status;
+}
+/**
+ Loads an EFI image into SMRAM.
+
+ @param DriverEntry EFI_MM_DRIVER_ENTRY instance
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+EFIAPI
+MmLoadImage (
+ IN OUT EFI_MM_DRIVER_ENTRY *DriverEntry
+ )
+{
+ UINTN PageCount;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS DstBuffer;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+
+ DEBUG ((DEBUG_INFO, "MmLoadImage - %g\n", &DriverEntry->FileName));
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Initialize ImageContext
+ //
+ ImageContext.Handle = DriverEntry->Pe32Data;
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+
+ //
+ // Get information about the image being loaded
+ //
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+ DstBuffer = (UINTN)(-1);
+
+ Status = MmAllocatePages (
+ AllocateMaxAddress,
+ EfiRuntimeServicesCode,
+ PageCount,
+ &DstBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;
+
+ //
+ // Align buffer on section boundary
+ //
+ ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
+ ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1));
+
+ //
+ // Load the image to our new buffer
+ //
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ MmFreePages (DstBuffer, PageCount);
+ return Status;
+ }
+
+ //
+ // Relocate the image in our new buffer
+ //
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ MmFreePages (DstBuffer, PageCount);
+ return Status;
+ }
+
+ //
+ // Flush the instruction cache so the image data are written before we execute it
+ //
+ InvalidateInstructionCacheRange ((VOID *)(UINTN) ImageContext.ImageAddress, (UINTN) ImageContext.ImageSize);
+
+ //
+ // Save Image EntryPoint in DriverEntry
+ //
+ DriverEntry->ImageEntryPoint = ImageContext.EntryPoint;
+ DriverEntry->ImageBuffer = DstBuffer;
+ DriverEntry->NumberOfPage = PageCount;
+
+ if (mEfiSystemTable != NULL) {
+ Status = mEfiSystemTable->BootServices->AllocatePool (
+ EfiBootServicesData,
+ sizeof (EFI_LOADED_IMAGE_PROTOCOL),
+ (VOID **)&DriverEntry->LoadedImage
+ );
+ if (EFI_ERROR (Status)) {
+ MmFreePages (DstBuffer, PageCount);
+ return Status;
+ }
+
+ ZeroMem (DriverEntry->LoadedImage, sizeof (EFI_LOADED_IMAGE_PROTOCOL));
+ //
+ // Fill in the remaining fields of the Loaded Image Protocol instance.
+ // Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed.
+ //
+ DriverEntry->LoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
+ DriverEntry->LoadedImage->ParentHandle = NULL;
+ DriverEntry->LoadedImage->SystemTable = mEfiSystemTable;
+ DriverEntry->LoadedImage->DeviceHandle = NULL;
+ DriverEntry->LoadedImage->FilePath = NULL;
+
+ DriverEntry->LoadedImage->ImageBase = (VOID *)(UINTN)DriverEntry->ImageBuffer;
+ DriverEntry->LoadedImage->ImageSize = ImageContext.ImageSize;
+ DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode;
+ DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData;
+
+ //
+ // Create a new image handle in the UEFI handle database for the MM Driver
+ //
+ DriverEntry->ImageHandle = NULL;
+ Status = mEfiSystemTable->BootServices->InstallMultipleProtocolInterfaces (
+ &DriverEntry->ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ DriverEntry->LoadedImage,
+ NULL
+ );
+ }
+
+ //
+ // Print the load address and the PDB file name if it is available
+ //
+ DEBUG_CODE_BEGIN ();
+
+ UINTN Index;
+ UINTN StartIndex;
+ CHAR8 EfiFileName[256];
+
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD,
+ "Loading MM driver at 0x%11p EntryPoint=0x%11p ",
+ (VOID *)(UINTN) ImageContext.ImageAddress,
+ FUNCTION_ENTRY_POINT (ImageContext.EntryPoint)));
+
+ //
+ // Print Module Name by Pdb file path.
+ // Windows and Unix style file path are all trimmed correctly.
+ //
+ if (ImageContext.PdbPointer != NULL) {
+ StartIndex = 0;
+ for (Index = 0; ImageContext.PdbPointer[Index] != 0; Index++) {
+ if ((ImageContext.PdbPointer[Index] == '\\') || (ImageContext.PdbPointer[Index] == '/')) {
+ StartIndex = Index + 1;
+ }
+ }
+
+ //
+ // Copy the PDB file name to our temporary string, and replace .pdb with .efi
+ // The PDB file name is limited in the range of 0~255.
+ // If the length is bigger than 255, trim the redundant characters to avoid overflow in array boundary.
+ //
+ for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
+ EfiFileName[Index] = ImageContext.PdbPointer[Index + StartIndex];
+ if (EfiFileName[Index] == 0) {
+ EfiFileName[Index] = '.';
+ }
+ if (EfiFileName[Index] == '.') {
+ EfiFileName[Index + 1] = 'e';
+ EfiFileName[Index + 2] = 'f';
+ EfiFileName[Index + 3] = 'i';
+ EfiFileName[Index + 4] = 0;
+ break;
+ }
+ }
+
+ if (Index == sizeof (EfiFileName) - 4) {
+ EfiFileName[Index] = 0;
+ }
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName));
+ }
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));
+
+ DEBUG_CODE_END ();
+
+ return Status;
+}
+
+/**
+ Preprocess dependency expression and update DriverEntry to reflect the
+ state of Before and After dependencies. If DriverEntry->Before
+ or DriverEntry->After is set it will never be cleared.
+
+ @param DriverEntry DriverEntry element to update .
+
+ @retval EFI_SUCCESS It always works.
+
+**/
+EFI_STATUS
+MmPreProcessDepex (
+ IN EFI_MM_DRIVER_ENTRY *DriverEntry
+ )
+{
+ UINT8 *Iterator;
+
+ Iterator = DriverEntry->Depex;
+ DriverEntry->Dependent = TRUE;
+
+ if (*Iterator == EFI_DEP_BEFORE) {
+ DriverEntry->Before = TRUE;
+ } else if (*Iterator == EFI_DEP_AFTER) {
+ DriverEntry->After = TRUE;
+ }
+
+ if (DriverEntry->Before || DriverEntry->After) {
+ CopyMem (&DriverEntry->BeforeAfterGuid, Iterator + 1, sizeof (EFI_GUID));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read Depex and pre-process the Depex for Before and After. If Section Extraction
+ protocol returns an error via ReadSection defer the reading of the Depex.
+
+ @param DriverEntry Driver to work on.
+
+ @retval EFI_SUCCESS Depex read and preprossesed
+ @retval EFI_PROTOCOL_ERROR The section extraction protocol returned an error
+ and Depex reading needs to be retried.
+ @retval Error DEPEX not found.
+
+**/
+EFI_STATUS
+MmGetDepexSectionAndPreProccess (
+ IN EFI_MM_DRIVER_ENTRY *DriverEntry
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Data already read
+ //
+ if (DriverEntry->Depex == NULL) {
+ Status = EFI_NOT_FOUND;
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_PROTOCOL_ERROR) {
+ //
+ // The section extraction protocol failed so set protocol error flag
+ //
+ DriverEntry->DepexProtocolError = TRUE;
+ } else {
+ //
+ // If no Depex assume depend on all architectural protocols
+ //
+ DriverEntry->Depex = NULL;
+ DriverEntry->Dependent = TRUE;
+ DriverEntry->DepexProtocolError = FALSE;
+ }
+ } else {
+ //
+ // Set Before and After state information based on Depex
+ // Driver will be put in Dependent state
+ //
+ MmPreProcessDepex (DriverEntry);
+ DriverEntry->DepexProtocolError = FALSE;
+ }
+
+ return Status;
+}
+
+/**
+ This is the main Dispatcher for MM and it exits when there are no more
+ drivers to run. Drain the mScheduledQueue and load and start a PE
+ image for each driver. Search the mDiscoveredList to see if any driver can
+ be placed on the mScheduledQueue. If no drivers are placed on the
+ mScheduledQueue exit the function.
+
+ @retval EFI_SUCCESS All of the MM Drivers that could be dispatched
+ have been run and the MM Entry Point has been
+ registered.
+ @retval EFI_NOT_READY The MM Driver that registered the MM Entry Point
+ was just dispatched.
+ @retval EFI_NOT_FOUND There are no MM Drivers available to be dispatched.
+ @retval EFI_ALREADY_STARTED The MM Dispatcher is already running
+
+**/
+EFI_STATUS
+MmDispatcher (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ EFI_MM_DRIVER_ENTRY *DriverEntry;
+ BOOLEAN ReadyToRun;
+
+ DEBUG ((DEBUG_INFO, "MmDispatcher\n"));
+
+ if (!gRequestDispatch) {
+ DEBUG ((DEBUG_INFO, " !gRequestDispatch\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ if (gDispatcherRunning) {
+ DEBUG ((DEBUG_INFO, " gDispatcherRunning\n"));
+ //
+ // If the dispatcher is running don't let it be restarted.
+ //
+ return EFI_ALREADY_STARTED;
+ }
+
+ gDispatcherRunning = TRUE;
+
+ do {
+ //
+ // Drain the Scheduled Queue
+ //
+ DEBUG ((DEBUG_INFO, " Drain the Scheduled Queue\n"));
+ while (!IsListEmpty (&mScheduledQueue)) {
+ DriverEntry = CR (
+ mScheduledQueue.ForwardLink,
+ EFI_MM_DRIVER_ENTRY,
+ ScheduledLink,
+ EFI_MM_DRIVER_ENTRY_SIGNATURE
+ );
+ DEBUG ((DEBUG_INFO, " DriverEntry (Scheduled) - %g\n", &DriverEntry->FileName));
+
+ //
+ // Load the MM Driver image into memory. If the Driver was transitioned from
+ // Untrusted to Scheduled it would have already been loaded so we may need to
+ // skip the LoadImage
+ //
+ if (DriverEntry->ImageHandle == NULL) {
+ Status = MmLoadImage (DriverEntry);
+
+ //
+ // Update the driver state to reflect that it's been loaded
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // The MM Driver could not be loaded, and do not attempt to load or start it again.
+ // Take driver from Scheduled to Initialized.
+ //
+ DriverEntry->Initialized = TRUE;
+ DriverEntry->Scheduled = FALSE;
+ RemoveEntryList (&DriverEntry->ScheduledLink);
+
+ //
+ // If it's an error don't try the StartImage
+ //
+ continue;
+ }
+ }
+
+ DriverEntry->Scheduled = FALSE;
+ DriverEntry->Initialized = TRUE;
+ RemoveEntryList (&DriverEntry->ScheduledLink);
+
+ //
+ // For each MM driver, pass NULL as ImageHandle
+ //
+ if (mEfiSystemTable == NULL) {
+ DEBUG ((DEBUG_INFO, "StartImage - 0x%x (Standalone Mode)\n", DriverEntry->ImageEntryPoint));
+ Status = ((MM_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint) (DriverEntry->ImageHandle, &gMmCoreMmst);
+ } else {
+ DEBUG ((DEBUG_INFO, "StartImage - 0x%x (Tradition Mode)\n", DriverEntry->ImageEntryPoint));
+ Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint) (
+ DriverEntry->ImageHandle,
+ mEfiSystemTable
+ );
+ }
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_INFO, "StartImage Status - %r\n", Status));
+ MmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage);
+ }
+ }
+
+ //
+ // Search DriverList for items to place on Scheduled Queue
+ //
+ DEBUG ((DEBUG_INFO, " Search DriverList for items to place on Scheduled Queue\n"));
+ ReadyToRun = FALSE;
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR (Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE);
+ DEBUG ((DEBUG_INFO, " DriverEntry (Discovered) - %g\n", &DriverEntry->FileName));
+
+ if (DriverEntry->DepexProtocolError) {
+ //
+ // If Section Extraction Protocol did not let the Depex be read before retry the read
+ //
+ Status = MmGetDepexSectionAndPreProccess (DriverEntry);
+ }
+
+ if (DriverEntry->Dependent) {
+ if (MmIsSchedulable (DriverEntry)) {
+ MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ ReadyToRun = TRUE;
+ }
+ }
+ }
+ } while (ReadyToRun);
+
+ //
+ // If there is no more MM driver to dispatch, stop the dispatch request
+ //
+ DEBUG ((DEBUG_INFO, " no more MM driver to dispatch, stop the dispatch request\n"));
+ gRequestDispatch = FALSE;
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR (Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE);
+ DEBUG ((DEBUG_INFO, " DriverEntry (Discovered) - %g\n", &DriverEntry->FileName));
+
+ if (!DriverEntry->Initialized) {
+ //
+ // We have MM driver pending to dispatch
+ //
+ gRequestDispatch = TRUE;
+ break;
+ }
+ }
+
+ gDispatcherRunning = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
+ must add any driver with a before dependency on InsertedDriverEntry first.
+ You do this by recursively calling this routine. After all the Before Depexes
+ are processed you can add InsertedDriverEntry to the mScheduledQueue.
+ Then you can add any driver with an After dependency on InsertedDriverEntry
+ by recursively calling this routine.
+
+ @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
+
+**/
+VOID
+MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
+ IN EFI_MM_DRIVER_ENTRY *InsertedDriverEntry
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_MM_DRIVER_ENTRY *DriverEntry;
+
+ //
+ // Process Before Dependency
+ //
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->Before && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate MM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " BEFORE FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
+ if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
+ //
+ // Recursively process BEFORE
+ //
+ DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));
+ MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ } else {
+ DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
+ }
+ }
+ }
+
+ //
+ // Convert driver from Dependent to Scheduled state
+ //
+
+ InsertedDriverEntry->Dependent = FALSE;
+ InsertedDriverEntry->Scheduled = TRUE;
+ InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink);
+
+
+ //
+ // Process After Dependency
+ //
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->After && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate MM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " AFTER FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
+ if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
+ //
+ // Recursively process AFTER
+ //
+ DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));
+ MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ } else {
+ DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
+ }
+ }
+ }
+}
+
+/**
+ Return TRUE if the firmware volume has been processed, FALSE if not.
+
+ @param FwVolHeader The header of the firmware volume that's being
+ tested.
+
+ @retval TRUE The firmware volume denoted by FwVolHeader has
+ been processed
+ @retval FALSE The firmware volume denoted by FwVolHeader has
+ not yet been processed
+
+**/
+BOOLEAN
+FvHasBeenProcessed (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
+ )
+{
+ LIST_ENTRY *Link;
+ KNOWN_FWVOL *KnownFwVol;
+
+ for (Link = mFwVolList.ForwardLink;
+ Link != &mFwVolList;
+ Link = Link->ForwardLink) {
+ KnownFwVol = CR (Link, KNOWN_FWVOL, Link, KNOWN_FWVOL_SIGNATURE);
+ if (KnownFwVol->FwVolHeader == FwVolHeader) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Remember that the firmware volume denoted by FwVolHeader has had its drivers
+ placed on mDiscoveredList. This function adds entries to mFwVolList. Items
+ are never removed/freed from mFwVolList.
+
+ @param FwVolHeader The header of the firmware volume that's being
+ processed.
+
+**/
+VOID
+FvIsBeingProcessed (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
+ )
+{
+ KNOWN_FWVOL *KnownFwVol;
+
+ DEBUG ((DEBUG_INFO, "FvIsBeingProcessed - 0x%08x\n", FwVolHeader));
+
+ KnownFwVol = AllocatePool (sizeof (KNOWN_FWVOL));
+ ASSERT (KnownFwVol != NULL);
+
+ KnownFwVol->Signature = KNOWN_FWVOL_SIGNATURE;
+ KnownFwVol->FwVolHeader = FwVolHeader;
+ InsertTailList (&mFwVolList, &KnownFwVol->Link);
+}
+
+/**
+ Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
+ and initialise any state variables. Read the Depex from the FV and store it
+ in DriverEntry. Pre-process the Depex to set the Before and After state.
+ The Discovered list is never freed and contains booleans that represent the
+ other possible MM driver states.
+
+ @param [in] FwVolHeader Pointer to the formware volume header.
+ @param [in] Pe32Data Pointer to the PE data.
+ @param [in] Pe32DataSize Size of the PE data.
+ @param [in] Depex Pointer to the Depex info.
+ @param [in] DepexSize Size of the Depex info.
+ @param [in] DriverName Name of driver to add to mDiscoveredList.
+
+ @retval EFI_SUCCESS If driver was added to the mDiscoveredList.
+**/
+EFI_STATUS
+MmAddToDriverList (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader,
+ IN VOID *Pe32Data,
+ IN UINTN Pe32DataSize,
+ IN VOID *Depex,
+ IN UINTN DepexSize,
+ IN EFI_GUID *DriverName
+ )
+{
+ EFI_MM_DRIVER_ENTRY *DriverEntry;
+
+ DEBUG ((DEBUG_INFO, "MmAddToDriverList - %g (0x%08x)\n", DriverName, Pe32Data));
+
+ //
+ // Create the Driver Entry for the list. ZeroPool initializes lots of variables to
+ // NULL or FALSE.
+ //
+ DriverEntry = AllocateZeroPool (sizeof (EFI_MM_DRIVER_ENTRY));
+ ASSERT (DriverEntry != NULL);
+
+ DriverEntry->Signature = EFI_MM_DRIVER_ENTRY_SIGNATURE;
+ CopyGuid (&DriverEntry->FileName, DriverName);
+ DriverEntry->FwVolHeader = FwVolHeader;
+ DriverEntry->Pe32Data = Pe32Data;
+ DriverEntry->Pe32DataSize = Pe32DataSize;
+ DriverEntry->Depex = Depex;
+ DriverEntry->DepexSize = DepexSize;
+
+ MmGetDepexSectionAndPreProccess (DriverEntry);
+
+ InsertTailList (&mDiscoveredList, &DriverEntry->Link);
+ gRequestDispatch = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Traverse the discovered list for any drivers that were discovered but not loaded
+ because the dependency expressions evaluated to false.
+
+**/
+VOID
+MmDisplayDiscoveredNotDispatched (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_MM_DRIVER_ENTRY *DriverEntry;
+
+ for (Link = mDiscoveredList.ForwardLink;Link !=&mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR (Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->Dependent) {
+ DEBUG ((DEBUG_LOAD, "MM Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));
+ }
+ }
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/FwVol.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/FwVol.c
new file mode 100644
index 00000000..e7941d9f
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/FwVol.c
@@ -0,0 +1,181 @@
+/** @file
+ Firmware volume helper interfaces.
+
+ 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 "StandaloneMmCore.h"
+#include <Library/FvLib.h>
+#include <Library/ExtractGuidedSectionLib.h>
+
+//
+// List of file types supported by dispatcher
+//
+EFI_FV_FILETYPE mMmFileTypes[] = {
+ EFI_FV_FILETYPE_MM,
+ 0xE, //EFI_FV_FILETYPE_MM_STANDALONE,
+ //
+ // Note: DXE core will process the FV image file, so skip it in MM core
+ // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
+ //
+};
+
+EFI_STATUS
+MmAddToDriverList (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader,
+ IN VOID *Pe32Data,
+ IN UINTN Pe32DataSize,
+ IN VOID *Depex,
+ IN UINTN DepexSize,
+ IN EFI_GUID *DriverName
+ );
+
+BOOLEAN
+FvHasBeenProcessed (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
+ );
+
+VOID
+FvIsBeingProcessed (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
+ );
+
+/**
+ Given the pointer to the Firmware Volume Header find the
+ MM driver and return its PE32 image.
+
+ @param [in] FwVolHeader Pointer to memory mapped FV
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Could not find section data.
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+ @retval EFI_VOLUME_CORRUPTED Firmware volume is corrupted.
+ @retval EFI_UNSUPPORTED Operation not supported.
+
+**/
+EFI_STATUS
+MmCoreFfsFindMmDriver (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS DepexStatus;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ EFI_FV_FILETYPE FileType;
+ VOID *Pe32Data;
+ UINTN Pe32DataSize;
+ VOID *Depex;
+ UINTN DepexSize;
+ UINTN Index;
+ EFI_COMMON_SECTION_HEADER *Section;
+ VOID *SectionData;
+ UINTN SectionDataSize;
+ UINT32 DstBufferSize;
+ VOID *ScratchBuffer;
+ UINT32 ScratchBufferSize;
+ VOID *DstBuffer;
+ UINT16 SectionAttribute;
+ UINT32 AuthenticationStatus;
+ EFI_FIRMWARE_VOLUME_HEADER *InnerFvHeader;
+
+ DEBUG ((DEBUG_INFO, "MmCoreFfsFindMmDriver - 0x%x\n", FwVolHeader));
+
+ if (FvHasBeenProcessed (FwVolHeader)) {
+ return EFI_SUCCESS;
+ }
+
+ FvIsBeingProcessed (FwVolHeader);
+
+ //
+ // First check for encapsulated compressed firmware volumes
+ //
+ FileHeader = NULL;
+ do {
+ Status = FfsFindNextFile (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
+ FwVolHeader, &FileHeader);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ Status = FfsFindSectionData (EFI_SECTION_GUID_DEFINED, FileHeader,
+ &SectionData, &SectionDataSize);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ Section = (EFI_COMMON_SECTION_HEADER *)(FileHeader + 1);
+ Status = ExtractGuidedSectionGetInfo (Section, &DstBufferSize,
+ &ScratchBufferSize, &SectionAttribute);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // Allocate scratch buffer
+ //
+ ScratchBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
+ if (ScratchBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Allocate destination buffer, extra one page for adjustment
+ //
+ DstBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));
+ if (DstBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Call decompress function
+ //
+ Status = ExtractGuidedSectionDecode (Section, &DstBuffer, ScratchBuffer,
+ &AuthenticationStatus);
+ FreePages (ScratchBuffer, EFI_SIZE_TO_PAGES (ScratchBufferSize));
+ if (EFI_ERROR (Status)) {
+ goto FreeDstBuffer;
+ }
+
+ DEBUG ((DEBUG_INFO,
+ "Processing compressed firmware volume (AuthenticationStatus == %x)\n",
+ AuthenticationStatus));
+
+ Status = FindFfsSectionInSections (DstBuffer, DstBufferSize,
+ EFI_SECTION_FIRMWARE_VOLUME_IMAGE, &Section);
+ if (EFI_ERROR (Status)) {
+ goto FreeDstBuffer;
+ }
+
+ InnerFvHeader = (VOID *)(Section + 1);
+ Status = MmCoreFfsFindMmDriver (InnerFvHeader);
+ if (EFI_ERROR (Status)) {
+ goto FreeDstBuffer;
+ }
+ } while (TRUE);
+
+ for (Index = 0; Index < sizeof (mMmFileTypes) / sizeof (mMmFileTypes[0]); Index++) {
+ DEBUG ((DEBUG_INFO, "Check MmFileTypes - 0x%x\n", mMmFileTypes[Index]));
+ FileType = mMmFileTypes[Index];
+ FileHeader = NULL;
+ do {
+ Status = FfsFindNextFile (FileType, FwVolHeader, &FileHeader);
+ if (!EFI_ERROR (Status)) {
+ Status = FfsFindSectionData (EFI_SECTION_PE32, FileHeader, &Pe32Data, &Pe32DataSize);
+ DEBUG ((DEBUG_INFO, "Find PE data - 0x%x\n", Pe32Data));
+ DepexStatus = FfsFindSectionData (EFI_SECTION_MM_DEPEX, FileHeader, &Depex, &DepexSize);
+ if (!EFI_ERROR (DepexStatus)) {
+ MmAddToDriverList (FwVolHeader, Pe32Data, Pe32DataSize, Depex, DepexSize, &FileHeader->Name);
+ }
+ }
+ } while (!EFI_ERROR (Status));
+ }
+
+ return EFI_SUCCESS;
+
+FreeDstBuffer:
+ FreePages (DstBuffer, EFI_SIZE_TO_PAGES (DstBufferSize));
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Handle.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Handle.c
new file mode 100644
index 00000000..97e48d75
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Handle.c
@@ -0,0 +1,527 @@
+/** @file
+ SMM handle & protocol handling.
+
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "StandaloneMmCore.h"
+
+//
+// mProtocolDatabase - A list of all protocols in the system. (simple list for now)
+// gHandleList - A list of all the handles in the system
+//
+LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase);
+LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList);
+
+/**
+ Check whether a handle is a valid EFI_HANDLE
+
+ @param UserHandle The handle to check
+
+ @retval EFI_INVALID_PARAMETER The handle is NULL or not a valid EFI_HANDLE.
+ @retval EFI_SUCCESS The handle is valid EFI_HANDLE.
+
+**/
+EFI_STATUS
+MmValidateHandle (
+ IN EFI_HANDLE UserHandle
+ )
+{
+ IHANDLE *Handle;
+
+ Handle = (IHANDLE *)UserHandle;
+ if (Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Handle->Signature != EFI_HANDLE_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Finds the protocol entry for the requested protocol.
+
+ @param Protocol The ID of the protocol
+ @param Create Create a new entry if not found
+
+ @return Protocol entry
+
+**/
+PROTOCOL_ENTRY *
+MmFindProtocolEntry (
+ IN EFI_GUID *Protocol,
+ IN BOOLEAN Create
+ )
+{
+ LIST_ENTRY *Link;
+ PROTOCOL_ENTRY *Item;
+ PROTOCOL_ENTRY *ProtEntry;
+
+ //
+ // Search the database for the matching GUID
+ //
+
+ ProtEntry = NULL;
+ for (Link = mProtocolDatabase.ForwardLink;
+ Link != &mProtocolDatabase;
+ Link = Link->ForwardLink) {
+
+ Item = CR (Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);
+ if (CompareGuid (&Item->ProtocolID, Protocol)) {
+ //
+ // This is the protocol entry
+ //
+ ProtEntry = Item;
+ break;
+ }
+ }
+
+ //
+ // If the protocol entry was not found and Create is TRUE, then
+ // allocate a new entry
+ //
+ if ((ProtEntry == NULL) && Create) {
+ ProtEntry = AllocatePool (sizeof(PROTOCOL_ENTRY));
+ if (ProtEntry != NULL) {
+ //
+ // Initialize new protocol entry structure
+ //
+ ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE;
+ CopyGuid ((VOID *)&ProtEntry->ProtocolID, Protocol);
+ InitializeListHead (&ProtEntry->Protocols);
+ InitializeListHead (&ProtEntry->Notify);
+
+ //
+ // Add it to protocol database
+ //
+ InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries);
+ }
+ }
+ return ProtEntry;
+}
+
+/**
+ Finds the protocol instance for the requested handle and protocol.
+ Note: This function doesn't do parameters checking, it's caller's responsibility
+ to pass in valid parameters.
+
+ @param Handle The handle to search the protocol on
+ @param Protocol GUID of the protocol
+ @param Interface The interface for the protocol being searched
+
+ @return Protocol instance (NULL: Not found)
+
+**/
+PROTOCOL_INTERFACE *
+MmFindProtocolInterface (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ )
+{
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_ENTRY *ProtEntry;
+ LIST_ENTRY *Link;
+
+ Prot = NULL;
+
+ //
+ // Lookup the protocol entry for this protocol ID
+ //
+ ProtEntry = MmFindProtocolEntry (Protocol, FALSE);
+ if (ProtEntry != NULL) {
+ //
+ // Look at each protocol interface for any matches
+ //
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link=Link->ForwardLink) {
+ //
+ // If this protocol interface matches, remove it
+ //
+ Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ if (Prot->Interface == Interface && Prot->Protocol == ProtEntry) {
+ break;
+ }
+ Prot = NULL;
+ }
+ }
+ return Prot;
+}
+
+/**
+ Wrapper function to MmInstallProtocolInterfaceNotify. This is the public API which
+ Calls the private one which contains a BOOLEAN parameter for notifications
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+
+ @return Status code
+
+**/
+EFI_STATUS
+EFIAPI
+MmInstallProtocolInterface (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface
+ )
+{
+ return MmInstallProtocolInterfaceNotify (
+ UserHandle,
+ Protocol,
+ InterfaceType,
+ Interface,
+ TRUE
+ );
+}
+
+/**
+ Installs a protocol interface into the boot services environment.
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+ @param Notify indicates whether notify the notification list
+ for this protocol
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Protocol interface successfully installed
+
+**/
+EFI_STATUS
+MmInstallProtocolInterfaceNotify (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface,
+ IN BOOLEAN Notify
+ )
+{
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_ENTRY *ProtEntry;
+ IHANDLE *Handle;
+ EFI_STATUS Status;
+ VOID *ExistingInterface;
+
+ //
+ // returns EFI_INVALID_PARAMETER if InterfaceType is invalid.
+ // Also added check for invalid UserHandle and Protocol pointers.
+ //
+ if (UserHandle == NULL || Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (InterfaceType != EFI_NATIVE_INTERFACE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Print debug message
+ //
+ DEBUG ((DEBUG_LOAD | DEBUG_INFO, "MmInstallProtocolInterface: %g %p\n", Protocol, Interface));
+
+ Status = EFI_OUT_OF_RESOURCES;
+ Prot = NULL;
+ Handle = NULL;
+
+ if (*UserHandle != NULL) {
+ Status = MmHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface);
+ if (!EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Lookup the Protocol Entry for the requested protocol
+ //
+ ProtEntry = MmFindProtocolEntry (Protocol, TRUE);
+ if (ProtEntry == NULL) {
+ goto Done;
+ }
+
+ //
+ // Allocate a new protocol interface structure
+ //
+ Prot = AllocateZeroPool (sizeof (PROTOCOL_INTERFACE));
+ if (Prot == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // If caller didn't supply a handle, allocate a new one
+ //
+ Handle = (IHANDLE *)*UserHandle;
+ if (Handle == NULL) {
+ Handle = AllocateZeroPool (sizeof (IHANDLE));
+ if (Handle == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Initialize new handler structure
+ //
+ Handle->Signature = EFI_HANDLE_SIGNATURE;
+ InitializeListHead (&Handle->Protocols);
+
+ //
+ // Add this handle to the list global list of all handles
+ // in the system
+ //
+ InsertTailList (&gHandleList, &Handle->AllHandles);
+ }
+
+ Status = MmValidateHandle (Handle);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Each interface that is added must be unique
+ //
+ ASSERT (MmFindProtocolInterface (Handle, Protocol, Interface) == NULL);
+
+ //
+ // Initialize the protocol interface structure
+ //
+ Prot->Signature = PROTOCOL_INTERFACE_SIGNATURE;
+ Prot->Handle = Handle;
+ Prot->Protocol = ProtEntry;
+ Prot->Interface = Interface;
+
+ //
+ // Add this protocol interface to the head of the supported
+ // protocol list for this handle
+ //
+ InsertHeadList (&Handle->Protocols, &Prot->Link);
+
+ //
+ // Add this protocol interface to the tail of the
+ // protocol entry
+ //
+ InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);
+
+ //
+ // Notify the notification list for this protocol
+ //
+ if (Notify) {
+ MmNotifyProtocol (Prot);
+ }
+ Status = EFI_SUCCESS;
+
+Done:
+ if (!EFI_ERROR (Status)) {
+ //
+ // Return the new handle back to the caller
+ //
+ *UserHandle = Handle;
+ } else {
+ //
+ // There was an error, clean up
+ //
+ if (Prot != NULL) {
+ FreePool (Prot);
+ }
+ }
+ return Status;
+}
+
+/**
+ Uninstalls all instances of a protocol:interfacer from a handle.
+ If the last protocol interface is remove from the handle, the
+ handle is freed.
+
+ @param UserHandle The handle to remove the protocol handler from
+ @param Protocol The protocol, of protocol:interface, to remove
+ @param Interface The interface, of protocol:interface, to remove
+
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_SUCCESS Protocol interface successfully uninstalled.
+
+**/
+EFI_STATUS
+EFIAPI
+MmUninstallProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ )
+{
+ EFI_STATUS Status;
+ IHANDLE *Handle;
+ PROTOCOL_INTERFACE *Prot;
+
+ //
+ // Check that Protocol is valid
+ //
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check that UserHandle is a valid handle
+ //
+ Status = MmValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check that Protocol exists on UserHandle, and Interface matches the interface in the database
+ //
+ Prot = MmFindProtocolInterface (UserHandle, Protocol, Interface);
+ if (Prot == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Remove the protocol interface from the protocol
+ //
+ Status = EFI_NOT_FOUND;
+ Handle = (IHANDLE *)UserHandle;
+ Prot = MmRemoveInterfaceFromProtocol (Handle, Protocol, Interface);
+
+ if (Prot != NULL) {
+ //
+ // Remove the protocol interface from the handle
+ //
+ RemoveEntryList (&Prot->Link);
+
+ //
+ // Free the memory
+ //
+ Prot->Signature = 0;
+ FreePool (Prot);
+ Status = EFI_SUCCESS;
+ }
+
+ //
+ // If there are no more handlers for the handle, free the handle
+ //
+ if (IsListEmpty (&Handle->Protocols)) {
+ Handle->Signature = 0;
+ RemoveEntryList (&Handle->AllHandles);
+ FreePool (Handle);
+ }
+ return Status;
+}
+
+/**
+ Locate a certain GUID protocol interface in a Handle's protocols.
+
+ @param UserHandle The handle to obtain the protocol interface on
+ @param Protocol The GUID of the protocol
+
+ @return The requested protocol interface for the handle
+
+**/
+PROTOCOL_INTERFACE *
+MmGetProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol
+ )
+{
+ EFI_STATUS Status;
+ PROTOCOL_ENTRY *ProtEntry;
+ PROTOCOL_INTERFACE *Prot;
+ IHANDLE *Handle;
+ LIST_ENTRY *Link;
+
+ Status = MmValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Handle = (IHANDLE *)UserHandle;
+
+ //
+ // Look at each protocol interface for a match
+ //
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ ProtEntry = Prot->Protocol;
+ if (CompareGuid (&ProtEntry->ProtocolID, Protocol)) {
+ return Prot;
+ }
+ }
+ return NULL;
+}
+
+/**
+ Queries a handle to determine if it supports a specified protocol.
+
+ @param UserHandle The handle being queried.
+ @param Protocol The published unique identifier of the protocol.
+ @param Interface Supplies the address where a pointer to the
+ corresponding Protocol Interface is returned.
+
+ @retval EFI_SUCCESS The interface information for the specified protocol was returned.
+ @retval EFI_UNSUPPORTED The device does not support the specified protocol.
+ @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE..
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_INVALID_PARAMETER Interface is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MmHandleProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface
+ )
+{
+ EFI_STATUS Status;
+ PROTOCOL_INTERFACE *Prot;
+
+ //
+ // Check for invalid Protocol
+ //
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check for invalid Interface
+ //
+ if (Interface == NULL) {
+ return EFI_INVALID_PARAMETER;
+ } else {
+ *Interface = NULL;
+ }
+
+ //
+ // Check for invalid UserHandle
+ //
+ Status = MmValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Look at each protocol interface for a match
+ //
+ Prot = MmGetProtocolInterface (UserHandle, Protocol);
+ if (Prot == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // This is the protocol interface entry for this protocol
+ //
+ *Interface = Prot->Interface;
+
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/InstallConfigurationTable.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/InstallConfigurationTable.c
new file mode 100644
index 00000000..0eb52ffe
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/InstallConfigurationTable.c
@@ -0,0 +1,172 @@
+/** @file
+ System Management System Table Services MmInstallConfigurationTable service
+
+ Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "StandaloneMmCore.h"
+
+#define CONFIG_TABLE_SIZE_INCREASED 0x10
+
+UINTN mMmSystemTableAllocateSize = 0;
+
+/**
+ The MmInstallConfigurationTable() function is used to maintain the list
+ of configuration tables that are stored in the System Management System
+ Table. The list is stored as an array of (GUID, Pointer) pairs. The list
+ must be allocated from pool memory with PoolType set to EfiRuntimeServicesData.
+
+ @param SystemTable A pointer to the SMM System Table (SMST).
+ @param Guid A pointer to the GUID for the entry to add, update, or remove.
+ @param Table A pointer to the buffer of the table to add.
+ @param TableSize The size of the table to install.
+
+ @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.
+ @retval EFI_INVALID_PARAMETER Guid is not valid.
+ @retval EFI_NOT_FOUND An attempt was made to delete a non-existent entry.
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.
+
+**/
+EFI_STATUS
+EFIAPI
+MmInstallConfigurationTable (
+ IN CONST EFI_MM_SYSTEM_TABLE *SystemTable,
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Table,
+ IN UINTN TableSize
+ )
+{
+ UINTN Index;
+ EFI_CONFIGURATION_TABLE *ConfigurationTable;
+ EFI_CONFIGURATION_TABLE *OldTable;
+
+ //
+ // If Guid is NULL, then this operation cannot be performed
+ //
+ if (Guid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ConfigurationTable = gMmCoreMmst.MmConfigurationTable;
+
+ //
+ // Search all the table for an entry that matches Guid
+ //
+ for (Index = 0; Index < gMmCoreMmst.NumberOfTableEntries; Index++) {
+ if (CompareGuid (Guid, &(ConfigurationTable[Index].VendorGuid))) {
+ break;
+ }
+ }
+
+ if (Index < gMmCoreMmst.NumberOfTableEntries) {
+ //
+ // A match was found, so this is either a modify or a delete operation
+ //
+ if (Table != NULL) {
+ //
+ // If Table is not NULL, then this is a modify operation.
+ // Modify the table entry and return.
+ //
+ ConfigurationTable[Index].VendorTable = Table;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // A match was found and Table is NULL, so this is a delete operation.
+ //
+ gMmCoreMmst.NumberOfTableEntries--;
+
+ //
+ // Copy over deleted entry
+ //
+ CopyMem (
+ &(ConfigurationTable[Index]),
+ &(ConfigurationTable[Index + 1]),
+ (gMmCoreMmst.NumberOfTableEntries - Index) * sizeof (EFI_CONFIGURATION_TABLE)
+ );
+
+ } else {
+ //
+ // No matching GUIDs were found, so this is an add operation.
+ //
+ if (Table == NULL) {
+ //
+ // If Table is NULL on an add operation, then return an error.
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Assume that Index == gMmCoreMmst.NumberOfTableEntries
+ //
+ if ((Index * sizeof (EFI_CONFIGURATION_TABLE)) >= mMmSystemTableAllocateSize) {
+ //
+ // Allocate a table with one additional entry.
+ //
+ mMmSystemTableAllocateSize += (CONFIG_TABLE_SIZE_INCREASED * sizeof (EFI_CONFIGURATION_TABLE));
+ ConfigurationTable = AllocatePool (mMmSystemTableAllocateSize);
+ if (ConfigurationTable == NULL) {
+ //
+ // If a new table could not be allocated, then return an error.
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (gMmCoreMmst.MmConfigurationTable != NULL) {
+ //
+ // Copy the old table to the new table.
+ //
+ CopyMem (
+ ConfigurationTable,
+ gMmCoreMmst.MmConfigurationTable,
+ Index * sizeof (EFI_CONFIGURATION_TABLE)
+ );
+
+ //
+ // Record the old table pointer.
+ //
+ OldTable = gMmCoreMmst.MmConfigurationTable;
+
+ //
+ // As the MmInstallConfigurationTable() may be re-entered by FreePool() in
+ // its calling stack, updating System table to the new table pointer must
+ // be done before calling FreePool() to free the old table.
+ // It can make sure the gMmCoreMmst.MmConfigurationTable point to the new
+ // table and avoid the errors of use-after-free to the old table by the
+ // reenter of MmInstallConfigurationTable() in FreePool()'s calling stack.
+ //
+ gMmCoreMmst.MmConfigurationTable = ConfigurationTable;
+
+ //
+ // Free the old table after updating System Table to the new table pointer.
+ //
+ FreePool (OldTable);
+ } else {
+ //
+ // Update System Table
+ //
+ gMmCoreMmst.MmConfigurationTable = ConfigurationTable;
+ }
+ }
+
+ //
+ // Fill in the new entry
+ //
+ CopyGuid ((VOID *)&ConfigurationTable[Index].VendorGuid, Guid);
+ ConfigurationTable[Index].VendorTable = Table;
+
+ //
+ // This is an add operation, so increment the number of table entries
+ //
+ gMmCoreMmst.NumberOfTableEntries++;
+ }
+
+ //
+ // CRC-32 field is ignorable for SMM System Table and should be set to zero
+ //
+
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Locate.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Locate.c
new file mode 100644
index 00000000..bc8be157
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Locate.c
@@ -0,0 +1,490 @@
+/** @file
+ Locate handle functions
+
+ Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "StandaloneMmCore.h"
+
+//
+// ProtocolRequest - Last LocateHandle request ID
+//
+UINTN mEfiLocateHandleRequest = 0;
+
+//
+// Internal prototypes
+//
+
+typedef struct {
+ EFI_GUID *Protocol;
+ VOID *SearchKey;
+ LIST_ENTRY *Position;
+ PROTOCOL_ENTRY *ProtEntry;
+} LOCATE_POSITION;
+
+typedef
+IHANDLE *
+(* CORE_GET_NEXT) (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ );
+
+/**
+ Routine to get the next Handle, when you are searching for all handles.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+MmGetNextLocateAllHandles (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ )
+{
+ IHANDLE *Handle;
+
+ //
+ // Next handle
+ //
+ Position->Position = Position->Position->ForwardLink;
+
+ //
+ // If not at the end of the list, get the handle
+ //
+ Handle = NULL;
+ *Interface = NULL;
+ if (Position->Position != &gHandleList) {
+ Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
+ }
+ return Handle;
+}
+
+/**
+ Routine to get the next Handle, when you are searching for register protocol
+ notifies.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+MmGetNextLocateByRegisterNotify (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ )
+{
+ IHANDLE *Handle;
+ PROTOCOL_NOTIFY *ProtNotify;
+ PROTOCOL_INTERFACE *Prot;
+ LIST_ENTRY *Link;
+
+ Handle = NULL;
+ *Interface = NULL;
+ ProtNotify = Position->SearchKey;
+
+ //
+ // If this is the first request, get the next handle
+ //
+ if (ProtNotify != NULL) {
+ ASSERT (ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE);
+ Position->SearchKey = NULL;
+
+ //
+ // If not at the end of the list, get the next handle
+ //
+ Link = ProtNotify->Position->ForwardLink;
+ if (Link != &ProtNotify->Protocol->Protocols) {
+ Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
+ Handle = Prot->Handle;
+ *Interface = Prot->Interface;
+ }
+ }
+ return Handle;
+}
+
+/**
+ Routine to get the next Handle, when you are searching for a given protocol.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+MmGetNextLocateByProtocol (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ )
+{
+ IHANDLE *Handle;
+ LIST_ENTRY *Link;
+ PROTOCOL_INTERFACE *Prot;
+
+ Handle = NULL;
+ *Interface = NULL;
+ for (; ;) {
+ //
+ // Next entry
+ //
+ Link = Position->Position->ForwardLink;
+ Position->Position = Link;
+
+ //
+ // If not at the end, return the handle
+ //
+ if (Link == &Position->ProtEntry->Protocols) {
+ Handle = NULL;
+ break;
+ }
+
+ //
+ // Get the handle
+ //
+ Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
+ Handle = Prot->Handle;
+ *Interface = Prot->Interface;
+
+ //
+ // If this handle has not been returned this request, then
+ // return it now
+ //
+ if (Handle->LocateRequest != mEfiLocateHandleRequest) {
+ Handle->LocateRequest = mEfiLocateHandleRequest;
+ break;
+ }
+ }
+ return Handle;
+}
+
+/**
+ Return the first Protocol Interface that matches the Protocol GUID. If
+ Registration is passed in return a Protocol Instance that was just add
+ to the system. If Registration is NULL return the first Protocol Interface
+ you find.
+
+ @param Protocol The protocol to search for
+ @param Registration Optional Registration Key returned from
+ RegisterProtocolNotify()
+ @param Interface Return the Protocol interface (instance).
+
+ @retval EFI_SUCCESS If a valid Interface is returned
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_NOT_FOUND Protocol interface not found
+
+**/
+EFI_STATUS
+EFIAPI
+MmLocateProtocol (
+ IN EFI_GUID *Protocol,
+ IN VOID *Registration OPTIONAL,
+ OUT VOID **Interface
+ )
+{
+ EFI_STATUS Status;
+ LOCATE_POSITION Position;
+ PROTOCOL_NOTIFY *ProtNotify;
+ IHANDLE *Handle;
+
+ if ((Interface == NULL) || (Protocol == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Interface = NULL;
+ Status = EFI_SUCCESS;
+
+ //
+ // Set initial position
+ //
+ Position.Protocol = Protocol;
+ Position.SearchKey = Registration;
+ Position.Position = &gHandleList;
+
+ mEfiLocateHandleRequest += 1;
+
+ if (Registration == NULL) {
+ //
+ // Look up the protocol entry and set the head pointer
+ //
+ Position.ProtEntry = MmFindProtocolEntry (Protocol, FALSE);
+ if (Position.ProtEntry == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ Position.Position = &Position.ProtEntry->Protocols;
+
+ Handle = MmGetNextLocateByProtocol (&Position, Interface);
+ } else {
+ Handle = MmGetNextLocateByRegisterNotify (&Position, Interface);
+ }
+
+ if (Handle == NULL) {
+ Status = EFI_NOT_FOUND;
+ } else if (Registration != NULL) {
+ //
+ // If this is a search by register notify and a handle was
+ // returned, update the register notification position
+ //
+ ProtNotify = Registration;
+ ProtNotify->Position = ProtNotify->Position->ForwardLink;
+ }
+
+ return Status;
+}
+
+/**
+ Locates the requested handle(s) and returns them in Buffer.
+
+ @param SearchType The type of search to perform to locate the
+ handles
+ @param Protocol The protocol to search for
+ @param SearchKey Dependant on SearchType
+ @param BufferSize On input the size of Buffer. On output the
+ size of data returned.
+ @param Buffer The buffer to return the results in
+
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is
+ returned in BufferSize.
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully found the requested handle(s) and
+ returns them in Buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+MmLocateHandle (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_HANDLE *Buffer
+ )
+{
+ EFI_STATUS Status;
+ LOCATE_POSITION Position;
+ PROTOCOL_NOTIFY *ProtNotify;
+ CORE_GET_NEXT GetNext;
+ UINTN ResultSize;
+ IHANDLE *Handle;
+ IHANDLE **ResultBuffer;
+ VOID *Interface;
+
+ if (BufferSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*BufferSize > 0) && (Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GetNext = NULL;
+
+ //
+ // Set initial position
+ //
+ Position.Protocol = Protocol;
+ Position.SearchKey = SearchKey;
+ Position.Position = &gHandleList;
+
+ ResultSize = 0;
+ ResultBuffer = (IHANDLE **) Buffer;
+ Status = EFI_SUCCESS;
+
+ //
+ // Get the search function based on type
+ //
+ switch (SearchType) {
+ case AllHandles:
+ GetNext = MmGetNextLocateAllHandles;
+ break;
+
+ case ByRegisterNotify:
+ GetNext = MmGetNextLocateByRegisterNotify;
+ //
+ // Must have SearchKey for locate ByRegisterNotify
+ //
+ if (SearchKey == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+ break;
+
+ case ByProtocol:
+ GetNext = MmGetNextLocateByProtocol;
+ if (Protocol == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+ //
+ // Look up the protocol entry and set the head pointer
+ //
+ Position.ProtEntry = MmFindProtocolEntry (Protocol, FALSE);
+ if (Position.ProtEntry == NULL) {
+ Status = EFI_NOT_FOUND;
+ break;
+ }
+ Position.Position = &Position.ProtEntry->Protocols;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Enumerate out the matching handles
+ //
+ mEfiLocateHandleRequest += 1;
+ for (; ;) {
+ //
+ // Get the next handle. If no more handles, stop
+ //
+ Handle = GetNext (&Position, &Interface);
+ if (NULL == Handle) {
+ break;
+ }
+
+ //
+ // Increase the resulting buffer size, and if this handle
+ // fits return it
+ //
+ ResultSize += sizeof (Handle);
+ if (ResultSize <= *BufferSize) {
+ *ResultBuffer = Handle;
+ ResultBuffer += 1;
+ }
+ }
+
+ //
+ // If the result is a zero length buffer, then there were no
+ // matching handles
+ //
+ if (ResultSize == 0) {
+ Status = EFI_NOT_FOUND;
+ } else {
+ //
+ // Return the resulting buffer size. If it's larger than what
+ // was passed, then set the error code
+ //
+ if (ResultSize > *BufferSize) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *BufferSize = ResultSize;
+
+ if (SearchType == ByRegisterNotify && !EFI_ERROR (Status)) {
+ ASSERT (SearchKey != NULL);
+ //
+ // If this is a search by register notify and a handle was
+ // returned, update the register notification position
+ //
+ ProtNotify = SearchKey;
+ ProtNotify->Position = ProtNotify->Position->ForwardLink;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Function returns an array of handles that support the requested protocol
+ in a buffer allocated from pool. This is a version of MmLocateHandle()
+ that allocates a buffer for the caller.
+
+ @param SearchType Specifies which handle(s) are to be returned.
+ @param Protocol Provides the protocol to search by. This
+ parameter is only valid for SearchType
+ ByProtocol.
+ @param SearchKey Supplies the search key depending on the
+ SearchType.
+ @param NumberHandles The number of handles returned in Buffer.
+ @param Buffer A pointer to the buffer to return the requested
+ array of handles that support Protocol.
+
+ @retval EFI_SUCCESS The result array of handles was returned.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
+ matching results.
+ @retval EFI_INVALID_PARAMETER One or more parameters are not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+MmLocateHandleBuffer (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *NumberHandles,
+ OUT EFI_HANDLE **Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+
+ if (NumberHandles == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BufferSize = 0;
+ *NumberHandles = 0;
+ *Buffer = NULL;
+ Status = MmLocateHandle (
+ SearchType,
+ Protocol,
+ SearchKey,
+ &BufferSize,
+ *Buffer
+ );
+ //
+ // LocateHandleBuffer() returns incorrect status code if SearchType is
+ // invalid.
+ //
+ // Add code to correctly handle expected errors from MmLocateHandle().
+ //
+ if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
+ if (Status != EFI_INVALID_PARAMETER) {
+ Status = EFI_NOT_FOUND;
+ }
+ return Status;
+ }
+
+ *Buffer = AllocatePool (BufferSize);
+ if (*Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = MmLocateHandle (
+ SearchType,
+ Protocol,
+ SearchKey,
+ &BufferSize,
+ *Buffer
+ );
+
+ *NumberHandles = BufferSize / sizeof(EFI_HANDLE);
+ if (EFI_ERROR (Status)) {
+ *NumberHandles = 0;
+ }
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Mmi.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Mmi.c
new file mode 100644
index 00000000..1a3c84c6
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Mmi.c
@@ -0,0 +1,331 @@
+/** @file
+ MMI management.
+
+ Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "StandaloneMmCore.h"
+
+//
+// MM_HANDLER_STATE_NOTIFIER
+//
+
+//
+// MM_HANDLER - used for each MM handler
+//
+
+#define MMI_ENTRY_SIGNATURE SIGNATURE_32('m','m','i','e')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY AllEntries; // All entries
+
+ EFI_GUID HandlerType; // Type of interrupt
+ LIST_ENTRY MmiHandlers; // All handlers
+} MMI_ENTRY;
+
+#define MMI_HANDLER_SIGNATURE SIGNATURE_32('m','m','i','h')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link; // Link on MMI_ENTRY.MmiHandlers
+ EFI_MM_HANDLER_ENTRY_POINT Handler; // The mm handler's entry point
+ MMI_ENTRY *MmiEntry;
+} MMI_HANDLER;
+
+LIST_ENTRY mRootMmiHandlerList = INITIALIZE_LIST_HEAD_VARIABLE (mRootMmiHandlerList);
+LIST_ENTRY mMmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mMmiEntryList);
+
+/**
+ Finds the MMI entry for the requested handler type.
+
+ @param HandlerType The type of the interrupt
+ @param Create Create a new entry if not found
+
+ @return MMI entry
+
+**/
+MMI_ENTRY *
+EFIAPI
+MmCoreFindMmiEntry (
+ IN EFI_GUID *HandlerType,
+ IN BOOLEAN Create
+ )
+{
+ LIST_ENTRY *Link;
+ MMI_ENTRY *Item;
+ MMI_ENTRY *MmiEntry;
+
+ //
+ // Search the MMI entry list for the matching GUID
+ //
+ MmiEntry = NULL;
+ for (Link = mMmiEntryList.ForwardLink;
+ Link != &mMmiEntryList;
+ Link = Link->ForwardLink) {
+
+ Item = CR (Link, MMI_ENTRY, AllEntries, MMI_ENTRY_SIGNATURE);
+ if (CompareGuid (&Item->HandlerType, HandlerType)) {
+ //
+ // This is the MMI entry
+ //
+ MmiEntry = Item;
+ break;
+ }
+ }
+
+ //
+ // If the protocol entry was not found and Create is TRUE, then
+ // allocate a new entry
+ //
+ if ((MmiEntry == NULL) && Create) {
+ MmiEntry = AllocatePool (sizeof (MMI_ENTRY));
+ if (MmiEntry != NULL) {
+ //
+ // Initialize new MMI entry structure
+ //
+ MmiEntry->Signature = MMI_ENTRY_SIGNATURE;
+ CopyGuid ((VOID *)&MmiEntry->HandlerType, HandlerType);
+ InitializeListHead (&MmiEntry->MmiHandlers);
+
+ //
+ // Add it to MMI entry list
+ //
+ InsertTailList (&mMmiEntryList, &MmiEntry->AllEntries);
+ }
+ }
+ return MmiEntry;
+}
+
+/**
+ Manage MMI of a particular type.
+
+ @param HandlerType Points to the handler type or NULL for root MMI handlers.
+ @param Context Points to an optional context buffer.
+ @param CommBuffer Points to the optional communication buffer.
+ @param CommBufferSize Points to the size of the optional communication buffer.
+
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was processed successfully but not quiesced.
+ @retval EFI_INTERRUPT_PENDING One or more MMI sources could not be quiesced.
+ @retval EFI_NOT_FOUND Interrupt source was not handled or quiesced.
+ @retval EFI_SUCCESS Interrupt source was handled and quiesced.
+
+**/
+EFI_STATUS
+EFIAPI
+MmiManage (
+ IN CONST EFI_GUID *HandlerType,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *Head;
+ MMI_ENTRY *MmiEntry;
+ MMI_HANDLER *MmiHandler;
+ BOOLEAN SuccessReturn;
+ EFI_STATUS Status;
+
+ Status = EFI_NOT_FOUND;
+ SuccessReturn = FALSE;
+ if (HandlerType == NULL) {
+ //
+ // Root MMI handler
+ //
+
+ Head = &mRootMmiHandlerList;
+ } else {
+ //
+ // Non-root MMI handler
+ //
+ MmiEntry = MmCoreFindMmiEntry ((EFI_GUID *) HandlerType, FALSE);
+ if (MmiEntry == NULL) {
+ //
+ // There is no handler registered for this interrupt source
+ //
+ return Status;
+ }
+
+ Head = &MmiEntry->MmiHandlers;
+ }
+
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
+ MmiHandler = CR (Link, MMI_HANDLER, Link, MMI_HANDLER_SIGNATURE);
+
+ Status = MmiHandler->Handler (
+ (EFI_HANDLE) MmiHandler,
+ Context,
+ CommBuffer,
+ CommBufferSize
+ );
+
+ switch (Status) {
+ case EFI_INTERRUPT_PENDING:
+ //
+ // If a handler returns EFI_INTERRUPT_PENDING and HandlerType is not NULL then
+ // no additional handlers will be processed and EFI_INTERRUPT_PENDING will be returned.
+ //
+ if (HandlerType != NULL) {
+ return EFI_INTERRUPT_PENDING;
+ }
+ break;
+
+ case EFI_SUCCESS:
+ //
+ // If at least one of the handlers returns EFI_SUCCESS then the function will return
+ // EFI_SUCCESS. If a handler returns EFI_SUCCESS and HandlerType is not NULL then no
+ // additional handlers will be processed.
+ //
+ if (HandlerType != NULL) {
+ return EFI_SUCCESS;
+ }
+ SuccessReturn = TRUE;
+ break;
+
+ case EFI_WARN_INTERRUPT_SOURCE_QUIESCED:
+ //
+ // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED
+ // then the function will return EFI_SUCCESS.
+ //
+ SuccessReturn = TRUE;
+ break;
+
+ case EFI_WARN_INTERRUPT_SOURCE_PENDING:
+ //
+ // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING
+ // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned.
+ //
+ break;
+
+ default:
+ //
+ // Unexpected status code returned.
+ //
+ ASSERT (FALSE);
+ break;
+ }
+ }
+
+ if (SuccessReturn) {
+ Status = EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+/**
+ Registers a handler to execute within MM.
+
+ @param Handler Handler service function pointer.
+ @param HandlerType Points to the handler type or NULL for root MMI handlers.
+ @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.
+
+ @retval EFI_SUCCESS Handler register success.
+ @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MmiHandlerRegister (
+ IN EFI_MM_HANDLER_ENTRY_POINT Handler,
+ IN CONST EFI_GUID *HandlerType OPTIONAL,
+ OUT EFI_HANDLE *DispatchHandle
+ )
+{
+ MMI_HANDLER *MmiHandler;
+ MMI_ENTRY *MmiEntry;
+ LIST_ENTRY *List;
+
+ if (Handler == NULL || DispatchHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MmiHandler = AllocateZeroPool (sizeof (MMI_HANDLER));
+ if (MmiHandler == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ MmiHandler->Signature = MMI_HANDLER_SIGNATURE;
+ MmiHandler->Handler = Handler;
+
+ if (HandlerType == NULL) {
+ //
+ // This is root MMI handler
+ //
+ MmiEntry = NULL;
+ List = &mRootMmiHandlerList;
+ } else {
+ //
+ // None root MMI handler
+ //
+ MmiEntry = MmCoreFindMmiEntry ((EFI_GUID *) HandlerType, TRUE);
+ if (MmiEntry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ List = &MmiEntry->MmiHandlers;
+ }
+
+ MmiHandler->MmiEntry = MmiEntry;
+ InsertTailList (List, &MmiHandler->Link);
+
+ *DispatchHandle = (EFI_HANDLE) MmiHandler;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Unregister a handler in MM.
+
+ @param DispatchHandle The handle that was specified when the handler was registered.
+
+ @retval EFI_SUCCESS Handler function was successfully unregistered.
+ @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.
+
+**/
+EFI_STATUS
+EFIAPI
+MmiHandlerUnRegister (
+ IN EFI_HANDLE DispatchHandle
+ )
+{
+ MMI_HANDLER *MmiHandler;
+ MMI_ENTRY *MmiEntry;
+
+ MmiHandler = (MMI_HANDLER *) DispatchHandle;
+
+ if (MmiHandler == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MmiHandler->Signature != MMI_HANDLER_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MmiEntry = MmiHandler->MmiEntry;
+
+ RemoveEntryList (&MmiHandler->Link);
+ FreePool (MmiHandler);
+
+ if (MmiEntry == NULL) {
+ //
+ // This is root MMI handler
+ //
+ return EFI_SUCCESS;
+ }
+
+ if (IsListEmpty (&MmiEntry->MmiHandlers)) {
+ //
+ // No handler registered for this interrupt now, remove the MMI_ENTRY
+ //
+ RemoveEntryList (&MmiEntry->AllEntries);
+
+ FreePool (MmiEntry);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Notify.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Notify.c
new file mode 100644
index 00000000..fd5e5adb
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Notify.c
@@ -0,0 +1,197 @@
+/** @file
+ Support functions for UEFI protocol notification infrastructure.
+
+ Copyright (c) 2009 - 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 "StandaloneMmCore.h"
+
+/**
+ Signal event for every protocol in protocol entry.
+
+ @param Prot Protocol interface
+
+**/
+VOID
+MmNotifyProtocol (
+ IN PROTOCOL_INTERFACE *Prot
+ )
+{
+ PROTOCOL_ENTRY *ProtEntry;
+ PROTOCOL_NOTIFY *ProtNotify;
+ LIST_ENTRY *Link;
+
+ ProtEntry = Prot->Protocol;
+ for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {
+ ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
+ ProtNotify->Function (&ProtEntry->ProtocolID, Prot->Interface, Prot->Handle);
+ }
+}
+
+/**
+ Removes Protocol from the protocol list (but not the handle list).
+
+ @param Handle The handle to remove protocol on.
+ @param Protocol GUID of the protocol to be moved
+ @param Interface The interface of the protocol
+
+ @return Protocol Entry
+
+**/
+PROTOCOL_INTERFACE *
+MmRemoveInterfaceFromProtocol (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ )
+{
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_NOTIFY *ProtNotify;
+ PROTOCOL_ENTRY *ProtEntry;
+ LIST_ENTRY *Link;
+
+ Prot = MmFindProtocolInterface (Handle, Protocol, Interface);
+ if (Prot != NULL) {
+
+ ProtEntry = Prot->Protocol;
+
+ //
+ // If there's a protocol notify location pointing to this entry, back it up one
+ //
+ for (Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link = Link->ForwardLink) {
+ ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
+
+ if (ProtNotify->Position == &Prot->ByProtocol) {
+ ProtNotify->Position = Prot->ByProtocol.BackLink;
+ }
+ }
+
+ //
+ // Remove the protocol interface entry
+ //
+ RemoveEntryList (&Prot->ByProtocol);
+ }
+
+ return Prot;
+}
+
+/**
+ Add a new protocol notification record for the request protocol.
+
+ @param Protocol The requested protocol to add the notify
+ registration
+ @param Function Points to the notification function
+ @param Registration Returns the registration record
+
+ @retval EFI_SUCCESS Successfully returned the registration record
+ that has been added or unhooked
+ @retval EFI_INVALID_PARAMETER Protocol is NULL or Registration is NULL
+ @retval EFI_OUT_OF_RESOURCES Not enough memory resource to finish the request
+ @retval EFI_NOT_FOUND If the registration is not found when Function == NULL
+
+**/
+EFI_STATUS
+EFIAPI
+MmRegisterProtocolNotify (
+ IN CONST EFI_GUID *Protocol,
+ IN EFI_MM_NOTIFY_FN Function,
+ OUT VOID **Registration
+ )
+{
+ PROTOCOL_ENTRY *ProtEntry;
+ PROTOCOL_NOTIFY *ProtNotify;
+ LIST_ENTRY *Link;
+ EFI_STATUS Status;
+
+ if (Protocol == NULL || Registration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Function == NULL) {
+ //
+ // Get the protocol entry per Protocol
+ //
+ ProtEntry = MmFindProtocolEntry ((EFI_GUID *) Protocol, FALSE);
+ if (ProtEntry != NULL) {
+ ProtNotify = (PROTOCOL_NOTIFY * )*Registration;
+ for (Link = ProtEntry->Notify.ForwardLink;
+ Link != &ProtEntry->Notify;
+ Link = Link->ForwardLink) {
+ //
+ // Compare the notification record
+ //
+ if (ProtNotify == (CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE))) {
+ //
+ // If Registration is an existing registration, then unhook it
+ //
+ ProtNotify->Signature = 0;
+ RemoveEntryList (&ProtNotify->Link);
+ FreePool (ProtNotify);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ //
+ // If the registration is not found
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ ProtNotify = NULL;
+
+ //
+ // Get the protocol entry to add the notification too
+ //
+ ProtEntry = MmFindProtocolEntry ((EFI_GUID *) Protocol, TRUE);
+ if (ProtEntry != NULL) {
+ //
+ // Find whether notification already exist
+ //
+ for (Link = ProtEntry->Notify.ForwardLink;
+ Link != &ProtEntry->Notify;
+ Link = Link->ForwardLink) {
+
+ ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
+ if (CompareGuid (&ProtNotify->Protocol->ProtocolID, Protocol) &&
+ (ProtNotify->Function == Function)) {
+
+ //
+ // Notification already exist
+ //
+ *Registration = ProtNotify;
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Allocate a new notification record
+ //
+ ProtNotify = AllocatePool (sizeof (PROTOCOL_NOTIFY));
+ if (ProtNotify != NULL) {
+ ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE;
+ ProtNotify->Protocol = ProtEntry;
+ ProtNotify->Function = Function;
+ //
+ // Start at the ending
+ //
+ ProtNotify->Position = ProtEntry->Protocols.BackLink;
+
+ InsertTailList (&ProtEntry->Notify, &ProtNotify->Link);
+ }
+ }
+
+ //
+ // Done. If we have a protocol notify entry, then return it.
+ // Otherwise, we must have run out of resources trying to add one
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ if (ProtNotify != NULL) {
+ *Registration = ProtNotify;
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Page.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Page.c
new file mode 100644
index 00000000..97655a82
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Page.c
@@ -0,0 +1,378 @@
+/** @file
+ MM Memory page management functions.
+
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "StandaloneMmCore.h"
+
+#define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
+ ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size)))
+
+#define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT)
+
+LIST_ENTRY mMmMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (mMmMemoryMap);
+
+UINTN mMapKey;
+
+/**
+ Internal Function. Allocate n pages from given free page node.
+
+ @param Pages The free page node.
+ @param NumberOfPages Number of pages to be allocated.
+ @param MaxAddress Request to allocate memory below this address.
+
+ @return Memory address of allocated pages.
+
+**/
+UINTN
+InternalAllocPagesOnOneNode (
+ IN OUT FREE_PAGE_LIST *Pages,
+ IN UINTN NumberOfPages,
+ IN UINTN MaxAddress
+ )
+{
+ UINTN Top;
+ UINTN Bottom;
+ FREE_PAGE_LIST *Node;
+
+ Top = TRUNCATE_TO_PAGES (MaxAddress + 1 - (UINTN)Pages);
+ if (Top > Pages->NumberOfPages) {
+ Top = Pages->NumberOfPages;
+ }
+ Bottom = Top - NumberOfPages;
+
+ if (Top < Pages->NumberOfPages) {
+ Node = (FREE_PAGE_LIST*)((UINTN)Pages + EFI_PAGES_TO_SIZE (Top));
+ Node->NumberOfPages = Pages->NumberOfPages - Top;
+ InsertHeadList (&Pages->Link, &Node->Link);
+ }
+
+ if (Bottom > 0) {
+ Pages->NumberOfPages = Bottom;
+ } else {
+ RemoveEntryList (&Pages->Link);
+ }
+
+ return (UINTN)Pages + EFI_PAGES_TO_SIZE (Bottom);
+}
+
+/**
+ Internal Function. Allocate n pages from free page list below MaxAddress.
+
+ @param FreePageList The free page node.
+ @param NumberOfPages Number of pages to be allocated.
+ @param MaxAddress Request to allocate memory below this address.
+
+ @return Memory address of allocated pages.
+
+**/
+UINTN
+InternalAllocMaxAddress (
+ IN OUT LIST_ENTRY *FreePageList,
+ IN UINTN NumberOfPages,
+ IN UINTN MaxAddress
+ )
+{
+ LIST_ENTRY *Node;
+ FREE_PAGE_LIST *Pages;
+
+ for (Node = FreePageList->BackLink; Node != FreePageList; Node = Node->BackLink) {
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
+ if (Pages->NumberOfPages >= NumberOfPages &&
+ (UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress) {
+ return InternalAllocPagesOnOneNode (Pages, NumberOfPages, MaxAddress);
+ }
+ }
+ return (UINTN)(-1);
+}
+
+/**
+ Internal Function. Allocate n pages from free page list at given address.
+
+ @param FreePageList The free page node.
+ @param NumberOfPages Number of pages to be allocated.
+ @param MaxAddress Request to allocate memory below this address.
+
+ @return Memory address of allocated pages.
+
+**/
+UINTN
+InternalAllocAddress (
+ IN OUT LIST_ENTRY *FreePageList,
+ IN UINTN NumberOfPages,
+ IN UINTN Address
+ )
+{
+ UINTN EndAddress;
+ LIST_ENTRY *Node;
+ FREE_PAGE_LIST *Pages;
+
+ if ((Address & EFI_PAGE_MASK) != 0) {
+ return ~Address;
+ }
+
+ EndAddress = Address + EFI_PAGES_TO_SIZE (NumberOfPages);
+ for (Node = FreePageList->BackLink; Node!= FreePageList; Node = Node->BackLink) {
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
+ if ((UINTN)Pages <= Address) {
+ if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) < EndAddress) {
+ break;
+ }
+ return InternalAllocPagesOnOneNode (Pages, NumberOfPages, EndAddress);
+ }
+ }
+ return ~Address;
+}
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform.
+ @param MemoryType The type of memory to turn the allocated pages
+ into.
+ @param NumberOfPages The number of pages to allocate.
+ @param Memory A pointer to receive the base allocated memory
+ address.
+
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+MmInternalAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ )
+{
+ UINTN RequestedAddress;
+
+ if (MemoryType != EfiRuntimeServicesCode &&
+ MemoryType != EfiRuntimeServicesData) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (NumberOfPages > TRUNCATE_TO_PAGES ((UINTN)-1) + 1) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // We don't track memory type in MM
+ //
+ RequestedAddress = (UINTN)*Memory;
+ switch (Type) {
+ case AllocateAnyPages:
+ RequestedAddress = (UINTN)(-1);
+ case AllocateMaxAddress:
+ *Memory = InternalAllocMaxAddress (
+ &mMmMemoryMap,
+ NumberOfPages,
+ RequestedAddress
+ );
+ if (*Memory == (UINTN)-1) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ break;
+ case AllocateAddress:
+ *Memory = InternalAllocAddress (
+ &mMmMemoryMap,
+ NumberOfPages,
+ RequestedAddress
+ );
+ if (*Memory != RequestedAddress) {
+ return EFI_NOT_FOUND;
+ }
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform.
+ @param MemoryType The type of memory to turn the allocated pages
+ into.
+ @param NumberOfPages The number of pages to allocate.
+ @param Memory A pointer to receive the base allocated memory
+ address.
+
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+MmAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MmInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory);
+ return Status;
+}
+
+/**
+ Internal Function. Merge two adjacent nodes.
+
+ @param First The first of two nodes to merge.
+
+ @return Pointer to node after merge (if success) or pointer to next node (if fail).
+
+**/
+FREE_PAGE_LIST *
+InternalMergeNodes (
+ IN FREE_PAGE_LIST *First
+ )
+{
+ FREE_PAGE_LIST *Next;
+
+ Next = BASE_CR (First->Link.ForwardLink, FREE_PAGE_LIST, Link);
+ ASSERT (
+ TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) >= First->NumberOfPages);
+
+ if (TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) == First->NumberOfPages) {
+ First->NumberOfPages += Next->NumberOfPages;
+ RemoveEntryList (&Next->Link);
+ Next = First;
+ }
+ return Next;
+}
+
+/**
+ Frees previous allocated pages.
+
+ @param Memory Base address of memory being freed.
+ @param NumberOfPages The number of pages to free.
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range.
+ @retval EFI_INVALID_PARAMETER Address not aligned.
+ @return EFI_SUCCESS Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+MmInternalFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ LIST_ENTRY *Node;
+ FREE_PAGE_LIST *Pages;
+
+ if ((Memory & EFI_PAGE_MASK) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Pages = NULL;
+ Node = mMmMemoryMap.ForwardLink;
+ while (Node != &mMmMemoryMap) {
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
+ if (Memory < (UINTN)Pages) {
+ break;
+ }
+ Node = Node->ForwardLink;
+ }
+
+ if (Node != &mMmMemoryMap &&
+ Memory + EFI_PAGES_TO_SIZE (NumberOfPages) > (UINTN)Pages) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Node->BackLink != &mMmMemoryMap) {
+ Pages = BASE_CR (Node->BackLink, FREE_PAGE_LIST, Link);
+ if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) > Memory) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ Pages = (FREE_PAGE_LIST*)(UINTN)Memory;
+ Pages->NumberOfPages = NumberOfPages;
+ InsertTailList (Node, &Pages->Link);
+
+ if (Pages->Link.BackLink != &mMmMemoryMap) {
+ Pages = InternalMergeNodes (
+ BASE_CR (Pages->Link.BackLink, FREE_PAGE_LIST, Link)
+ );
+ }
+
+ if (Node != &mMmMemoryMap) {
+ InternalMergeNodes (Pages);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Frees previous allocated pages.
+
+ @param Memory Base address of memory being freed.
+ @param NumberOfPages The number of pages to free.
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range.
+ @retval EFI_INVALID_PARAMETER Address not aligned.
+ @return EFI_SUCCESS Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+MmFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MmInternalFreePages (Memory, NumberOfPages);
+ return Status;
+}
+
+/**
+ Add free MMRAM region for use by memory service.
+
+ @param MemBase Base address of memory region.
+ @param MemLength Length of the memory region.
+ @param Type Memory type.
+ @param Attributes Memory region state.
+
+**/
+VOID
+MmAddMemoryRegion (
+ IN EFI_PHYSICAL_ADDRESS MemBase,
+ IN UINT64 MemLength,
+ IN EFI_MEMORY_TYPE Type,
+ IN UINT64 Attributes
+ )
+{
+ UINTN AlignedMemBase;
+
+ //
+ // Do not add memory regions that is already allocated, needs testing, or needs ECC initialization
+ //
+ if ((Attributes & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
+ return;
+ }
+
+ //
+ // Align range on an EFI_PAGE_SIZE boundary
+ //
+ AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
+ MemLength -= AlignedMemBase - MemBase;
+ MmFreePages (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength));
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Pool.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Pool.c
new file mode 100644
index 00000000..3d263ec3
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/Pool.c
@@ -0,0 +1,287 @@
+/** @file
+ SMM Memory pool management functions.
+
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "StandaloneMmCore.h"
+
+LIST_ENTRY mMmPoolLists[MAX_POOL_INDEX];
+//
+// To cache the MMRAM base since when Loading modules At fixed address feature is enabled,
+// all module is assigned an offset relative the MMRAM base in build time.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressMmramBase = 0;
+
+/**
+ 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
+ )
+{
+ UINTN Index;
+
+ //
+ // Initialize Pool list
+ //
+ for (Index = sizeof (mMmPoolLists) / sizeof (*mMmPoolLists); Index > 0;) {
+ InitializeListHead (&mMmPoolLists[--Index]);
+ }
+
+
+ //
+ // Initialize free MMRAM regions
+ //
+ for (Index = 0; Index < MmramRangeCount; Index++) {
+ //
+ // BUGBUG: Add legacy MMRAM region is buggy.
+ //
+ if (MmramRanges[Index].CpuStart < BASE_1MB) {
+ continue;
+ }
+ DEBUG ((DEBUG_INFO, "MmAddMemoryRegion %d : 0x%016lx - 0x%016lx\n",
+ Index, MmramRanges[Index].CpuStart, MmramRanges[Index].PhysicalSize));
+ MmAddMemoryRegion (
+ MmramRanges[Index].CpuStart,
+ MmramRanges[Index].PhysicalSize,
+ EfiConventionalMemory,
+ MmramRanges[Index].RegionState
+ );
+ }
+
+}
+
+/**
+ Internal Function. Allocate a pool by specified PoolIndex.
+
+ @param PoolIndex Index which indicate the Pool size.
+ @param FreePoolHdr The returned Free pool.
+
+ @retval EFI_OUT_OF_RESOURCES Allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+InternalAllocPoolByIndex (
+ IN UINTN PoolIndex,
+ OUT FREE_POOL_HEADER **FreePoolHdr
+ )
+{
+ EFI_STATUS Status;
+ FREE_POOL_HEADER *Hdr;
+ EFI_PHYSICAL_ADDRESS Address;
+
+ ASSERT (PoolIndex <= MAX_POOL_INDEX);
+ Status = EFI_SUCCESS;
+ Hdr = NULL;
+ if (PoolIndex == MAX_POOL_INDEX) {
+ Status = MmInternalAllocatePages (
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1),
+ &Address
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Hdr = (FREE_POOL_HEADER *) (UINTN) Address;
+ } else if (!IsListEmpty (&mMmPoolLists[PoolIndex])) {
+ Hdr = BASE_CR (GetFirstNode (&mMmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);
+ RemoveEntryList (&Hdr->Link);
+ } else {
+ Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);
+ if (!EFI_ERROR (Status)) {
+ Hdr->Header.Size >>= 1;
+ Hdr->Header.Available = TRUE;
+ InsertHeadList (&mMmPoolLists[PoolIndex], &Hdr->Link);
+ Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;
+ Hdr->Header.Available = FALSE;
+ }
+
+ *FreePoolHdr = Hdr;
+ return Status;
+}
+
+/**
+ Internal Function. Free a pool by specified PoolIndex.
+
+ @param FreePoolHdr The pool to free.
+
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+InternalFreePoolByIndex (
+ IN FREE_POOL_HEADER *FreePoolHdr
+ )
+{
+ UINTN PoolIndex;
+
+ ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);
+ ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);
+ ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);
+
+ PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);
+ FreePoolHdr->Header.Available = TRUE;
+ ASSERT (PoolIndex < MAX_POOL_INDEX);
+ InsertHeadList (&mMmPoolLists[PoolIndex], &FreePoolHdr->Link);
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate.
+ @param Size The amount of pool to allocate.
+ @param Buffer The address to return a pointer to the allocated
+ pool.
+
+ @retval EFI_INVALID_PARAMETER PoolType not valid.
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+MmInternalAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ )
+{
+ POOL_HEADER *PoolHdr;
+ FREE_POOL_HEADER *FreePoolHdr;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Address;
+ UINTN PoolIndex;
+
+ if (PoolType != EfiRuntimeServicesCode &&
+ PoolType != EfiRuntimeServicesData) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Size += sizeof (*PoolHdr);
+ if (Size > MAX_POOL_SIZE) {
+ Size = EFI_SIZE_TO_PAGES (Size);
+ Status = MmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PoolHdr = (POOL_HEADER*)(UINTN)Address;
+ PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);
+ PoolHdr->Available = FALSE;
+ *Buffer = PoolHdr + 1;
+ return Status;
+ }
+
+ Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;
+ PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);
+ if ((Size & (Size - 1)) != 0) {
+ PoolIndex++;
+ }
+
+ Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);
+ if (!EFI_ERROR (Status)) {
+ *Buffer = &FreePoolHdr->Header + 1;
+ }
+ return Status;
+}
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate.
+ @param Size The amount of pool to allocate.
+ @param Buffer The address to return a pointer to the allocated
+ pool.
+
+ @retval EFI_INVALID_PARAMETER PoolType not valid.
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+MmAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MmInternalAllocatePool (PoolType, Size, Buffer);
+ return Status;
+}
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free.
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+MmInternalFreePool (
+ IN VOID *Buffer
+ )
+{
+ FREE_POOL_HEADER *FreePoolHdr;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);
+ ASSERT (!FreePoolHdr->Header.Available);
+
+ if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {
+ ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);
+ ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);
+ return MmInternalFreePages (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,
+ EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)
+ );
+ }
+ return InternalFreePoolByIndex (FreePoolHdr);
+}
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free.
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+MmFreePool (
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MmInternalFreePool (Buffer);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/StandaloneMmCore.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/StandaloneMmCore.c
new file mode 100644
index 00000000..a7cb1ad9
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/StandaloneMmCore.c
@@ -0,0 +1,661 @@
+/** @file
+ MM Core Main Entry Point
+
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "StandaloneMmCore.h"
+
+EFI_STATUS
+MmCoreFfsFindMmDriver (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
+ );
+
+EFI_STATUS
+MmDispatcher (
+ VOID
+ );
+
+//
+// Globals used to initialize the protocol
+//
+EFI_HANDLE mMmCpuHandle = NULL;
+
+//
+// Physical pointer to private structure shared between MM IPL and the MM Core
+//
+MM_CORE_PRIVATE_DATA *gMmCorePrivate;
+
+//
+// MM Core global variable for MM System Table. Only accessed as a physical structure in MMRAM.
+//
+EFI_MM_SYSTEM_TABLE gMmCoreMmst = {
+
+ // The table header for the MMST.
+ {
+ MM_MMST_SIGNATURE,
+ EFI_MM_SYSTEM_TABLE_REVISION,
+ sizeof (gMmCoreMmst.Hdr)
+ },
+ // MmFirmwareVendor
+ NULL,
+ // MmFirmwareRevision
+ 0,
+ // MmInstallConfigurationTable
+ MmInstallConfigurationTable,
+ // I/O Service
+ {
+ {
+ (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5, // MmMemRead
+ (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5 // MmMemWrite
+ },
+ {
+ (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5, // MmIoRead
+ (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5 // MmIoWrite
+ }
+ },
+ // Runtime memory services
+ MmAllocatePool,
+ MmFreePool,
+ MmAllocatePages,
+ MmFreePages,
+ // MP service
+ NULL, // MmStartupThisAp
+ 0, // CurrentlyExecutingCpu
+ 0, // NumberOfCpus
+ NULL, // CpuSaveStateSize
+ NULL, // CpuSaveState
+ 0, // NumberOfTableEntries
+ NULL, // MmConfigurationTable
+ MmInstallProtocolInterface,
+ MmUninstallProtocolInterface,
+ MmHandleProtocol,
+ MmRegisterProtocolNotify,
+ MmLocateHandle,
+ MmLocateProtocol,
+ MmiManage,
+ MmiHandlerRegister,
+ MmiHandlerUnRegister
+};
+
+//
+// Table of MMI Handlers that are registered by the MM Core when it is initialized
+//
+MM_CORE_MMI_HANDLERS mMmCoreMmiHandlers[] = {
+ { MmReadyToLockHandler, &gEfiDxeMmReadyToLockProtocolGuid, NULL, TRUE },
+ { MmEndOfDxeHandler, &gEfiEndOfDxeEventGroupGuid, NULL, FALSE },
+ { MmExitBootServiceHandler,&gEfiEventExitBootServicesGuid, NULL, FALSE },
+ { MmReadyToBootHandler, &gEfiEventReadyToBootGuid, NULL, FALSE },
+ { NULL, NULL, NULL, FALSE },
+};
+
+EFI_SYSTEM_TABLE *mEfiSystemTable;
+UINTN mMmramRangeCount;
+EFI_MMRAM_DESCRIPTOR *mMmramRanges;
+
+/**
+ Place holder function until all the MM System Table Service are available.
+
+ Note: This function is only used by MMRAM invocation. It is never used by DXE invocation.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+ @param Arg4 Undefined
+ @param Arg5 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+MmEfiNotAvailableYetArg5 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3,
+ UINTN Arg4,
+ UINTN Arg5
+ )
+{
+ //
+ // This function should never be executed. If it does, then the architectural protocols
+ // have not been designed correctly.
+ //
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ Software MMI handler that is called when a ExitBoot Service event is signaled.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmExitBootServiceHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_HANDLE MmHandle;
+ EFI_STATUS Status;
+ STATIC BOOLEAN mInExitBootServices = FALSE;
+
+ Status = EFI_SUCCESS;
+ if (!mInExitBootServices) {
+ MmHandle = NULL;
+ Status = MmInstallProtocolInterface (
+ &MmHandle,
+ &gEfiEventExitBootServicesGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ }
+ mInExitBootServices = TRUE;
+ return Status;
+}
+
+/**
+ Software MMI handler that is called when a ExitBoot Service event is signaled.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmReadyToBootHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_HANDLE MmHandle;
+ EFI_STATUS Status;
+ STATIC BOOLEAN mInReadyToBoot = FALSE;
+
+ Status = EFI_SUCCESS;
+ if (!mInReadyToBoot) {
+ MmHandle = NULL;
+ Status = MmInstallProtocolInterface (
+ &MmHandle,
+ &gEfiEventReadyToBootGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ }
+ mInReadyToBoot = TRUE;
+ return Status;
+}
+
+/**
+ Software MMI handler that is called when the DxeMmReadyToLock protocol is added
+ or if gEfiEventReadyToBootGuid is signaled. This function unregisters the
+ Software SMIs that are nor required after MMRAM is locked and installs the
+ MM Ready To Lock Protocol so MM Drivers are informed that MMRAM is about
+ to be locked.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmReadyToLockHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_HANDLE MmHandle;
+
+ DEBUG ((DEBUG_INFO, "MmReadyToLockHandler\n"));
+
+ //
+ // Unregister MMI Handlers that are no longer required after the MM driver dispatch is stopped
+ //
+ for (Index = 0; mMmCoreMmiHandlers[Index].HandlerType != NULL; Index++) {
+ if (mMmCoreMmiHandlers[Index].UnRegister) {
+ MmiHandlerUnRegister (mMmCoreMmiHandlers[Index].DispatchHandle);
+ }
+ }
+
+ //
+ // Install MM Ready to lock protocol
+ //
+ MmHandle = NULL;
+ Status = MmInstallProtocolInterface (
+ &MmHandle,
+ &gEfiMmReadyToLockProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+
+ //
+ // Make sure MM CPU I/O 2 Protocol has been installed into the handle database
+ //
+ //Status = MmLocateProtocol (&EFI_MM_CPU_IO_PROTOCOL_GUID, NULL, &Interface);
+
+ //
+ // Print a message on a debug build if the MM CPU I/O 2 Protocol is not installed
+ //
+ //if (EFI_ERROR (Status)) {
+ //DEBUG ((DEBUG_ERROR, "\nSMM: SmmCpuIo Arch Protocol not present!!\n"));
+ //}
+
+
+ //
+ // Assert if the CPU I/O 2 Protocol is not installed
+ //
+ //ASSERT_EFI_ERROR (Status);
+
+ //
+ // Display any drivers that were not dispatched because dependency expression
+ // evaluated to false if this is a debug build
+ //
+ //MmDisplayDiscoveredNotDispatched ();
+
+ return Status;
+}
+
+/**
+ Software MMI handler that is called when the EndOfDxe event is signaled.
+ This function installs the MM EndOfDxe Protocol so MM Drivers are informed that
+ platform code will invoke 3rd part code.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmEndOfDxeHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE MmHandle;
+
+ DEBUG ((DEBUG_INFO, "MmEndOfDxeHandler\n"));
+ //
+ // Install MM EndOfDxe protocol
+ //
+ MmHandle = NULL;
+ Status = MmInstallProtocolInterface (
+ &MmHandle,
+ &gEfiMmEndOfDxeProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ return Status;
+}
+
+
+
+/**
+ The main entry point to MM Foundation.
+
+ Note: This function is only used by MMRAM invocation. It is never used by DXE invocation.
+
+ @param MmEntryContext Processor information and functionality
+ needed by MM Foundation.
+
+**/
+VOID
+EFIAPI
+MmEntryPoint (
+ IN CONST EFI_MM_ENTRY_CONTEXT *MmEntryContext
+)
+{
+ EFI_STATUS Status;
+ EFI_MM_COMMUNICATE_HEADER *CommunicateHeader;
+
+ DEBUG ((DEBUG_INFO, "MmEntryPoint ...\n"));
+
+ //
+ // Update MMST using the context
+ //
+ CopyMem (&gMmCoreMmst.MmStartupThisAp, MmEntryContext, sizeof (EFI_MM_ENTRY_CONTEXT));
+
+ //
+ // Call platform hook before Mm Dispatch
+ //
+ //PlatformHookBeforeMmDispatch ();
+
+ //
+ // If a legacy boot has occurred, then make sure gMmCorePrivate is not accessed
+ //
+
+ //
+ // TBD: Mark the InMm flag as TRUE
+ //
+ gMmCorePrivate->InMm = TRUE;
+
+ //
+ // Check to see if this is a Synchronous MMI sent through the MM Communication
+ // Protocol or an Asynchronous MMI
+ //
+ if (gMmCorePrivate->CommunicationBuffer != 0) {
+ //
+ // Synchronous MMI for MM Core or request from Communicate protocol
+ //
+ if (!MmIsBufferOutsideMmValid ((UINTN)gMmCorePrivate->CommunicationBuffer, gMmCorePrivate->BufferSize)) {
+ //
+ // If CommunicationBuffer is not in valid address scope, return EFI_INVALID_PARAMETER
+ //
+ gMmCorePrivate->CommunicationBuffer = 0;
+ gMmCorePrivate->ReturnStatus = EFI_INVALID_PARAMETER;
+ } else {
+ CommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)(UINTN)gMmCorePrivate->CommunicationBuffer;
+ gMmCorePrivate->BufferSize -= OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);
+ Status = MmiManage (
+ &CommunicateHeader->HeaderGuid,
+ NULL,
+ CommunicateHeader->Data,
+ (UINTN *)&gMmCorePrivate->BufferSize
+ );
+ //
+ // Update CommunicationBuffer, BufferSize and ReturnStatus
+ // Communicate service finished, reset the pointer to CommBuffer to NULL
+ //
+ gMmCorePrivate->BufferSize += OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);
+ gMmCorePrivate->CommunicationBuffer = 0;
+ gMmCorePrivate->ReturnStatus = (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Process Asynchronous MMI sources
+ //
+ MmiManage (NULL, NULL, NULL, NULL);
+
+ //
+ // TBD: Do not use private data structure ?
+ //
+
+ //
+ // Clear the InMm flag as we are going to leave MM
+ //
+ gMmCorePrivate->InMm = FALSE;
+
+ DEBUG ((DEBUG_INFO, "MmEntryPoint Done\n"));
+}
+
+/** Register the MM Entry Point provided by the MM Core with the
+ MM Configuration protocol.
+
+ @param [in] Protocol Pointer to the protocol.
+ @param [in] Interface Pointer to the MM Configuration protocol.
+ @param [in] Handle Handle.
+
+ @retval EFI_SUCCESS Success.
+**/
+EFI_STATUS
+EFIAPI
+MmConfigurationMmNotify (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_MM_CONFIGURATION_PROTOCOL *MmConfiguration;
+
+ DEBUG ((DEBUG_INFO, "MmConfigurationMmNotify(%g) - %x\n", Protocol, Interface));
+
+ MmConfiguration = Interface;
+
+ //
+ // Register the MM Entry Point provided by the MM Core with the MM COnfiguration protocol
+ //
+ Status = MmConfiguration->RegisterMmEntry (MmConfiguration, (EFI_MM_ENTRY_POINT)(UINTN)gMmCorePrivate->MmEntryPoint);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Set flag to indicate that the MM Entry Point has been registered which
+ // means that MMIs are now fully operational.
+ //
+ gMmCorePrivate->MmEntryPointRegistered = TRUE;
+
+ //
+ // Print debug message showing MM Core entry point address.
+ //
+ DEBUG ((DEBUG_INFO, "MM Core registered MM Entry Point address %p\n", (VOID *)(UINTN)gMmCorePrivate->MmEntryPoint));
+ return EFI_SUCCESS;
+}
+
+/** Returns the HOB list size.
+
+ @param [in] HobStart Pointer to the start of the HOB list.
+
+ @retval Size of the HOB list.
+**/
+UINTN
+GetHobListSize (
+ IN VOID *HobStart
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+
+ ASSERT (HobStart != NULL);
+
+ Hob.Raw = (UINT8 *) HobStart;
+ while (!END_OF_HOB_LIST (Hob)) {
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+ //
+ // Need plus END_OF_HOB_LIST
+ //
+ return (UINTN)Hob.Raw - (UINTN)HobStart + sizeof (EFI_HOB_GENERIC_HEADER);
+}
+
+/**
+ The Entry Point for MM Core
+
+ Install DXE Protocols and reload MM Core into MMRAM and register MM Core
+ EntryPoint on the MMI vector.
+
+ Note: This function is called for both DXE invocation and MMRAM invocation.
+
+ @param HobStart Pointer to the start of the HOB list.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_UNSUPPORTED Unsupported operation.
+**/
+EFI_STATUS
+EFIAPI
+StandaloneMmMain (
+ IN VOID *HobStart
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ VOID *MmHobStart;
+ UINTN HobSize;
+ VOID *Registration;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ MM_CORE_DATA_HOB_DATA *DataInHob;
+ EFI_HOB_GUID_TYPE *MmramRangesHob;
+ EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *MmramRangesHobData;
+ EFI_MMRAM_DESCRIPTOR *MmramRanges;
+ UINTN MmramRangeCount;
+ EFI_HOB_FIRMWARE_VOLUME *BfvHob;
+
+ ProcessLibraryConstructorList (HobStart, &gMmCoreMmst);
+
+ DEBUG ((DEBUG_INFO, "MmMain - 0x%x\n", HobStart));
+
+ //
+ // Determine if the caller has passed a reference to a MM_CORE_PRIVATE_DATA
+ // structure in the Hoblist. This choice will govern how boot information is
+ // extracted later.
+ //
+ GuidHob = GetNextGuidHob (&gMmCoreDataHobGuid, HobStart);
+ if (GuidHob == NULL) {
+ //
+ // Allocate and zero memory for a MM_CORE_PRIVATE_DATA table and then
+ // initialise it
+ //
+ gMmCorePrivate = (MM_CORE_PRIVATE_DATA *) AllocateRuntimePages(EFI_SIZE_TO_PAGES(sizeof (MM_CORE_PRIVATE_DATA)));
+ SetMem ((VOID *)(UINTN)gMmCorePrivate, sizeof (MM_CORE_PRIVATE_DATA), 0);
+ gMmCorePrivate->Signature = MM_CORE_PRIVATE_DATA_SIGNATURE;
+ gMmCorePrivate->MmEntryPointRegistered = FALSE;
+ gMmCorePrivate->InMm = FALSE;
+ gMmCorePrivate->ReturnStatus = EFI_SUCCESS;
+
+ //
+ // Extract the MMRAM ranges from the MMRAM descriptor HOB
+ //
+ MmramRangesHob = GetNextGuidHob (&gEfiMmPeiMmramMemoryReserveGuid, HobStart);
+ if (MmramRangesHob == NULL)
+ return EFI_UNSUPPORTED;
+
+ MmramRangesHobData = GET_GUID_HOB_DATA (MmramRangesHob);
+ ASSERT (MmramRangesHobData != NULL);
+ MmramRanges = MmramRangesHobData->Descriptor;
+ MmramRangeCount = (UINTN)MmramRangesHobData->NumberOfMmReservedRegions;
+ ASSERT (MmramRanges);
+ ASSERT (MmramRangeCount);
+
+ //
+ // Copy the MMRAM ranges into MM_CORE_PRIVATE_DATA table just in case any
+ // code relies on them being present there
+ //
+ gMmCorePrivate->MmramRangeCount = (UINT64)MmramRangeCount;
+ gMmCorePrivate->MmramRanges =
+ (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (MmramRangeCount * sizeof (EFI_MMRAM_DESCRIPTOR));
+ ASSERT (gMmCorePrivate->MmramRanges != 0);
+ CopyMem (
+ (VOID *)(UINTN)gMmCorePrivate->MmramRanges,
+ MmramRanges,
+ MmramRangeCount * sizeof (EFI_MMRAM_DESCRIPTOR)
+ );
+ } else {
+ DataInHob = GET_GUID_HOB_DATA (GuidHob);
+ gMmCorePrivate = (MM_CORE_PRIVATE_DATA *)(UINTN)DataInHob->Address;
+ MmramRanges = (EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate->MmramRanges;
+ MmramRangeCount = (UINTN)gMmCorePrivate->MmramRangeCount;
+ }
+
+ //
+ // Print the MMRAM ranges passed by the caller
+ //
+ DEBUG ((DEBUG_INFO, "MmramRangeCount - 0x%x\n", MmramRangeCount));
+ for (Index = 0; Index < MmramRangeCount; Index++) {
+ DEBUG ((DEBUG_INFO, "MmramRanges[%d]: 0x%016lx - 0x%lx\n", Index,
+ MmramRanges[Index].CpuStart,
+ MmramRanges[Index].PhysicalSize));
+ }
+
+ //
+ // Copy the MMRAM ranges into private MMRAM
+ //
+ mMmramRangeCount = MmramRangeCount;
+ DEBUG ((DEBUG_INFO, "mMmramRangeCount - 0x%x\n", mMmramRangeCount));
+ mMmramRanges = AllocatePool (mMmramRangeCount * sizeof (EFI_MMRAM_DESCRIPTOR));
+ DEBUG ((DEBUG_INFO, "mMmramRanges - 0x%x\n", mMmramRanges));
+ ASSERT (mMmramRanges != NULL);
+ CopyMem (mMmramRanges, (VOID *)(UINTN)MmramRanges, mMmramRangeCount * sizeof (EFI_MMRAM_DESCRIPTOR));
+
+ //
+ // Get Boot Firmware Volume address from the BFV Hob
+ //
+ BfvHob = GetFirstHob (EFI_HOB_TYPE_FV);
+ if (BfvHob != NULL) {
+ DEBUG ((DEBUG_INFO, "BFV address - 0x%x\n", BfvHob->BaseAddress));
+ DEBUG ((DEBUG_INFO, "BFV size - 0x%x\n", BfvHob->Length));
+ gMmCorePrivate->StandaloneBfvAddress = BfvHob->BaseAddress;
+ }
+
+ gMmCorePrivate->Mmst = (EFI_PHYSICAL_ADDRESS)(UINTN)&gMmCoreMmst;
+ gMmCorePrivate->MmEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)MmEntryPoint;
+
+ //
+ // No need to initialize memory service.
+ // It is done in the constructor of StandaloneMmCoreMemoryAllocationLib(),
+ // so that the library linked with StandaloneMmCore can use AllocatePool() in
+ // the constructor.
+
+ DEBUG ((DEBUG_INFO, "MmInstallConfigurationTable For HobList\n"));
+ //
+ // Install HobList
+ //
+ HobSize = GetHobListSize (HobStart);
+ DEBUG ((DEBUG_INFO, "HobSize - 0x%x\n", HobSize));
+ MmHobStart = AllocatePool (HobSize);
+ DEBUG ((DEBUG_INFO, "MmHobStart - 0x%x\n", MmHobStart));
+ ASSERT (MmHobStart != NULL);
+ CopyMem (MmHobStart, HobStart, HobSize);
+ Status = MmInstallConfigurationTable (&gMmCoreMmst, &gEfiHobListGuid, MmHobStart, HobSize);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register notification for EFI_MM_CONFIGURATION_PROTOCOL registration and
+ // use it to register the MM Foundation entrypoint
+ //
+ DEBUG ((DEBUG_INFO, "MmRegisterProtocolNotify - MmConfigurationMmProtocol\n"));
+ Status = MmRegisterProtocolNotify (
+ &gEfiMmConfigurationProtocolGuid,
+ MmConfigurationMmNotify,
+ &Registration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Dispatch standalone BFV
+ //
+ DEBUG ((DEBUG_INFO, "Mm Dispatch StandaloneBfvAddress - 0x%08x\n", gMmCorePrivate->StandaloneBfvAddress));
+ if (gMmCorePrivate->StandaloneBfvAddress != 0) {
+ MmCoreFfsFindMmDriver ((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)gMmCorePrivate->StandaloneBfvAddress);
+ MmDispatcher ();
+ }
+
+ //
+ // Register all handlers in the core table
+ //
+ for (Index = 0; mMmCoreMmiHandlers[Index].HandlerType != NULL; Index++) {
+ Status = MmiHandlerRegister (
+ mMmCoreMmiHandlers[Index].Handler,
+ mMmCoreMmiHandlers[Index].HandlerType,
+ &mMmCoreMmiHandlers[Index].DispatchHandle
+ );
+ DEBUG ((DEBUG_INFO, "MmiHandlerRegister - GUID %g - Status %d\n", mMmCoreMmiHandlers[Index].HandlerType, Status));
+ }
+
+ DEBUG ((DEBUG_INFO, "MmMain Done!\n"));
+
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/StandaloneMmCore.h b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/StandaloneMmCore.h
new file mode 100644
index 00000000..a08c34cb
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/StandaloneMmCore.h
@@ -0,0 +1,853 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by MmCore module.
+
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _MM_CORE_H_
+#define _MM_CORE_H_
+
+#include <PiMm.h>
+#include <StandaloneMm.h>
+
+#include <Protocol/DxeMmReadyToLock.h>
+#include <Protocol/MmReadyToLock.h>
+#include <Protocol/MmEndOfDxe.h>
+#include <Protocol/MmCommunication2.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/MmConfiguration.h>
+
+#include <Guid/Apriori.h>
+#include <Guid/EventGroup.h>
+#include <Guid/EventLegacyBios.h>
+#include <Guid/ZeroGuid.h>
+#include <Guid/MemoryProfile.h>
+#include <Guid/HobList.h>
+#include <Guid/MmFvDispatch.h>
+#include <Guid/MmramMemoryReserve.h>
+
+#include <Library/StandaloneMmCoreEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+
+#include <Library/StandaloneMmMemLib.h>
+#include <Library/HobLib.h>
+
+#include "StandaloneMmCorePrivateData.h"
+
+//
+// Used to build a table of MMI Handlers that the MM Core registers
+//
+typedef struct {
+ EFI_MM_HANDLER_ENTRY_POINT Handler;
+ EFI_GUID *HandlerType;
+ EFI_HANDLE DispatchHandle;
+ BOOLEAN UnRegister;
+} MM_CORE_MMI_HANDLERS;
+
+//
+// Structure for recording the state of an MM Driver
+//
+#define EFI_MM_DRIVER_ENTRY_SIGNATURE SIGNATURE_32('s', 'd','r','v')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link; // mDriverList
+
+ LIST_ENTRY ScheduledLink; // mScheduledQueue
+
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_GUID FileName;
+ VOID *Pe32Data;
+ UINTN Pe32DataSize;
+
+ VOID *Depex;
+ UINTN DepexSize;
+
+ BOOLEAN Before;
+ BOOLEAN After;
+ EFI_GUID BeforeAfterGuid;
+
+ BOOLEAN Dependent;
+ BOOLEAN Scheduled;
+ BOOLEAN Initialized;
+ BOOLEAN DepexProtocolError;
+
+ EFI_HANDLE ImageHandle;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ //
+ // Image EntryPoint in MMRAM
+ //
+ PHYSICAL_ADDRESS ImageEntryPoint;
+ //
+ // Image Buffer in MMRAM
+ //
+ PHYSICAL_ADDRESS ImageBuffer;
+ //
+ // Image Page Number
+ //
+ UINTN NumberOfPage;
+} EFI_MM_DRIVER_ENTRY;
+
+#define EFI_HANDLE_SIGNATURE SIGNATURE_32('h','n','d','l')
+
+///
+/// IHANDLE - contains a list of protocol handles
+///
+typedef struct {
+ UINTN Signature;
+ /// All handles list of IHANDLE
+ LIST_ENTRY AllHandles;
+ /// List of PROTOCOL_INTERFACE's for this handle
+ LIST_ENTRY Protocols;
+ UINTN LocateRequest;
+} IHANDLE;
+
+#define ASSERT_IS_HANDLE(a) ASSERT((a)->Signature == EFI_HANDLE_SIGNATURE)
+
+#define PROTOCOL_ENTRY_SIGNATURE SIGNATURE_32('p','r','t','e')
+
+///
+/// PROTOCOL_ENTRY - each different protocol has 1 entry in the protocol
+/// database. Each handler that supports this protocol is listed, along
+/// with a list of registered notifies.
+///
+typedef struct {
+ UINTN Signature;
+ /// Link Entry inserted to mProtocolDatabase
+ LIST_ENTRY AllEntries;
+ /// ID of the protocol
+ EFI_GUID ProtocolID;
+ /// All protocol interfaces
+ LIST_ENTRY Protocols;
+ /// Registered notification handlers
+ LIST_ENTRY Notify;
+} PROTOCOL_ENTRY;
+
+#define PROTOCOL_INTERFACE_SIGNATURE SIGNATURE_32('p','i','f','c')
+
+///
+/// PROTOCOL_INTERFACE - each protocol installed on a handle is tracked
+/// with a protocol interface structure
+///
+typedef struct {
+ UINTN Signature;
+ /// Link on IHANDLE.Protocols
+ LIST_ENTRY Link;
+ /// Back pointer
+ IHANDLE *Handle;
+ /// Link on PROTOCOL_ENTRY.Protocols
+ LIST_ENTRY ByProtocol;
+ /// The protocol ID
+ PROTOCOL_ENTRY *Protocol;
+ /// The interface value
+ VOID *Interface;
+} PROTOCOL_INTERFACE;
+
+#define PROTOCOL_NOTIFY_SIGNATURE SIGNATURE_32('p','r','t','n')
+
+///
+/// PROTOCOL_NOTIFY - used for each register notification for a protocol
+///
+typedef struct {
+ UINTN Signature;
+ PROTOCOL_ENTRY *Protocol;
+ /// All notifications for this protocol
+ LIST_ENTRY Link;
+ /// Notification function
+ EFI_MM_NOTIFY_FN Function;
+ /// Last position notified
+ LIST_ENTRY *Position;
+} PROTOCOL_NOTIFY;
+
+//
+// MM Core Global Variables
+//
+extern MM_CORE_PRIVATE_DATA *gMmCorePrivate;
+extern EFI_MM_SYSTEM_TABLE gMmCoreMmst;
+extern LIST_ENTRY gHandleList;
+extern EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressMmramBase;
+
+/**
+ 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
+ );
+
+/**
+ The MmInstallConfigurationTable() function is used to maintain the list
+ of configuration tables that are stored in the System Management System
+ Table. The list is stored as an array of (GUID, Pointer) pairs. The list
+ must be allocated from pool memory with PoolType set to EfiRuntimeServicesData.
+
+ @param SystemTable A pointer to the MM System Table (SMST).
+ @param Guid A pointer to the GUID for the entry to add, update, or remove.
+ @param Table A pointer to the buffer of the table to add.
+ @param TableSize The size of the table to install.
+
+ @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.
+ @retval EFI_INVALID_PARAMETER Guid is not valid.
+ @retval EFI_NOT_FOUND An attempt was made to delete a non-existent entry.
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.
+
+**/
+EFI_STATUS
+EFIAPI
+MmInstallConfigurationTable (
+ IN CONST EFI_MM_SYSTEM_TABLE *SystemTable,
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Table,
+ IN UINTN TableSize
+ );
+
+/**
+ Wrapper function to MmInstallProtocolInterfaceNotify. This is the public API which
+ Calls the private one which contains a BOOLEAN parameter for notifications
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+
+ @return Status code
+
+**/
+EFI_STATUS
+EFIAPI
+MmInstallProtocolInterface (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface
+ );
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform
+ @param MemoryType The type of memory to turn the allocated pages
+ into
+ @param NumberOfPages The number of pages to allocate
+ @param Memory A pointer to receive the base allocated memory
+ address
+
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+MmAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ );
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform
+ @param MemoryType The type of memory to turn the allocated pages
+ into
+ @param NumberOfPages The number of pages to allocate
+ @param Memory A pointer to receive the base allocated memory
+ address
+
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+MmInternalAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ );
+
+/**
+ Frees previous allocated pages.
+
+ @param Memory Base address of memory being freed
+ @param NumberOfPages The number of pages to free
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range
+ @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
+ @return EFI_SUCCESS Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+MmFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+/**
+ Frees previous allocated pages.
+
+ @param Memory Base address of memory being freed
+ @param NumberOfPages The number of pages to free
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range
+ @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
+ @return EFI_SUCCESS Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+MmInternalFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER PoolType not valid
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+MmAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ );
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER PoolType not valid
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+MmInternalAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ );
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+MmFreePool (
+ IN VOID *Buffer
+ );
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+MmInternalFreePool (
+ IN VOID *Buffer
+ );
+
+/**
+ Installs a protocol interface into the boot services environment.
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+ @param Notify indicates whether notify the notification list
+ for this protocol
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Protocol interface successfully installed
+
+**/
+EFI_STATUS
+MmInstallProtocolInterfaceNotify (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface,
+ IN BOOLEAN Notify
+ );
+
+/**
+ Uninstalls all instances of a protocol:interfacer from a handle.
+ If the last protocol interface is remove from the handle, the
+ handle is freed.
+
+ @param UserHandle The handle to remove the protocol handler from
+ @param Protocol The protocol, of protocol:interface, to remove
+ @param Interface The interface, of protocol:interface, to remove
+
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_SUCCESS Protocol interface successfully uninstalled.
+
+**/
+EFI_STATUS
+EFIAPI
+MmUninstallProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ );
+
+/**
+ Queries a handle to determine if it supports a specified protocol.
+
+ @param UserHandle The handle being queried.
+ @param Protocol The published unique identifier of the protocol.
+ @param Interface Supplies the address where a pointer to the
+ corresponding Protocol Interface is returned.
+
+ @return The requested protocol interface for the handle
+
+**/
+EFI_STATUS
+EFIAPI
+MmHandleProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface
+ );
+
+/**
+ Add a new protocol notification record for the request protocol.
+
+ @param Protocol The requested protocol to add the notify
+ registration
+ @param Function Points to the notification function
+ @param Registration Returns the registration record
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully returned the registration record
+ that has been added
+
+**/
+EFI_STATUS
+EFIAPI
+MmRegisterProtocolNotify (
+ IN CONST EFI_GUID *Protocol,
+ IN EFI_MM_NOTIFY_FN Function,
+ OUT VOID **Registration
+ );
+
+/**
+ Locates the requested handle(s) and returns them in Buffer.
+
+ @param SearchType The type of search to perform to locate the
+ handles
+ @param Protocol The protocol to search for
+ @param SearchKey Dependant on SearchType
+ @param BufferSize On input the size of Buffer. On output the
+ size of data returned.
+ @param Buffer The buffer to return the results in
+
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is
+ returned in BufferSize.
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully found the requested handle(s) and
+ returns them in Buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+MmLocateHandle (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_HANDLE *Buffer
+ );
+
+/**
+ Return the first Protocol Interface that matches the Protocol GUID. If
+ Registration is passed in return a Protocol Instance that was just add
+ to the system. If Registration is NULL return the first Protocol Interface
+ you find.
+
+ @param Protocol The protocol to search for
+ @param Registration Optional Registration Key returned from
+ RegisterProtocolNotify()
+ @param Interface Return the Protocol interface (instance).
+
+ @retval EFI_SUCCESS If a valid Interface is returned
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_NOT_FOUND Protocol interface not found
+
+**/
+EFI_STATUS
+EFIAPI
+MmLocateProtocol (
+ IN EFI_GUID *Protocol,
+ IN VOID *Registration OPTIONAL,
+ OUT VOID **Interface
+ );
+
+/**
+ Manage MMI of a particular type.
+
+ @param HandlerType Points to the handler type or NULL for root MMI handlers.
+ @param Context Points to an optional context buffer.
+ @param CommBuffer Points to the optional communication buffer.
+ @param CommBufferSize Points to the size of the optional communication buffer.
+
+ @retval EFI_SUCCESS Interrupt source was processed successfully but not quiesced.
+ @retval EFI_INTERRUPT_PENDING One or more MMI sources could not be quiesced.
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was not handled or quiesced.
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED Interrupt source was handled and quiesced.
+
+**/
+EFI_STATUS
+EFIAPI
+MmiManage (
+ IN CONST EFI_GUID *HandlerType,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ Registers a handler to execute within MM.
+
+ @param Handler Handler service function pointer.
+ @param HandlerType Points to the handler type or NULL for root MMI handlers.
+ @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.
+
+ @retval EFI_SUCCESS Handler register success.
+ @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MmiHandlerRegister (
+ IN EFI_MM_HANDLER_ENTRY_POINT Handler,
+ IN CONST EFI_GUID *HandlerType OPTIONAL,
+ OUT EFI_HANDLE *DispatchHandle
+ );
+
+/**
+ Unregister a handler in MM.
+
+ @param DispatchHandle The handle that was specified when the handler was registered.
+
+ @retval EFI_SUCCESS Handler function was successfully unregistered.
+ @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.
+
+**/
+EFI_STATUS
+EFIAPI
+MmiHandlerUnRegister (
+ IN EFI_HANDLE DispatchHandle
+ );
+
+/**
+ This function is the main entry point for an MM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmDriverDispatchHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ This function is the main entry point for an MM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmExitBootServiceHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ This function is the main entry point for an MM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmReadyToBootHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ This function is the main entry point for an MM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmReadyToLockHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ This function is the main entry point for an MM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmEndOfDxeHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ Place holder function until all the MM System Table Service are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+ @param Arg4 Undefined
+ @param Arg5 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+MmEfiNotAvailableYetArg5 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3,
+ UINTN Arg4,
+ UINTN Arg5
+ );
+
+//
+//Functions used during debug builds
+//
+
+/**
+ Traverse the discovered list for any drivers that were discovered but not loaded
+ because the dependency expressions evaluated to false.
+
+**/
+VOID
+MmDisplayDiscoveredNotDispatched (
+ VOID
+ );
+
+/**
+ Add free MMRAM region for use by memory service.
+
+ @param MemBase Base address of memory region.
+ @param MemLength Length of the memory region.
+ @param Type Memory type.
+ @param Attributes Memory region state.
+
+**/
+VOID
+MmAddMemoryRegion (
+ IN EFI_PHYSICAL_ADDRESS MemBase,
+ IN UINT64 MemLength,
+ IN EFI_MEMORY_TYPE Type,
+ IN UINT64 Attributes
+ );
+
+/**
+ Finds the protocol entry for the requested protocol.
+
+ @param Protocol The ID of the protocol
+ @param Create Create a new entry if not found
+
+ @return Protocol entry
+
+**/
+PROTOCOL_ENTRY *
+MmFindProtocolEntry (
+ IN EFI_GUID *Protocol,
+ IN BOOLEAN Create
+ );
+
+/**
+ Signal event for every protocol in protocol entry.
+
+ @param Prot Protocol interface
+
+**/
+VOID
+MmNotifyProtocol (
+ IN PROTOCOL_INTERFACE *Prot
+ );
+
+/**
+ Finds the protocol instance for the requested handle and protocol.
+ Note: This function doesn't do parameters checking, it's caller's responsibility
+ to pass in valid parameters.
+
+ @param Handle The handle to search the protocol on
+ @param Protocol GUID of the protocol
+ @param Interface The interface for the protocol being searched
+
+ @return Protocol instance (NULL: Not found)
+
+**/
+PROTOCOL_INTERFACE *
+MmFindProtocolInterface (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ );
+
+/**
+ Removes Protocol from the protocol list (but not the handle list).
+
+ @param Handle The handle to remove protocol on.
+ @param Protocol GUID of the protocol to be moved
+ @param Interface The interface of the protocol
+
+ @return Protocol Entry
+
+**/
+PROTOCOL_INTERFACE *
+MmRemoveInterfaceFromProtocol (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ );
+
+/**
+ This is the POSTFIX version of the dependency evaluator. This code does
+ not need to handle Before or After, as it is not valid to call this
+ routine in this case. POSTFIX means all the math is done on top of the stack.
+
+ @param DriverEntry DriverEntry element to update.
+
+ @retval TRUE If driver is ready to run.
+ @retval FALSE If driver is not ready to run or some fatal error
+ was found.
+
+**/
+BOOLEAN
+MmIsSchedulable (
+ IN EFI_MM_DRIVER_ENTRY *DriverEntry
+ );
+
+/**
+ Dump MMRAM information.
+
+**/
+VOID
+DumpMmramInfo (
+ VOID
+ );
+
+extern UINTN mMmramRangeCount;
+extern EFI_MMRAM_DESCRIPTOR *mMmramRanges;
+extern EFI_SYSTEM_TABLE *mEfiSystemTable;
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/StandaloneMmCore.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/StandaloneMmCore.inf
new file mode 100644
index 00000000..cd33ce21
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/StandaloneMmCore.inf
@@ -0,0 +1,81 @@
+## @file
+# This module provide an SMM CIS compliant implementation of SMM Core.
+#
+# Copyright (c) 2009 - 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]
+ INF_VERSION = 0x0001001A
+ BASE_NAME = StandaloneMmCore
+ FILE_GUID = 6E14B6FD-3600-4DD6-A17A-206B3B6DCE16
+ MODULE_TYPE = MM_CORE_STANDALONE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x00010032
+ ENTRY_POINT = StandaloneMmMain
+
+# VALID_ARCHITECTURES = IA32 X64 AARCH64
+
+[Sources]
+ StandaloneMmCore.c
+ StandaloneMmCore.h
+ StandaloneMmCorePrivateData.h
+ Page.c
+ Pool.c
+ Handle.c
+ Locate.c
+ Notify.c
+ Dependency.c
+ Dispatcher.c
+ Mmi.c
+ InstallConfigurationTable.c
+ FwVol.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ StandaloneMmPkg/StandaloneMmPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ CacheMaintenanceLib
+ DebugLib
+ ExtractGuidedSectionLib
+ FvLib
+ HobLib
+ MemoryAllocationLib
+ MemLib
+ PeCoffLib
+ ReportStatusCodeLib
+ StandaloneMmCoreEntryPoint
+
+[Protocols]
+ gEfiDxeMmReadyToLockProtocolGuid ## UNDEFINED # SmiHandlerRegister
+ gEfiMmReadyToLockProtocolGuid ## PRODUCES
+ gEfiMmEndOfDxeProtocolGuid ## PRODUCES
+ gEfiLoadedImageProtocolGuid ## PRODUCES
+ gEfiMmConfigurationProtocolGuid ## CONSUMES
+
+[Guids]
+ gAprioriGuid ## SOMETIMES_CONSUMES ## File
+ gEfiEventDxeDispatchGuid ## PRODUCES ## GUID # SmiHandlerRegister
+ gEfiEndOfDxeEventGroupGuid ## PRODUCES ## GUID # SmiHandlerRegister
+ ## SOMETIMES_CONSUMES ## GUID # Locate protocol
+ ## SOMETIMES_PRODUCES ## GUID # SmiHandlerRegister
+ gEdkiiMemoryProfileGuid
+ gZeroGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiHobListGuid
+ gEfiHobMemoryAllocModuleGuid
+ gMmCoreDataHobGuid
+ gMmFvDispatchGuid
+ gEfiEventLegacyBootGuid
+ gEfiEventExitBootServicesGuid
+ gEfiEventReadyToBootGuid
+
+[BuildOptions]
+ GCC:*_*_*_CC_FLAGS = -fpie
+ GCC:*_*_*_DLINK_FLAGS = -Wl,-z,text,-Bsymbolic,-pie
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/StandaloneMmCorePrivateData.h b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/StandaloneMmCorePrivateData.h
new file mode 100644
index 00000000..721888b5
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Core/StandaloneMmCorePrivateData.h
@@ -0,0 +1,60 @@
+/** @file
+ The internal header file that declared a data structure that is shared
+ between the MM IPL and the MM Core.
+
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _STANDALONE_MM_CORE_PRIVATE_DATA_H_
+#define _STANDALONE_MM_CORE_PRIVATE_DATA_H_
+
+#include <Guid/MmCoreData.h>
+
+//
+// Page management
+//
+
+typedef struct {
+ LIST_ENTRY Link;
+ UINTN NumberOfPages;
+} FREE_PAGE_LIST;
+
+extern LIST_ENTRY mMmMemoryMap;
+
+//
+// Pool management
+//
+
+//
+// MIN_POOL_SHIFT must not be less than 5
+//
+#define MIN_POOL_SHIFT 6
+#define MIN_POOL_SIZE (1 << MIN_POOL_SHIFT)
+
+//
+// MAX_POOL_SHIFT must not be less than EFI_PAGE_SHIFT - 1
+//
+#define MAX_POOL_SHIFT (EFI_PAGE_SHIFT - 1)
+#define MAX_POOL_SIZE (1 << MAX_POOL_SHIFT)
+
+//
+// MAX_POOL_INDEX are calculated by maximum and minimum pool sizes
+//
+#define MAX_POOL_INDEX (MAX_POOL_SHIFT - MIN_POOL_SHIFT + 1)
+
+typedef struct {
+ UINTN Size;
+ BOOLEAN Available;
+} POOL_HEADER;
+
+typedef struct {
+ POOL_HEADER Header;
+ LIST_ENTRY Link;
+} FREE_POOL_HEADER;
+
+extern LIST_ENTRY mMmPoolLists[MAX_POOL_INDEX];
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/EventHandle.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/EventHandle.c
new file mode 100644
index 00000000..c5139bec
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/EventHandle.c
@@ -0,0 +1,250 @@
+/** @file
+
+ Copyright (c) 2016 HP Development Company, L.P.
+ Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Pi/PiMmCis.h>
+
+
+#include <Library/ArmSvcLib.h>
+#include <Library/ArmLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+
+#include <Protocol/DebugSupport.h> // for EFI_SYSTEM_CONTEXT
+
+#include <Guid/ZeroGuid.h>
+#include <Guid/MmramMemoryReserve.h>
+
+#include <IndustryStandard/ArmFfaSvc.h>
+#include <IndustryStandard/ArmStdSmc.h>
+
+#include "StandaloneMmCpu.h"
+
+EFI_STATUS
+EFIAPI
+MmFoundationEntryRegister (
+ IN CONST EFI_MM_CONFIGURATION_PROTOCOL *This,
+ IN EFI_MM_ENTRY_POINT MmEntryPoint
+ );
+
+//
+// On ARM platforms every event is expected to have a GUID associated with
+// it. It will be used by the MM Entry point to find the handler for the
+// event. It will either be populated in a EFI_MM_COMMUNICATE_HEADER by the
+// caller of the event (e.g. MM_COMMUNICATE SMC) or by the CPU driver
+// (e.g. during an asynchronous event). In either case, this context is
+// maintained in an array which has an entry for each CPU. The pointer to this
+// array is held in PerCpuGuidedEventContext. Memory is allocated once the
+// number of CPUs in the system are made known through the
+// MP_INFORMATION_HOB_DATA.
+//
+EFI_MM_COMMUNICATE_HEADER **PerCpuGuidedEventContext = NULL;
+
+// Descriptor with whereabouts of memory used for communication with the normal world
+EFI_MMRAM_DESCRIPTOR mNsCommBuffer;
+
+MP_INFORMATION_HOB_DATA *mMpInformationHobData;
+
+EFI_MM_CONFIGURATION_PROTOCOL mMmConfig = {
+ 0,
+ MmFoundationEntryRegister
+};
+
+STATIC EFI_MM_ENTRY_POINT mMmEntryPoint = NULL;
+
+/**
+ The PI Standalone MM entry point for the TF-A CPU driver.
+
+ @param [in] EventId The event Id.
+ @param [in] CpuNumber The CPU number.
+ @param [in] NsCommBufferAddr Address of the NS common buffer.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER A parameter was invalid.
+ @retval EFI_ACCESS_DENIED Access not permitted.
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+ @retval EFI_UNSUPPORTED Operation not supported.
+**/
+EFI_STATUS
+PiMmStandaloneArmTfCpuDriverEntry (
+ IN UINTN EventId,
+ IN UINTN CpuNumber,
+ IN UINTN NsCommBufferAddr
+ )
+{
+ EFI_MM_COMMUNICATE_HEADER *GuidedEventContext;
+ EFI_MM_ENTRY_CONTEXT MmEntryPointContext;
+ EFI_STATUS Status;
+ UINTN NsCommBufferSize;
+
+ DEBUG ((DEBUG_INFO, "Received event - 0x%x on cpu %d\n", EventId, CpuNumber));
+
+ Status = EFI_SUCCESS;
+ //
+ // ARM TF passes SMC FID of the MM_COMMUNICATE interface as the Event ID upon
+ // receipt of a synchronous MM request. Use the Event ID to distinguish
+ // between synchronous and asynchronous events.
+ //
+ if ((ARM_SMC_ID_MM_COMMUNICATE_AARCH64 != EventId) &&
+ (ARM_SVC_ID_FFA_MSG_SEND_DIRECT_REQ_AARCH64 != EventId)) {
+ DEBUG ((DEBUG_INFO, "UnRecognized Event - 0x%x\n", EventId));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Perform parameter validation of NsCommBufferAddr
+ if (NsCommBufferAddr == (UINTN)NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (NsCommBufferAddr < mNsCommBuffer.PhysicalStart) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ if ((NsCommBufferAddr + sizeof (EFI_MM_COMMUNICATE_HEADER)) >=
+ (mNsCommBuffer.PhysicalStart + mNsCommBuffer.PhysicalSize)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Find out the size of the buffer passed
+ NsCommBufferSize = ((EFI_MM_COMMUNICATE_HEADER *) NsCommBufferAddr)->MessageLength +
+ sizeof (EFI_MM_COMMUNICATE_HEADER);
+
+ // perform bounds check.
+ if (NsCommBufferAddr + NsCommBufferSize >=
+ mNsCommBuffer.PhysicalStart + mNsCommBuffer.PhysicalSize) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ GuidedEventContext = NULL;
+ // Now that the secure world can see the normal world buffer, allocate
+ // memory to copy the communication buffer to the secure world.
+ Status = mMmst->MmAllocatePool (
+ EfiRuntimeServicesData,
+ NsCommBufferSize,
+ (VOID **) &GuidedEventContext
+ );
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "Mem alloc failed - 0x%x\n", EventId));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ // X1 contains the VA of the normal world memory accessible from
+ // S-EL0
+ CopyMem (GuidedEventContext, (CONST VOID *) NsCommBufferAddr, NsCommBufferSize);
+
+ // Stash the pointer to the allocated Event Context for this CPU
+ PerCpuGuidedEventContext[CpuNumber] = GuidedEventContext;
+
+ ZeroMem (&MmEntryPointContext, sizeof (EFI_MM_ENTRY_CONTEXT));
+
+ MmEntryPointContext.CurrentlyExecutingCpu = CpuNumber;
+ MmEntryPointContext.NumberOfCpus = mMpInformationHobData->NumberOfProcessors;
+
+ // Populate the MM system table with MP and state information
+ mMmst->CurrentlyExecutingCpu = CpuNumber;
+ mMmst->NumberOfCpus = mMpInformationHobData->NumberOfProcessors;
+ mMmst->CpuSaveStateSize = 0;
+ mMmst->CpuSaveState = NULL;
+
+ if (mMmEntryPoint == NULL) {
+ DEBUG ((DEBUG_INFO, "Mm Entry point Not Found\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ mMmEntryPoint (&MmEntryPointContext);
+
+ // Free the memory allocation done earlier and reset the per-cpu context
+ ASSERT (GuidedEventContext);
+ CopyMem ((VOID *)NsCommBufferAddr, (CONST VOID *) GuidedEventContext, NsCommBufferSize);
+
+ Status = mMmst->MmFreePool ((VOID *) GuidedEventContext);
+ if (Status != EFI_SUCCESS) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ PerCpuGuidedEventContext[CpuNumber] = NULL;
+
+ return Status;
+}
+
+/**
+ Registers the MM foundation entry point.
+
+ @param [in] This Pointer to the MM Configuration protocol.
+ @param [in] MmEntryPoint Function pointer to the MM Entry point.
+
+ @retval EFI_SUCCESS Success.
+**/
+EFI_STATUS
+EFIAPI
+MmFoundationEntryRegister (
+ IN CONST EFI_MM_CONFIGURATION_PROTOCOL *This,
+ IN EFI_MM_ENTRY_POINT MmEntryPoint
+ )
+{
+ // store the entry point in a global
+ mMmEntryPoint = MmEntryPoint;
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is the main entry point for an MM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by
+ MmiHandlerRegister().
+ @param Context Points to an optional handler context which was
+ specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an
+ MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+PiMmCpuTpFwRootMmiHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN CpuNumber;
+
+ ASSERT (Context == NULL);
+ ASSERT (CommBuffer == NULL);
+ ASSERT (CommBufferSize == NULL);
+
+ CpuNumber = mMmst->CurrentlyExecutingCpu;
+ if (PerCpuGuidedEventContext[CpuNumber] == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ DEBUG ((DEBUG_INFO, "CommBuffer - 0x%x, CommBufferSize - 0x%x\n",
+ PerCpuGuidedEventContext[CpuNumber],
+ PerCpuGuidedEventContext[CpuNumber]->MessageLength));
+
+ Status = mMmst->MmiManage (
+ &PerCpuGuidedEventContext[CpuNumber]->HeaderGuid,
+ NULL,
+ PerCpuGuidedEventContext[CpuNumber]->Data,
+ &PerCpuGuidedEventContext[CpuNumber]->MessageLength
+ );
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_WARN, "Unable to manage Guided Event - %d\n", Status));
+ }
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/StandaloneMmCpu.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/StandaloneMmCpu.c
new file mode 100644
index 00000000..b543733e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/StandaloneMmCpu.c
@@ -0,0 +1,250 @@
+/** @file
+
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
+ Copyright (c) 2016 HP Development Company, L.P.
+ Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Pi/PiMmCis.h>
+#include <Library/AArch64/StandaloneMmCoreEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/ArmSvcLib.h>
+#include <Library/ArmLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/HobLib.h>
+
+#include <Protocol/DebugSupport.h> // for EFI_SYSTEM_CONTEXT
+
+#include <Guid/ZeroGuid.h>
+#include <Guid/MmramMemoryReserve.h>
+
+
+#include "StandaloneMmCpu.h"
+
+// 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 this CPU driver will be
+// populated to allow the entry point driver to invoke it upon receipt of an
+// event
+extern EFI_GUID gEfiArmTfCpuDriverEpDescriptorGuid;
+
+//
+// Private copy of the MM system table for future use
+//
+EFI_MM_SYSTEM_TABLE *mMmst = NULL;
+
+//
+// Globals used to initialize the protocol
+//
+STATIC EFI_HANDLE mMmCpuHandle = NULL;
+
+/** Returns the HOB data for the matching HOB GUID.
+
+ @param [in] HobList Pointer to the HOB list.
+ @param [in] HobGuid The GUID for the HOB.
+ @param [out] HobData Pointer to the HOB data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Could not find HOB with matching GUID.
+**/
+EFI_STATUS
+GetGuidedHobData (
+ IN VOID *HobList,
+ IN CONST EFI_GUID *HobGuid,
+ OUT VOID **HobData
+ )
+{
+ EFI_HOB_GUID_TYPE *Hob;
+
+ if ((HobList == NULL) || (HobGuid == NULL) || (HobData == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Hob = GetNextGuidHob (HobGuid, HobList);
+ if (Hob == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ *HobData = GET_GUID_HOB_DATA (Hob);
+ if (*HobData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/** Entry point for the Standalone MM CPU driver.
+
+ @param [in] ImageHandle Unused. Not actual image handle.
+ @param [in] SystemTable Pointer to MM System table.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+ @retval EFI_NOT_FOUND Failed to find the HOB for the CPU
+ driver endpoint descriptor.
+**/
+EFI_STATUS
+StandaloneMmCpuInitialize (
+ IN EFI_HANDLE ImageHandle, // not actual imagehandle
+ IN EFI_MM_SYSTEM_TABLE *SystemTable // not actual systemtable
+ )
+{
+ ARM_TF_CPU_DRIVER_EP_DESCRIPTOR *CpuDriverEntryPointDesc;
+ EFI_CONFIGURATION_TABLE *ConfigurationTable;
+ MP_INFORMATION_HOB_DATA *MpInformationHobData;
+ EFI_MMRAM_DESCRIPTOR *NsCommBufMmramRange;
+ EFI_STATUS Status;
+ EFI_HANDLE DispatchHandle;
+ UINT32 MpInfoSize;
+ UINTN Index;
+ UINTN ArraySize;
+ VOID *HobStart;
+
+ ASSERT (SystemTable != NULL);
+ mMmst = SystemTable;
+
+ // publish the MM config protocol so the MM core can register its entry point
+ Status = mMmst->MmInstallProtocolInterface (
+ &mMmCpuHandle,
+ &gEfiMmConfigurationProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mMmConfig
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // register the root MMI handler
+ Status = mMmst->MmiHandlerRegister (
+ PiMmCpuTpFwRootMmiHandler,
+ NULL,
+ &DispatchHandle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Retrieve the Hoblist from the MMST to extract the details of the NS
+ // communication buffer that has been reserved by S-EL1/EL3
+ ConfigurationTable = mMmst->MmConfigurationTable;
+ for (Index = 0; Index < mMmst->NumberOfTableEntries; Index++) {
+ if (CompareGuid (&gEfiHobListGuid, &(ConfigurationTable[Index].VendorGuid))) {
+ break;
+ }
+ }
+
+ // Bail out if the Hoblist could not be found
+ if (Index >= mMmst->NumberOfTableEntries) {
+ DEBUG ((DEBUG_INFO, "Hoblist not found - 0x%x\n", Index));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ HobStart = ConfigurationTable[Index].VendorTable;
+
+ //
+ // Locate the HOB with the buffer to populate the entry point of this driver
+ //
+ Status = GetGuidedHobData (
+ HobStart,
+ &gEfiArmTfCpuDriverEpDescriptorGuid,
+ (VOID **) &CpuDriverEntryPointDesc
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "ArmTfCpuDriverEpDesc HOB data extraction failed - 0x%x\n", Status));
+ return Status;
+ }
+
+ // Share the entry point of the CPU driver
+ DEBUG ((DEBUG_INFO, "Sharing Cpu Driver EP *0x%lx = 0x%lx\n",
+ (UINT64) CpuDriverEntryPointDesc->ArmTfCpuDriverEpPtr,
+ (UINT64) PiMmStandaloneArmTfCpuDriverEntry));
+ *(CpuDriverEntryPointDesc->ArmTfCpuDriverEpPtr) = PiMmStandaloneArmTfCpuDriverEntry;
+
+ // Find the descriptor that contains the whereabouts of the buffer for
+ // communication with the Normal world.
+ Status = GetGuidedHobData (
+ HobStart,
+ &gEfiStandaloneMmNonSecureBufferGuid,
+ (VOID **) &NsCommBufMmramRange
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "NsCommBufMmramRange HOB data extraction failed - 0x%x\n", Status));
+ return Status;
+ }
+
+ DEBUG ((DEBUG_INFO, "mNsCommBuffer.PhysicalStart - 0x%lx\n", (UINT64) NsCommBufMmramRange->PhysicalStart));
+ DEBUG ((DEBUG_INFO, "mNsCommBuffer.PhysicalSize - 0x%lx\n", (UINT64) NsCommBufMmramRange->PhysicalSize));
+
+ CopyMem (&mNsCommBuffer, NsCommBufMmramRange, sizeof(EFI_MMRAM_DESCRIPTOR));
+ DEBUG ((DEBUG_INFO, "mNsCommBuffer: 0x%016lx - 0x%lx\n", mNsCommBuffer.CpuStart, mNsCommBuffer.PhysicalSize));
+
+ //
+ // Extract the MP information from the Hoblist
+ //
+ Status = GetGuidedHobData (
+ HobStart,
+ &gMpInformationHobGuid,
+ (VOID **) &MpInformationHobData
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "MpInformationHob extraction failed - 0x%x\n", Status));
+ return Status;
+ }
+
+ //
+ // Allocate memory for the MP information and copy over the MP information
+ // passed by Trusted Firmware. Use the number of processors passed in the HOB
+ // to copy the processor information
+ //
+ MpInfoSize = sizeof (MP_INFORMATION_HOB_DATA) +
+ (sizeof (EFI_PROCESSOR_INFORMATION) *
+ MpInformationHobData->NumberOfProcessors);
+ Status = mMmst->MmAllocatePool (
+ EfiRuntimeServicesData,
+ MpInfoSize,
+ (VOID **) &mMpInformationHobData
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "mMpInformationHobData mem alloc failed - 0x%x\n", Status));
+ return Status;
+ }
+
+ CopyMem (mMpInformationHobData, MpInformationHobData, MpInfoSize);
+
+ // Print MP information
+ DEBUG ((DEBUG_INFO, "mMpInformationHobData: 0x%016lx - 0x%lx\n",
+ mMpInformationHobData->NumberOfProcessors,
+ mMpInformationHobData->NumberOfEnabledProcessors));
+ for (Index = 0; Index < mMpInformationHobData->NumberOfProcessors; Index++) {
+ DEBUG ((DEBUG_INFO, "mMpInformationHobData[0x%lx]: %d, %d, %d\n",
+ mMpInformationHobData->ProcessorInfoBuffer[Index].ProcessorId,
+ mMpInformationHobData->ProcessorInfoBuffer[Index].Location.Package,
+ mMpInformationHobData->ProcessorInfoBuffer[Index].Location.Core,
+ mMpInformationHobData->ProcessorInfoBuffer[Index].Location.Thread));
+ }
+
+ //
+ // Allocate memory for a table to hold pointers to a
+ // EFI_MM_COMMUNICATE_HEADER for each CPU
+ //
+ ArraySize = sizeof (EFI_MM_COMMUNICATE_HEADER *) *
+ mMpInformationHobData->NumberOfEnabledProcessors;
+ Status = mMmst->MmAllocatePool (
+ EfiRuntimeServicesData,
+ ArraySize,
+ (VOID **) &PerCpuGuidedEventContext
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "PerCpuGuidedEventContext mem alloc failed - 0x%x\n", Status));
+ return Status;
+ }
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/StandaloneMmCpu.h b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/StandaloneMmCpu.h
new file mode 100644
index 00000000..9058428d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/StandaloneMmCpu.h
@@ -0,0 +1,81 @@
+/** @file
+ Private header with declarations and definitions specific to the MM Standalone
+ CPU driver
+
+ Copyright (c) 2017 - 2021, Arm Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _ARM_TF_CPU_DRIVER_H_
+#define _ARM_TF_CPU_DRIVER_H_
+
+#include <Protocol/MmCommunication2.h>
+#include <Protocol/MmConfiguration.h>
+#include <Protocol/MmCpu.h>
+#include <Guid/MpInformation.h>
+
+//
+// CPU driver initialization specific declarations
+//
+extern EFI_MM_SYSTEM_TABLE *mMmst;
+
+//
+// CPU State Save protocol specific declarations
+//
+extern EFI_MM_CPU_PROTOCOL mMmCpuState;
+
+//
+// MM event handling specific declarations
+//
+extern EFI_MM_COMMUNICATE_HEADER **PerCpuGuidedEventContext;
+extern EFI_MMRAM_DESCRIPTOR mNsCommBuffer;
+extern MP_INFORMATION_HOB_DATA *mMpInformationHobData;
+extern EFI_MM_CONFIGURATION_PROTOCOL mMmConfig;
+
+/**
+ The PI Standalone MM entry point for the TF-A CPU driver.
+
+ @param [in] EventId The event Id.
+ @param [in] CpuNumber The CPU number.
+ @param [in] NsCommBufferAddr Address of the NS common buffer.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER A parameter was invalid.
+ @retval EFI_ACCESS_DENIED Access not permitted.
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+ @retval EFI_UNSUPPORTED Operation not supported.
+**/
+EFI_STATUS
+PiMmStandaloneArmTfCpuDriverEntry (
+ IN UINTN EventId,
+ IN UINTN CpuNumber,
+ IN UINTN NsCommBufferAddr
+ );
+
+/**
+ This function is the main entry point for an MM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by
+ MmiHandlerRegister().
+ @param Context Points to an optional handler context which was
+ specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an
+ MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+PiMmCpuTpFwRootMmiHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/StandaloneMmCpu.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/StandaloneMmCpu.inf
new file mode 100644
index 00000000..460d9ce8
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/StandaloneMmCpu.inf
@@ -0,0 +1,52 @@
+## @file
+# Standalone MM CPU driver for ARM Standard Platforms
+#
+# Copyright (c) 2009, Apple Inc. All rights reserved.<BR>
+# Copyright (c) 2016 HP Development Company, L.P.
+# Copyright (c) 2017 - 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x0001001A
+ BASE_NAME = StandaloneMmCpu
+ FILE_GUID = 58F7A62B-6280-42A7-BC38-10535A64A92C
+ MODULE_TYPE = MM_STANDALONE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x00010032
+ ENTRY_POINT = StandaloneMmCpuInitialize
+
+[Sources]
+ StandaloneMmCpu.c
+ StandaloneMmCpu.h
+ EventHandle.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ StandaloneMmPkg/StandaloneMmPkg.dec
+
+[LibraryClasses]
+ ArmLib
+ ArmSvcLib
+ BaseMemoryLib
+ DebugLib
+ HobLib
+ StandaloneMmDriverEntryPoint
+
+[Protocols]
+ gEfiMmConfigurationProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+ gEfiMmCpuProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+
+[Guids]
+ gEfiHobListGuid
+ gEfiMmPeiMmramMemoryReserveGuid
+ gZeroGuid
+ gMpInformationHobGuid
+ gEfiStandaloneMmNonSecureBufferGuid
+ gEfiArmTfCpuDriverEpDescriptorGuid
+
+[Depex]
+ TRUE
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Guid/MmCoreData.h b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Guid/MmCoreData.h
new file mode 100644
index 00000000..6c33b4be
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Guid/MmCoreData.h
@@ -0,0 +1,127 @@
+/** @file
+ MM Core data.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2018 - 2021, Arm Limited. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __MM_CORE_DATA_H__
+#define __MM_CORE_DATA_H__
+
+#define MM_CORE_DATA_HOB_GUID \
+ { 0xa160bf99, 0x2aa4, 0x4d7d, { 0x99, 0x93, 0x89, 0x9c, 0xb1, 0x2d, 0xf3, 0x76 }}
+
+extern EFI_GUID gMmCoreDataHobGuid;
+
+typedef struct {
+ //
+ // Address pointer to MM_CORE_PRIVATE_DATA
+ //
+ EFI_PHYSICAL_ADDRESS Address;
+} MM_CORE_DATA_HOB_DATA;
+
+
+///
+/// Define values for the communications buffer used when gEfiEventDxeDispatchGuid is
+/// event signaled. This event is signaled by the DXE Core each time the DXE Core
+/// dispatcher has completed its work. When this event is signaled, the MM Core
+/// if notified, so the MM Core can dispatch MM drivers. If COMM_BUFFER_MM_DISPATCH_ERROR
+/// is returned in the communication buffer, then an error occurred dispatching MM
+/// Drivers. If COMM_BUFFER_MM_DISPATCH_SUCCESS is returned, then the MM Core
+/// dispatched all the drivers it could. If COMM_BUFFER_MM_DISPATCH_RESTART is
+/// returned, then the MM Core just dispatched the MM Driver that registered
+/// the MM Entry Point enabling the use of MM Mode. In this case, the MM Core
+/// should be notified again to dispatch more MM Drivers using MM Mode.
+///
+#define COMM_BUFFER_MM_DISPATCH_ERROR 0x00
+#define COMM_BUFFER_MM_DISPATCH_SUCCESS 0x01
+#define COMM_BUFFER_MM_DISPATCH_RESTART 0x02
+
+///
+/// Signature for the private structure shared between the MM IPL and the MM Core
+///
+#define MM_CORE_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('m', 'm', 'i', 'c')
+
+///
+/// Private structure that is used to share information between the MM IPL and
+/// the MM Core. This structure is allocated from memory of type EfiRuntimeServicesData.
+/// Since runtime memory types are converted to available memory when a legacy boot
+/// is performed, the MM Core must not access any fields of this structure if a legacy
+/// boot is performed. As a result, the MM IPL must create an event notification
+/// for the Legacy Boot event and notify the MM Core that a legacy boot is being
+/// performed. The MM Core can then use this information to filter accesses to
+/// thos structure.
+///
+typedef struct {
+ UINT64 Signature;
+
+ ///
+ /// The number of MMRAM ranges passed from the MM IPL to the MM Core. The MM
+ /// Core uses these ranges of MMRAM to initialize the MM Core memory manager.
+ ///
+ UINT64 MmramRangeCount;
+
+ ///
+ /// A table of MMRAM ranges passed from the MM IPL to the MM Core. The MM
+ /// Core uses these ranges of MMRAM to initialize the MM Core memory manager.
+ ///
+ EFI_PHYSICAL_ADDRESS MmramRanges;
+
+ ///
+ /// The MM Foundation Entry Point. The MM Core fills in this field when the
+ /// MM Core is initialized. The MM IPL is responsbile for registering this entry
+ /// point with the MM Configuration Protocol. The MM Configuration Protocol may
+ /// not be available at the time the MM IPL and MM Core are started, so the MM IPL
+ /// sets up a protocol notification on the MM Configuration Protocol and registers
+ /// the MM Foundation Entry Point as soon as the MM Configuration Protocol is
+ /// available.
+ ///
+ EFI_PHYSICAL_ADDRESS MmEntryPoint;
+
+ ///
+ /// Boolean flag set to TRUE while an MMI is being processed by the MM Core.
+ ///
+ BOOLEAN MmEntryPointRegistered;
+
+ ///
+ /// Boolean flag set to TRUE while an MMI is being processed by the MM Core.
+ ///
+ BOOLEAN InMm;
+
+ ///
+ /// This field is set by the MM Core then the MM Core is initialized. This field is
+ /// used by the MM Base 2 Protocol and MM Communication Protocol implementations in
+ /// the MM IPL.
+ ///
+ EFI_PHYSICAL_ADDRESS Mmst;
+
+ ///
+ /// This field is used by the MM Communication Protocol to pass a buffer into
+ /// a software MMI handler and for the software MMI handler to pass a buffer back to
+ /// the caller of the MM Communication Protocol.
+ ///
+ EFI_PHYSICAL_ADDRESS CommunicationBuffer;
+
+ ///
+ /// This field is used by the MM Communication Protocol to pass the size of a buffer,
+ /// in bytes, into a software MMI handler and for the software MMI handler to pass the
+ /// size, in bytes, of a buffer back to the caller of the MM Communication Protocol.
+ ///
+ UINT64 BufferSize;
+
+ ///
+ /// This field is used by the MM Communication Protocol to pass the return status from
+ /// a software MMI handler back to the caller of the MM Communication Protocol.
+ ///
+ UINT64 ReturnStatus;
+
+ EFI_PHYSICAL_ADDRESS MmCoreImageBase;
+ UINT64 MmCoreImageSize;
+ EFI_PHYSICAL_ADDRESS MmCoreEntryPoint;
+
+ EFI_PHYSICAL_ADDRESS StandaloneBfvAddress;
+} MM_CORE_PRIVATE_DATA;
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Guid/MmFvDispatch.h b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Guid/MmFvDispatch.h
new file mode 100644
index 00000000..162a3890
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Guid/MmFvDispatch.h
@@ -0,0 +1,33 @@
+/** @file
+ GUIDs for MM Event.
+
+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
+
+**/
+
+#ifndef __MM_FV_DISPATCH_H__
+#define __MM_FV_DISPATCH_H__
+
+#define MM_FV_DISPATCH_GUID \
+ { 0xb65694cc, 0x9e3, 0x4c3b, { 0xb5, 0xcd, 0x5, 0xf4, 0x4d, 0x3c, 0xdb, 0xff }}
+
+extern EFI_GUID gMmFvDispatchGuid;
+
+#pragma pack(1)
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS Address;
+ UINT64 Size;
+} EFI_MM_COMMUNICATE_FV_DISPATCH_DATA;
+
+typedef struct {
+ EFI_GUID HeaderGuid;
+ UINTN MessageLength;
+ EFI_MM_COMMUNICATE_FV_DISPATCH_DATA Data;
+} EFI_MM_COMMUNICATE_FV_DISPATCH;
+#pragma pack()
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Guid/MmramMemoryReserve.h b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Guid/MmramMemoryReserve.h
new file mode 100644
index 00000000..1d98d601
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Guid/MmramMemoryReserve.h
@@ -0,0 +1,56 @@
+/** @file
+ Definition of GUIDed HOB for reserving MMRAM regions.
+
+ This file defines:
+ * the GUID used to identify the GUID HOB for reserving MMRAM regions.
+ * the data structure of MMRAM descriptor to describe MMRAM candidate regions
+ * values of state of MMRAM candidate regions
+ * the GUID specific data structure of HOB for reserving MMRAM regions.
+ This GUIDed HOB can be used to convey the existence of the T-SEG reservation and H-SEG usage
+
+Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Revision Reference:
+ GUIDs defined in MmCis spec version 0.9.
+
+**/
+
+#ifndef _EFI_MM_PEI_MMRAM_MEMORY_RESERVE_H_
+#define _EFI_MM_PEI_MMRAM_MEMORY_RESERVE_H_
+
+#define EFI_MM_PEI_MMRAM_MEMORY_RESERVE \
+ { \
+ 0x0703f912, 0xbf8d, 0x4e2a, {0xbe, 0x07, 0xab, 0x27, 0x25, 0x25, 0xc5, 0x92 } \
+ }
+
+/**
+* GUID specific data structure of HOB for reserving MMRAM regions.
+*
+* Inconsistent with specification here:
+* EFI_HOB_MMRAM_DESCRIPTOR_BLOCK has been changed to EFI_MMRAM_HOB_DESCRIPTOR_BLOCK.
+* This inconsistency is kept in code in order for backward compatibility.
+**/
+typedef struct {
+ ///
+ /// Designates the number of possible regions in the system
+ /// that can be usable for MMRAM.
+ ///
+ /// Inconsistent with specification here:
+ /// In Framework MM CIS 0.91 specification, it defines the field type as UINTN.
+ /// However, HOBs are supposed to be CPU neutral, so UINT32 should be used instead.
+ ///
+ UINT32 NumberOfMmReservedRegions;
+ ///
+ /// Used throughout this protocol to describe the candidate
+ /// regions for MMRAM that are supported by this platform.
+ ///
+ EFI_MMRAM_DESCRIPTOR Descriptor[1];
+} EFI_MMRAM_HOB_DESCRIPTOR_BLOCK;
+
+extern EFI_GUID gEfiMmPeiSmramMemoryReserveGuid;
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Guid/MpInformation.h b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Guid/MpInformation.h
new file mode 100644
index 00000000..d3d0e992
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Guid/MpInformation.h
@@ -0,0 +1,35 @@
+/** @file
+ EFI MP information protocol provides a lightweight MP_SERVICES_PROTOCOL.
+
+ MP information protocol only provides static information of MP processor.
+
+ Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _MP_INFORMATION_H_
+#define _MP_INFORMATION_H_
+
+#include <Protocol/MpService.h>
+#include <PiPei.h>
+#include <Ppi/SecPlatformInformation.h>
+
+#define MP_INFORMATION_GUID \
+ { \
+ 0xba33f15d, 0x4000, 0x45c1, {0x8e, 0x88, 0xf9, 0x16, 0x92, 0xd4, 0x57, 0xe3} \
+ }
+
+#pragma pack(1)
+typedef struct {
+ UINT64 NumberOfProcessors;
+ UINT64 NumberOfEnabledProcessors;
+ EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer[];
+} MP_INFORMATION_HOB_DATA;
+#pragma pack()
+
+extern EFI_GUID gMpInformationHobGuid;
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Library/AArch64/StandaloneMmCoreEntryPoint.h b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Library/AArch64/StandaloneMmCoreEntryPoint.h
new file mode 100644
index 00000000..d13b0665
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Library/AArch64/StandaloneMmCoreEntryPoint.h
@@ -0,0 +1,216 @@
+/** @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
+
+**/
+
+#ifndef __STANDALONEMMCORE_ENTRY_POINT_H__
+#define __STANDALONEMMCORE_ENTRY_POINT_H__
+
+#include <Library/PeCoffLib.h>
+#include <Library/FvLib.h>
+
+#define CPU_INFO_FLAG_PRIMARY_CPU 0x00000001
+
+typedef struct {
+ UINT8 Type; /* type of the structure */
+ UINT8 Version; /* version of this structure */
+ UINT16 Size; /* size of this structure in bytes */
+ UINT32 Attr; /* attributes: unused bits SBZ */
+} EFI_PARAM_HEADER;
+
+typedef struct {
+ UINT64 Mpidr;
+ UINT32 LinearId;
+ UINT32 Flags;
+} EFI_SECURE_PARTITION_CPU_INFO;
+
+typedef struct {
+ EFI_PARAM_HEADER Header;
+ UINT64 SpMemBase;
+ UINT64 SpMemLimit;
+ UINT64 SpImageBase;
+ UINT64 SpStackBase;
+ UINT64 SpHeapBase;
+ UINT64 SpNsCommBufBase;
+ UINT64 SpSharedBufBase;
+ UINT64 SpImageSize;
+ UINT64 SpPcpuStackSize;
+ UINT64 SpHeapSize;
+ UINT64 SpNsCommBufSize;
+ UINT64 SpPcpuSharedBufSize;
+ UINT32 NumSpMemRegions;
+ UINT32 NumCpus;
+ EFI_SECURE_PARTITION_CPU_INFO *CpuInfo;
+} EFI_SECURE_PARTITION_BOOT_INFO;
+
+typedef
+EFI_STATUS
+(*PI_MM_ARM_TF_CPU_DRIVER_ENTRYPOINT) (
+ IN UINTN EventId,
+ IN UINTN CpuNumber,
+ IN UINTN NsCommBufferAddr
+ );
+
+typedef struct {
+ PI_MM_ARM_TF_CPU_DRIVER_ENTRYPOINT *ArmTfCpuDriverEpPtr;
+} ARM_TF_CPU_DRIVER_EP_DESCRIPTOR;
+
+typedef RETURN_STATUS (*REGION_PERMISSION_UPDATE_FUNC) (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ 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
+ );
+
+
+/**
+ 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
+ );
+
+
+/**
+ 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
+ );
+
+
+/**
+ 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 *
+EFIAPI
+CreateHobListFromBootInfo (
+ IN OUT PI_MM_ARM_TF_CPU_DRIVER_ENTRYPOINT *CpuDriverEntryPoint,
+ IN EFI_SECURE_PARTITION_BOOT_INFO *PayloadBootInfo
+ );
+
+
+/**
+ 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
+ );
+
+
+/**
+ Auto generated function that calls the library constructors for all of the module's dependent libraries.
+
+ This function must be called by _ModuleEntryPoint().
+ This function calls the set of library constructors for the set of library instances
+ that a module depends on. This includes library instances that a module depends on
+ directly and library instances that a module depends on indirectly through other
+ libraries. This function is auto generated by build tools and those build tools are
+ responsible for collecting the set of library instances, determine which ones have
+ constructors, and calling the library constructors in the proper order based upon
+ each of the library instances own dependencies.
+
+ @param ImageHandle The image handle of the DXE Core.
+ @param SystemTable A pointer to the EFI System Table.
+
+**/
+VOID
+EFIAPI
+ProcessLibraryConstructorList (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_MM_SYSTEM_TABLE *MmSystemTable
+ );
+
+
+/**
+ Auto generated function that calls a set of module entry points.
+
+ This function must be called by _ModuleEntryPoint().
+ This function calls the set of module entry points.
+ This function is auto generated by build tools and those build tools are responsible
+ for collecting the module entry points and calling them in a specified order.
+
+ @param HobStart Pointer to the beginning of the HOB List passed in from the PEI Phase.
+
+**/
+VOID
+EFIAPI
+ProcessModuleEntryPointList (
+ IN VOID *HobStart
+ );
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Library/FvLib.h b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Library/FvLib.h
new file mode 100644
index 00000000..038fff97
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Library/FvLib.h
@@ -0,0 +1,104 @@
+/** @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
+
+**/
+
+#ifndef _FV_LIB_H_
+#define _FV_LIB_H_
+
+#include <Uefi.h>
+#include <Pi/PiFirmwareVolume.h>
+#include <Pi/PiFirmwareFile.h>
+
+/**
+ 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
+ );
+
+/**
+ 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
+ );
+
+/**
+ 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
+ );
+
+/**
+ 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,
+ OUT VOID **SectionData,
+ OUT UINTN *SectionDataSize
+ );
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Library/StandaloneMmCoreEntryPoint.h b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Library/StandaloneMmCoreEntryPoint.h
new file mode 100644
index 00000000..0e2c663e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Library/StandaloneMmCoreEntryPoint.h
@@ -0,0 +1,95 @@
+/** @file
+ Module entry point library for STANDALONE MM core.
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __MODULE_ENTRY_POINT_H__
+#define __MODULE_ENTRY_POINT_H__
+
+///
+/// Global variable that contains a pointer to the Hob List passed into the STANDALONE MM Core entry point.
+///
+extern VOID *gHobList;
+
+
+/**
+ 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
+ );
+
+
+/**
+ 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
+ );
+
+
+/**
+ Auto generated function that calls the library constructors for all of the module's dependent libraries.
+
+ This function must be called by _ModuleEntryPoint().
+ This function calls the set of library constructors for the set of library instances
+ that a module depends on. This includes library instances that a module depends on
+ directly and library instances that a module depends on indirectly through other
+ libraries. This function is auto generated by build tools and those build tools are
+ responsible for collecting the set of library instances, determine which ones have
+ constructors, and calling the library constructors in the proper order based upon
+ each of the library instances own dependencies.
+
+ @param ImageHandle The image handle of the STANDALONE MM Core.
+ @param SystemTable A pointer to the EFI System Table.
+
+**/
+VOID
+EFIAPI
+ProcessLibraryConstructorList (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_MM_SYSTEM_TABLE *MmSystemTable
+ );
+
+
+/**
+ Autogenerated function that calls a set of module entry points.
+
+ This function must be called by _ModuleEntryPoint().
+ This function calls the set of module entry points.
+ This function is auto generated by build tools and those build tools are responsible
+ for collecting the module entry points and calling them in a specified order.
+
+ @param HobStart Pointer to the beginning of the HOB List passed in from the PEI Phase.
+
+**/
+VOID
+EFIAPI
+ProcessModuleEntryPointList (
+ IN VOID *HobStart
+ );
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Library/StandaloneMmMemLib.h b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Library/StandaloneMmMemLib.h
new file mode 100644
index 00000000..20b0c0c8
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/Library/StandaloneMmMemLib.h
@@ -0,0 +1,134 @@
+/** @file
+ Provides services for MM Memory Operation.
+
+ The MM Mem Library provides function for checking if buffer is outside MMRAM and valid.
+ It also provides functions for copy data from MMRAM to non-MMRAM, from non-MMRAM to MMRAM,
+ from non-MMRAM to non-MMRAM, or set data in non-MMRAM.
+
+ 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
+
+**/
+
+#ifndef _MM_MEM_LIB_H_
+#define _MM_MEM_LIB_H_
+
+/**
+ 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
+ );
+
+/**
+ 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
+ );
+
+/**
+ 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
+ );
+
+/**
+ 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
+ );
+
+/**
+ 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
+ );
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/StandaloneMm.h b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/StandaloneMm.h
new file mode 100644
index 00000000..ed8849d5
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Include/StandaloneMm.h
@@ -0,0 +1,29 @@
+/** @file
+ Standalone MM.
+
+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
+
+**/
+
+#ifndef _STANDALONE_MM_H_
+#define _STANDALONE_MM_H_
+
+#include <PiMm.h>
+
+typedef
+EFI_STATUS
+(EFIAPI *MM_IMAGE_ENTRY_POINT) (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_MM_SYSTEM_TABLE *MmSystemTable
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *STANDALONE_MM_FOUNDATION_ENTRY_POINT) (
+ IN VOID *HobStart
+ );
+
+#endif
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
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/StandaloneMmPkg.ci.yaml b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
new file mode 100644
index 00000000..12f4b573
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
@@ -0,0 +1,84 @@
+## @file
+# CI configuration for StandaloneMmPkg
+#
+# Copyright (c) 2020 - 2021, Arm Limited. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+{
+ ## options defined .pytool/Plugin/CompilerPlugin
+ "CompilerPlugin": {
+ "DscPath": "StandaloneMmPkg.dsc"
+ },
+
+ ## options defined .pytool/Plugin/HostUnitTestCompilerPlugin
+ "HostUnitTestCompilerPlugin": {
+ "DscPath": "" # Don't support this test
+ },
+
+ ## options defined .pytool/Plugin/CharEncodingCheck
+ "CharEncodingCheck": {
+ "IgnoreFiles": []
+ },
+
+ ## options defined .pytool/Plugin/DependencyCheck
+ "DependencyCheck": {
+ "AcceptableDependencies": [
+ "ArmPkg/ArmPkg.dec",
+ "EmbeddedPkg/EmbeddedPkg.dec",
+ "StandaloneMmPkg/StandaloneMmPkg.dec",
+ "MdeModulePkg/MdeModulePkg.dec",
+ "MdePkg/MdePkg.dec"
+ ],
+ # For host based unit tests
+ "AcceptableDependencies-HOST_APPLICATION":[
+ "UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec"
+ ],
+ # For UEFI shell based apps
+ "AcceptableDependencies-UEFI_APPLICATION":[],
+ "IgnoreInf": []
+ },
+
+ ## options defined .pytool/Plugin/DscCompleteCheck
+ "DscCompleteCheck": {
+ "IgnoreInf": [],
+ "DscPath": "StandaloneMmPkg.dsc"
+ },
+
+ ## options defined .pytool/Plugin/HostUnitTestDscCompleteCheck
+ "HostUnitTestDscCompleteCheck": {
+ "IgnoreInf": [""],
+ "DscPath": "" # Don't support this test
+ },
+
+ ## options defined .pytool/Plugin/GuidCheck
+ "GuidCheck": {
+ "IgnoreGuidName": [],
+ "IgnoreGuidValue": [],
+ "IgnoreFoldersAndFiles": [],
+ "IgnoreDuplicates": [],
+ },
+
+ ## options defined .pytool/Plugin/LibraryClassCheck
+ "LibraryClassCheck": {
+ "IgnoreHeaderFile": []
+ },
+
+ ## options defined .pytool/Plugin/SpellCheck
+ "SpellCheck": {
+ "AuditOnly": False,
+ "IgnoreFiles": [], # use gitignore syntax to ignore errors
+ # in matching files
+ "ExtendWords": [
+ "Bsymbolic",
+ "FwVol",
+ "mpidr",
+ "mstrict",
+ "schedulable",
+ "StandaloneMMCore",
+ ], # words to extend to the dictionary for this package
+ "IgnoreStandardPaths": [], # Standard Plugin defined paths that
+ # should be ignore
+ "AdditionalIncludePaths": [] # Additional paths to spell check
+ # (wildcards supported)
+ }
+}
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/StandaloneMmPkg.dec b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/StandaloneMmPkg.dec
new file mode 100644
index 00000000..e7408b5d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/StandaloneMmPkg.dec
@@ -0,0 +1,50 @@
+## @file
+# This package is a platform package that provide platform module/library
+# required by Standalone MM platform.
+#
+# Copyright (c) 2016-2021, Arm Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+
+[Defines]
+ DEC_SPECIFICATION = 0x0001001A
+ PACKAGE_NAME = StandaloneMmPkg
+ PACKAGE_GUID = 2AE82968-7769-4A85-A5BC-A0954CE54A5C
+ PACKAGE_VERSION = 1.0
+
+[Includes]
+ Include
+
+[LibraryClasses]
+
+ ## @libraryclass Defines a set of helper methods.
+ FvLib|Include/Library/FvLib.h
+
+ ## @libraryclass Defines a set of interfaces for the MM core entrypoint.
+ StandaloneMmCoreEntryPoint|Include/Library/StandaloneMmCoreEntryPoint.h
+
+ ## @libraryclass Defines a set of interfaces that provides services for
+ ## MM Memory Operation.
+ MemLib|Include/Library/StandaloneMmMemLib.h
+
+[LibraryClasses.AArch64]
+ ## @libraryclass Defines a set of interfaces for the MM core entrypoint for
+ ## AArch64.
+ StandaloneMmCoreEntryPoint|Include/Library/AArch64/StandaloneMmCoreEntryPoint.h
+
+[Guids]
+ gStandaloneMmPkgTokenSpaceGuid = { 0x18fe7632, 0xf5c8, 0x4e63, { 0x8d, 0xe8, 0x17, 0xa5, 0x5c, 0x59, 0x13, 0xbd }}
+ gMpInformationHobGuid = { 0xba33f15d, 0x4000, 0x45c1, { 0x8e, 0x88, 0xf9, 0x16, 0x92, 0xd4, 0x57, 0xe3 }}
+ gMmFvDispatchGuid = { 0xb65694cc, 0x09e3, 0x4c3b, { 0xb5, 0xcd, 0x05, 0xf4, 0x4d, 0x3c, 0xdb, 0xff }}
+
+ ## Include/Guid/MmCoreData.h
+ gMmCoreDataHobGuid = { 0xa160bf99, 0x2aa4, 0x4d7d, { 0x99, 0x93, 0x89, 0x9c, 0xb1, 0x2d, 0xf3, 0x76 }}
+
+ ## Include/Guid/MmramMemoryReserve.h
+ gEfiMmPeiMmramMemoryReserveGuid = { 0x0703f912, 0xbf8d, 0x4e2a, { 0xbe, 0x07, 0xab, 0x27, 0x25, 0x25, 0xc5, 0x92 }}
+
+ gEfiStandaloneMmNonSecureBufferGuid = { 0xf00497e3, 0xbfa2, 0x41a1, { 0x9d, 0x29, 0x54, 0xc2, 0xe9, 0x37, 0x21, 0xc5 }}
+ gEfiArmTfCpuDriverEpDescriptorGuid = { 0x6ecbd5a1, 0xc0f8, 0x4702, { 0x83, 0x01, 0x4f, 0xc2, 0xc5, 0x47, 0x0a, 0x51 }}
+
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/StandaloneMmPkg.dsc b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/StandaloneMmPkg.dsc
new file mode 100644
index 00000000..9dd838af
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/StandaloneMmPkg.dsc
@@ -0,0 +1,140 @@
+## @file
+# Standalone MM Platform.
+#
+# Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR>
+# Copyright (C) Microsoft Corporation<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ PLATFORM_NAME = StandaloneMm
+ PLATFORM_GUID = 9A4BBA60-B4F9-47C7-9258-3BD77CAE9322
+ PLATFORM_VERSION = 1.0
+ DSC_SPECIFICATION = 0x00010011
+ OUTPUT_DIRECTORY = Build/StandaloneMm
+ SUPPORTED_ARCHITECTURES = AARCH64|X64
+ BUILD_TARGETS = DEBUG|RELEASE
+ SKUID_IDENTIFIER = DEFAULT
+
+ # LzmaF86
+ DEFINE COMPRESSION_TOOL_GUID = D42AE6BD-1352-4bfb-909A-CA72A6EAE889
+
+################################################################################
+#
+# Library Class section - list of all Library Classes needed by this Platform.
+#
+################################################################################
+
+!include MdePkg/MdeLibs.dsc.inc
+
+[LibraryClasses]
+ #
+ # Basic
+ #
+ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+ CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf
+ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+ DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+ ExtractGuidedSectionLib|EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf
+ FvLib|StandaloneMmPkg/Library/FvLib/FvLib.inf
+ HobLib|StandaloneMmPkg/Library/StandaloneMmHobLib/StandaloneMmHobLib.inf
+ IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+ MemLib|StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.inf
+ MemoryAllocationLib|StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationLib.inf
+ MmServicesTableLib|MdePkg/Library/StandaloneMmServicesTableLib/StandaloneMmServicesTableLib.inf
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
+ PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
+ StandaloneMmCoreEntryPoint|StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf
+ StandaloneMmDriverEntryPoint|MdePkg/Library/StandaloneMmDriverEntryPoint/StandaloneMmDriverEntryPoint.inf
+ VariableMmDependency|StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.inf
+
+[LibraryClasses.AARCH64]
+ ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf
+ StandaloneMmMmuLib|ArmPkg/Library/StandaloneMmMmuLib/ArmMmuStandaloneMmLib.inf
+ ArmSvcLib|ArmPkg/Library/ArmSvcLib/ArmSvcLib.inf
+ CacheMaintenanceLib|ArmPkg/Library/ArmCacheMaintenanceLib/ArmCacheMaintenanceLib.inf
+ PeCoffExtraActionLib|StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.inf
+
+ NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
+ NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
+
+[LibraryClasses.common.MM_CORE_STANDALONE]
+ HobLib|StandaloneMmPkg/Library/StandaloneMmCoreHobLib/StandaloneMmCoreHobLib.inf
+
+[LibraryClasses.common.MM_STANDALONE]
+ MemoryAllocationLib|StandaloneMmPkg/Library/StandaloneMmMemoryAllocationLib/StandaloneMmMemoryAllocationLib.inf
+
+################################################################################
+#
+# Pcd Section - list of all EDK II PCD Entries defined by this Platform
+#
+################################################################################
+[PcdsFixedAtBuild]
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x800000CF
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xff
+ gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x0f
+
+###################################################################################################
+#
+# Components Section - list of the modules and components that will be processed by compilation
+# tools and the EDK II tools to generate PE32/PE32+/Coff image files.
+#
+# Note: The EDK II DSC file is not used to specify how compiled binary images get placed
+# into firmware volume images. This section is just a list of modules to compile from
+# source into UEFI-compliant binaries.
+# It is the FDF file that contains information on combining binary files into firmware
+# volume images, whose concept is beyond UEFI and is described in PI specification.
+# Binary modules do not need to be listed in this section, as they should be
+# specified in the FDF file. For example: Shell binary (Shell_Full.efi), FAT binary (Fat.efi),
+# Logo (Logo.bmp), and etc.
+# There may also be modules listed in this section that are not required in the FDF file,
+# When a module listed here is excluded from FDF file, then UEFI-compliant binary will be
+# generated for it, but the binary will not be put into any firmware volume.
+#
+###################################################################################################
+[Components.common]
+ #
+ # MM Core
+ #
+ StandaloneMmPkg/Core/StandaloneMmCore.inf
+ StandaloneMmPkg/Library/FvLib/FvLib.inf
+ StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf
+ StandaloneMmPkg/Library/StandaloneMmCoreHobLib/StandaloneMmCoreHobLib.inf
+ StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationLib.inf
+ StandaloneMmPkg/Library/StandaloneMmHobLib/StandaloneMmHobLib.inf
+ StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.inf
+ StandaloneMmPkg/Library/StandaloneMmMemoryAllocationLib/StandaloneMmMemoryAllocationLib.inf
+ StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.inf
+
+[Components.AARCH64]
+ StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/StandaloneMmCpu.inf
+ StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.inf
+
+###################################################################################################
+#
+# BuildOptions Section - Define the module specific tool chain flags that should be used as
+# the default flags for a module. These flags are appended to any
+# standard flags that are defined by the build process. They can be
+# applied for any modules or only those modules with the specific
+# module style (EDK or EDKII) specified in [Components] section.
+#
+###################################################################################################
+[BuildOptions.AARCH64]
+GCC:*_*_*_DLINK_FLAGS = -z common-page-size=0x1000 -march=armv8-a+nofp -mstrict-align
+GCC:*_*_*_CC_FLAGS = -mstrict-align
+
+[BuildOptions.X64]
+ MSFT:*_*_*_DLINK_FLAGS = /ALIGN:4096
+ GCC:*_GCC*_*_DLINK_FLAGS = -z common-page-size=0x1000