diff --git a/StandaloneMmPkg/Core/Dependency.c b/StandaloneMmPkg/Core/Dependency.c
new file mode 100644
index 0000000000..365007d8ae
--- /dev/null
+++ b/StandaloneMmPkg/Core/Dependency.c
@@ -0,0 +1,389 @@
+/** @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
+  schedulability is that the dependency expression is satisfied.
+
+  Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+  Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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 expressiion.
+    //
+    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 it's intermediate value
+    // may be strange.
+    //
+    Iterator++;
+  }
+
+Done:
+  return FALSE;
+}
diff --git a/StandaloneMmPkg/Core/Dispatcher.c b/StandaloneMmPkg/Core/Dispatcher.c
new file mode 100644
index 0000000000..8d009b4f80
--- /dev/null
+++ b/StandaloneMmPkg/Core/Dispatcher.c
@@ -0,0 +1,1071 @@
+/** @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 mFvHandleList 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 and recursively adds
+            all Befores. It then addes the item that was passed in and then
+            processess the After dependecies 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.
+  Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StandaloneMmCore.h"
+
+//
+// MM Dispatcher Data structures
+//
+#define KNOWN_HANDLE_SIGNATURE  SIGNATURE_32('k','n','o','w')
+
+typedef struct {
+  UINTN           Signature;
+  LIST_ENTRY      Link;         // mFvHandleList
+  EFI_HANDLE      Handle;
+} KNOWN_HANDLE;
+
+//
+// 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 Befores 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 handles who's Fv's have been parsed and added to the mFwDriverList.
+//
+LIST_ENTRY  mFvHandleList = INITIALIZE_LIST_HEAD_VARIABLE (mFvHandleList);
+
+//
+// Flag for the MM Dispacher.  TRUE if dispatcher is execuing.
+//
+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 correponding 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 avalaible 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
+  )
+{
+  VOID                           *Buffer;
+  UINTN                          PageCount;
+  EFI_STATUS                     Status;
+  EFI_PHYSICAL_ADDRESS           DstBuffer;
+  PE_COFF_LOADER_IMAGE_CONTEXT   ImageContext;
+
+  DEBUG ((DEBUG_INFO, "MmLoadImage - %g\n", &DriverEntry->FileName));
+
+  Buffer = AllocateCopyPool (DriverEntry->Pe32DataSize, DriverEntry->Pe32Data);
+  if (Buffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status               = EFI_SUCCESS;
+
+  //
+  // Initialize ImageContext
+  //
+  ImageContext.Handle = Buffer;
+  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+
+  //
+  // Get information about the image being loaded
+  //
+  Status = PeCoffLoaderGetImageInfo (&ImageContext);
+  if (EFI_ERROR (Status)) {
+    if (Buffer != NULL) {
+      MmFreePool (Buffer);
+    }
+    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)) {
+    if (Buffer != NULL) {
+      MmFreePool (Buffer);
+    }
+    return Status;
+  }
+
+  ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;
+
+  //
+  // Align buffer on section boundry
+  //
+  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)) {
+    if (Buffer != NULL) {
+      MmFreePool (Buffer);
+    }
+    MmFreePages (DstBuffer, PageCount);
+    return Status;
+  }
+
+  //
+  // Relocate the image in our new buffer
+  //
+  Status = PeCoffLoaderRelocateImage (&ImageContext);
+  if (EFI_ERROR (Status)) {
+    if (Buffer != NULL) {
+      MmFreePool (Buffer);
+    }
+    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)) {
+      if (Buffer != NULL) {
+        MmFreePool (Buffer);
+      }
+      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 redudant 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 ();
+
+  //
+  // Free buffer allocated by Fv->ReadSection.
+  //
+  // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection
+  // used the UEFI Boot Services AllocatePool() function
+  //
+  MmFreePool (Buffer);
+  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;
+  BOOLEAN               PreviousMmEntryPointRegistered;
+
+  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
+      // Untrused 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);
+
+      //
+      // Cache state of MmEntryPointRegistered before calling entry point
+      //
+      PreviousMmEntryPointRegistered = gMmCorePrivate->MmEntryPointRegistered;
+
+      //
+      // 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);
+      }
+
+      if (!PreviousMmEntryPointRegistered && gMmCorePrivate->MmEntryPointRegistered) {
+        //
+        // Return immediately if the MM Entry Point was registered by the MM
+        // Driver that was just dispatched.  The MM IPL will reinvoke the MM
+        // Core Dispatcher.  This is required so MM Mode may be enabled as soon
+        // as all the dependent MM Drivers for MM Mode have been dispatched.
+        // Once the MM Entry Point has been registered, then MM Mode will be
+        // used.
+        //
+        gRequestDispatch = TRUE;
+        gDispatcherRunning = FALSE;
+        return EFI_NOT_READY;
+      }
+    }
+
+    //
+    // 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 Befores 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 Fv has been processed, FALSE if not.
+
+  @param  FvHandle              The handle of a FV that's being tested
+
+  @retval TRUE                  Fv protocol on FvHandle has been processed
+  @retval FALSE                 Fv protocol on FvHandle has not yet been
+                                processed
+
+**/
+BOOLEAN
+FvHasBeenProcessed (
+  IN EFI_HANDLE  FvHandle
+  )
+{
+  LIST_ENTRY    *Link;
+  KNOWN_HANDLE  *KnownHandle;
+
+  for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {
+    KnownHandle = CR (Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);
+    if (KnownHandle->Handle == FvHandle) {
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+/**
+  Remember that Fv protocol on FvHandle has had it's drivers placed on the
+  mDiscoveredList. This fucntion adds entries on the mFvHandleList. Items are
+  never removed/freed from the mFvHandleList.
+
+  @param  FvHandle              The handle of a FV that has been processed
+
+**/
+VOID
+FvIsBeingProcesssed (
+  IN EFI_HANDLE  FvHandle
+  )
+{
+  KNOWN_HANDLE  *KnownHandle;
+
+  DEBUG ((DEBUG_INFO, "FvIsBeingProcesssed - 0x%08x\n", FvHandle));
+
+  KnownHandle = AllocatePool (sizeof (KNOWN_HANDLE));
+  ASSERT (KnownHandle != NULL);
+
+  KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;
+  KnownHandle->Handle = FvHandle;
+  InsertTailList (&mFvHandleList, &KnownHandle->Link);
+}
+
+/**
+  Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
+  and initilize 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 free'ed and contains booleans that represent the
+  other possible MM driver states.
+
+  @param  Fv                    Fv protocol, needed to read Depex info out of
+                                FLASH.
+  @param  FvHandle              Handle for Fv, needed in the
+                                EFI_MM_DRIVER_ENTRY so that the PE image can be
+                                read out of the FV at a later time.
+  @param  DriverName            Name of driver to add to mDiscoveredList.
+
+  @retval EFI_SUCCESS           If driver was added to the mDiscoveredList.
+  @retval EFI_ALREADY_STARTED   The driver has already been started. Only one
+                                DriverName may be active in the system at any one
+                                time.
+
+**/
+EFI_STATUS
+MmAddToDriverList (
+  IN EFI_HANDLE   FvHandle,
+  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->FvHandle         = FvHandle;
+  DriverEntry->Pe32Data         = Pe32Data;
+  DriverEntry->Pe32DataSize     = Pe32DataSize;
+  DriverEntry->Depex            = Depex;
+  DriverEntry->DepexSize        = DepexSize;
+
+  MmGetDepexSectionAndPreProccess (DriverEntry);
+
+  InsertTailList (&mDiscoveredList, &DriverEntry->Link);
+  gRequestDispatch = TRUE;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function is the main entry point for an MM handler dispatch
+  or communicate-based callback.
+
+  Event notification that is fired every time a FV dispatch protocol is added.
+  More than one protocol may have been added when this event is fired, so you
+  must loop on MmLocateHandle () to see how many protocols were added and
+  do the following to each FV:
+  If the Fv has already been processed, skip it. If the Fv has not been
+  processed then mark it as being processed, as we are about to process it.
+  Read the Fv and add any driver in the Fv to the mDiscoveredList.The
+  mDiscoveredList is never free'ed and contains variables that define
+  the other states the MM driver transitions to..
+  While you are at it read the A Priori file into memory.
+  Place drivers in the A Priori list onto the mScheduledQueue.
+
+  @param  DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
+  @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
+  )
+{
+  EFI_STATUS                            Status;
+
+  DEBUG ((DEBUG_INFO, "MmDriverDispatchHandler\n"));
+
+  //
+  // Execute the MM Dispatcher on any newly discovered FVs and previously
+  // discovered MM drivers that have been discovered but not dispatched.
+  //
+  Status = MmDispatcher ();
+
+  //
+  // Check to see if CommBuffer and CommBufferSize are valid
+  //
+  if (CommBuffer != NULL && CommBufferSize != NULL) {
+    if (*CommBufferSize > 0) {
+      if (Status == EFI_NOT_READY) {
+        //
+        // If a the MM Core Entry Point was just registered, then set flag to
+        // request the MM Dispatcher to be restarted.
+        //
+        *(UINT8 *)CommBuffer = COMM_BUFFER_MM_DISPATCH_RESTART;
+      } else if (!EFI_ERROR (Status)) {
+        //
+        // Set the flag to show that the MM Dispatcher executed without errors
+        //
+        *(UINT8 *)CommBuffer = COMM_BUFFER_MM_DISPATCH_SUCCESS;
+      } else {
+        //
+        // Set the flag to show that the MM Dispatcher encountered an error
+        //
+        *(UINT8 *)CommBuffer = COMM_BUFFER_MM_DISPATCH_ERROR;
+      }
+    }
+  }
+
+  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 SmiHandlerRegister().
+  @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
+MmFvDispatchHandler (
+  IN     EFI_HANDLE               DispatchHandle,
+  IN     CONST VOID               *Context,        OPTIONAL
+  IN OUT VOID                     *CommBuffer,     OPTIONAL
+  IN OUT UINTN                    *CommBufferSize  OPTIONAL
+  )
+{
+  EFI_STATUS                            Status;
+  EFI_MM_COMMUNICATE_FV_DISPATCH_DATA  *CommunicationFvDispatchData;
+  EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
+
+  DEBUG ((DEBUG_INFO, "MmFvDispatchHandler\n"));
+
+  CommunicationFvDispatchData = CommBuffer;
+
+  DEBUG ((DEBUG_INFO, "  Dispatch - 0x%016lx - 0x%016lx\n", CommunicationFvDispatchData->Address,
+          CommunicationFvDispatchData->Size));
+
+  FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)CommunicationFvDispatchData->Address;
+
+  MmCoreFfsFindMmDriver (FwVolHeader);
+
+  //
+  // Execute the MM Dispatcher on any newly discovered FVs and previously
+  // discovered MM drivers that have been discovered but not dispatched.
+  //
+  Status = MmDispatcher ();
+
+  return Status;
+}
+
+/**
+  Traverse the discovered list for any drivers that were discovered but not loaded
+  because the dependency experessions 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/StandaloneMmPkg/Core/FwVol.c b/StandaloneMmPkg/Core/FwVol.c
new file mode 100644
index 0000000000..5abf98c247
--- /dev/null
+++ b/StandaloneMmPkg/Core/FwVol.c
@@ -0,0 +1,104 @@
+/**@file
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.
+Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StandaloneMmCore.h"
+#include 
+
+//
+// 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_HANDLE   FvHandle,
+  IN VOID         *Pe32Data,
+  IN UINTN        Pe32DataSize,
+  IN VOID         *Depex,
+  IN UINTN        DepexSize,
+  IN EFI_GUID     *DriverName
+  );
+
+BOOLEAN
+FvHasBeenProcessed (
+  IN EFI_HANDLE  FvHandle
+  );
+
+VOID
+FvIsBeingProcesssed (
+  IN EFI_HANDLE  FvHandle
+  );
+
+EFI_STATUS
+MmCoreFfsFindMmDriver (
+  IN  EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader
+  )
+/*++
+
+Routine Description:
+  Given the pointer to the Firmware Volume Header find the
+  MM driver and return it's PE32 image.
+
+Arguments:
+  FwVolHeader - Pointer to memory mapped FV
+
+Returns:
+  other       - Failure
+
+--*/
+{
+  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;
+
+  DEBUG ((DEBUG_INFO, "MmCoreFfsFindMmDriver - 0x%x\n", FwVolHeader));
+
+  if (FvHasBeenProcessed (FwVolHeader)) {
+    return EFI_SUCCESS;
+  }
+
+  FvIsBeingProcesssed (FwVolHeader);
+
+  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 Status;
+}
diff --git a/StandaloneMmPkg/Core/Handle.c b/StandaloneMmPkg/Core/Handle.c
new file mode 100644
index 0000000000..70d59fe15d
--- /dev/null
+++ b/StandaloneMmPkg/Core/Handle.c
@@ -0,0 +1,533 @@
+/** @file
+  SMM handle & protocol handling.
+
+  Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+  Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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/StandaloneMmPkg/Core/InstallConfigurationTable.c b/StandaloneMmPkg/Core/InstallConfigurationTable.c
new file mode 100644
index 0000000000..2392be9958
--- /dev/null
+++ b/StandaloneMmPkg/Core/InstallConfigurationTable.c
@@ -0,0 +1,178 @@
+/** @file
+  System Management System Table Services MmInstallConfigurationTable service
+
+  Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.
+  Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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/StandaloneMmPkg/Core/Locate.c b/StandaloneMmPkg/Core/Locate.c
new file mode 100644
index 0000000000..9129718723
--- /dev/null
+++ b/StandaloneMmPkg/Core/Locate.c
@@ -0,0 +1,496 @@
+/** @file
+  Locate handle functions
+
+  Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.
+  Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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 pasased in return a Protocol Instance that was just add
+  to the system. If Retistration 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/StandaloneMmPkg/Core/Mmi.c b/StandaloneMmPkg/Core/Mmi.c
new file mode 100644
index 0000000000..7193ebcd15
--- /dev/null
+++ b/StandaloneMmPkg/Core/Mmi.c
@@ -0,0 +1,337 @@
+/** @file
+  MMI management.
+
+  Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.
+  Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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 funtion 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/StandaloneMmPkg/Core/Notify.c b/StandaloneMmPkg/Core/Notify.c
new file mode 100644
index 0000000000..57a03fed5b
--- /dev/null
+++ b/StandaloneMmPkg/Core/Notify.c
@@ -0,0 +1,203 @@
+/** @file
+  Support functions for UEFI protocol notification infrastructure.
+
+  Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+  Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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/StandaloneMmPkg/Core/Page.c b/StandaloneMmPkg/Core/Page.c
new file mode 100644
index 0000000000..8250f8c729
--- /dev/null
+++ b/StandaloneMmPkg/Core/Page.c
@@ -0,0 +1,384 @@
+/** @file
+  MM Memory page management functions.
+
+  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+  Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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/StandaloneMmPkg/Core/Pool.c b/StandaloneMmPkg/Core/Pool.c
new file mode 100644
index 0000000000..ce6cfcb9a4
--- /dev/null
+++ b/StandaloneMmPkg/Core/Pool.c
@@ -0,0 +1,293 @@
+/** @file
+  SMM Memory pool management functions.
+
+  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+  Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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/StandaloneMmPkg/Core/StandaloneMmCore.c b/StandaloneMmPkg/Core/StandaloneMmCore.c
new file mode 100644
index 0000000000..74432320bf
--- /dev/null
+++ b/StandaloneMmPkg/Core/StandaloneMmCore.c
@@ -0,0 +1,712 @@
+/** @file
+  MM Core Main Entry Point
+
+  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+  Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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
+};
+
+//
+// Flag to determine if the platform has performed a legacy boot.
+// If this flag is TRUE, then the runtime code and runtime data associated with the
+// MM IPL are converted to free memory, so the MM Core must guarantee that is
+// does not touch of the code/data associated with the MM IPL if this flag is TRUE.
+//
+BOOLEAN  mInLegacyBoot = FALSE;
+
+//
+// Table of MMI Handlers that are registered by the MM Core when it is initialized
+//
+MM_CORE_MMI_HANDLERS  mMmCoreMmiHandlers[] = {
+  { MmFvDispatchHandler,     &gMmFvDispatchGuid,                 NULL, TRUE  },
+  { MmDriverDispatchHandler, &gEfiEventDxeDispatchGuid,          NULL, TRUE  },
+  { MmReadyToLockHandler,    &gEfiDxeMmReadyToLockProtocolGuid,  NULL, TRUE  },
+  { MmEndOfDxeHandler,       &gEfiEndOfDxeEventGroupGuid,        NULL, FALSE },
+  { MmLegacyBootHandler,     &gEfiEventLegacyBootGuid,           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 Legacy Boot event is signaled.  The MM
+  Core uses this signal to know that a Legacy Boot has been performed and that
+  gMmCorePrivate that is shared between the UEFI and MM execution environments can
+  not be accessed from MM anymore since that structure is considered free memory by
+  a legacy OS.
+
+  @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
+MmLegacyBootHandler (
+  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 = EFI_SUCCESS;
+
+  if (!mInLegacyBoot) {
+    MmHandle = NULL;
+    Status = MmInstallProtocolInterface (
+               &MmHandle,
+               &gEfiEventLegacyBootGuid,
+               EFI_NATIVE_INTERFACE,
+               NULL
+               );
+  }
+  mInLegacyBoot = 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
+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 = EFI_SUCCESS;
+  STATIC BOOLEAN mInExitBootServices = FALSE;
+
+  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 = EFI_SUCCESS;
+  STATIC BOOLEAN mInReadyToBoot = FALSE;
+
+  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;
+  BOOLEAN                     InLegacyBoot;
+
+  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 occured, then make sure gMmCorePrivate is not accessed
+  //
+  InLegacyBoot = mInLegacyBoot;
+  if (!InLegacyBoot) {
+    //
+    // 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 ?
+  //
+
+  //
+  // If a legacy boot has occured, then make sure gMmCorePrivate is not accessed
+  //
+  if (!InLegacyBoot) {
+    //
+    // Clear the InMm flag as we are going to leave MM
+    //
+    gMmCorePrivate->InMm = FALSE;
+  }
+
+  DEBUG ((DEBUG_INFO, "MmEntryPoint Done\n"));
+}
+
+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;
+}
+
+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  ImageHandle    The firmware allocated handle for the EFI image.
+  @param  SystemTable    A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS    The entry point is executed successfully.
+  @retval Other          Some error occurred when executing this entry point.
+
+**/
+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;
+  UINT32                          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 = 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 = 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 = 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 constructor of StandaloneMmCoreMemoryAllocationLib(),
+  // so that the library linked with StandaloneMmCore can use AllocatePool() in constuctor.
+  //
+
+  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/StandaloneMmPkg/Core/StandaloneMmCore.h b/StandaloneMmPkg/Core/StandaloneMmCore.h
new file mode 100644
index 0000000000..0d20bcaa6b
--- /dev/null
+++ b/StandaloneMmPkg/Core/StandaloneMmCore.h
@@ -0,0 +1,903 @@
+/** @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.
+  Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _MM_CORE_H_
+#define _MM_CORE_H_
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#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_HANDLE                      FvHandle;
+  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;
+  /// Registerd 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 pasased in return a Protocol Instance that was just add
+  to the system. If Retistration 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 funtion 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
+MmFvDispatchHandler (
+  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
+MmLegacyBootHandler (
+  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 buils
+//
+
+/**
+  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/StandaloneMmPkg/Core/StandaloneMmCore.inf b/StandaloneMmPkg/Core/StandaloneMmCore.inf
new file mode 100644
index 0000000000..ff2b8b9cef
--- /dev/null
+++ b/StandaloneMmPkg/Core/StandaloneMmCore.inf
@@ -0,0 +1,80 @@
+## @file
+# This module provide an SMM CIS compliant implementation of SMM Core.
+#
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+# Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[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
+  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
+  gMmCoreDataHobGuid
+  gMmFvDispatchGuid
+  gEfiEventLegacyBootGuid
+  gEfiEventExitBootServicesGuid
+  gEfiEventReadyToBootGuid
diff --git a/StandaloneMmPkg/Core/StandaloneMmCorePrivateData.h b/StandaloneMmPkg/Core/StandaloneMmCorePrivateData.h
new file mode 100644
index 0000000000..d9598937cf
--- /dev/null
+++ b/StandaloneMmPkg/Core/StandaloneMmCorePrivateData.h
@@ -0,0 +1,66 @@
+/** @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.
+  Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _STANDALONE_MM_CORE_PRIVATE_DATA_H_
+#define _STANDALONE_MM_CORE_PRIVATE_DATA_H_
+
+#include 
+
+//
+// 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/StandaloneMmPkg/Include/Guid/MmFvDispatch.h b/StandaloneMmPkg/Include/Guid/MmFvDispatch.h
new file mode 100644
index 0000000000..d141d40d8d
--- /dev/null
+++ b/StandaloneMmPkg/Include/Guid/MmFvDispatch.h
@@ -0,0 +1,39 @@
+/** @file
+  GUIDs for MM Event.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.
+Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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/StandaloneMmPkg/Include/Library/StandaloneMmCoreEntryPoint.h b/StandaloneMmPkg/Include/Library/StandaloneMmCoreEntryPoint.h
new file mode 100644
index 0000000000..f53094bfc3
--- /dev/null
+++ b/StandaloneMmPkg/Include/Library/StandaloneMmCoreEntryPoint.h
@@ -0,0 +1,101 @@
+/** @file
+  Module entry point library for STANDALONE MM core.
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
+Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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/StandaloneMmPkg/Include/StandaloneMm.h b/StandaloneMmPkg/Include/StandaloneMm.h
new file mode 100644
index 0000000000..2517d41e74
--- /dev/null
+++ b/StandaloneMmPkg/Include/StandaloneMm.h
@@ -0,0 +1,36 @@
+/** @file
+  Standalone MM.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.
+Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution.  The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _STANDALONE_MM_H_
+#define _STANDALONE_MM_H_
+
+#include 
+
+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