]> git.proxmox.com Git - mirror_edk2.git/blobdiff - StandaloneMmPkg/Core/StandaloneMmCore.c
StandaloneMmPkg/Core: Implementation of Standalone MM Core Module.
[mirror_edk2.git] / StandaloneMmPkg / Core / StandaloneMmCore.c
diff --git a/StandaloneMmPkg/Core/StandaloneMmCore.c b/StandaloneMmPkg/Core/StandaloneMmCore.c
new file mode 100644 (file)
index 0000000..7443232
--- /dev/null
@@ -0,0 +1,712 @@
+/** @file\r
+  MM Core Main Entry Point\r
+\r
+  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "StandaloneMmCore.h"\r
+\r
+EFI_STATUS\r
+MmCoreFfsFindMmDriver (\r
+  IN  EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader\r
+  );\r
+\r
+EFI_STATUS\r
+MmDispatcher (\r
+  VOID\r
+  );\r
+\r
+//\r
+// Globals used to initialize the protocol\r
+//\r
+EFI_HANDLE            mMmCpuHandle = NULL;\r
+\r
+//\r
+// Physical pointer to private structure shared between MM IPL and the MM Core\r
+//\r
+MM_CORE_PRIVATE_DATA  *gMmCorePrivate;\r
+\r
+//\r
+// MM Core global variable for MM System Table.  Only accessed as a physical structure in MMRAM.\r
+//\r
+EFI_MM_SYSTEM_TABLE  gMmCoreMmst = {\r
+\r
+  // The table header for the MMST.\r
+  {\r
+    MM_MMST_SIGNATURE,\r
+    EFI_MM_SYSTEM_TABLE_REVISION,\r
+    sizeof (gMmCoreMmst.Hdr)\r
+  },\r
+  // MmFirmwareVendor\r
+  NULL,\r
+  // MmFirmwareRevision\r
+  0,\r
+  // MmInstallConfigurationTable\r
+  MmInstallConfigurationTable,\r
+  // I/O Service\r
+  {\r
+    {\r
+      (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5,       // MmMemRead\r
+      (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5        // MmMemWrite\r
+    },\r
+    {\r
+      (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5,       // MmIoRead\r
+      (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5        // MmIoWrite\r
+    }\r
+  },\r
+  // Runtime memory services\r
+  MmAllocatePool,\r
+  MmFreePool,\r
+  MmAllocatePages,\r
+  MmFreePages,\r
+  // MP service\r
+  NULL,                          // MmStartupThisAp\r
+  0,                             // CurrentlyExecutingCpu\r
+  0,                             // NumberOfCpus\r
+  NULL,                          // CpuSaveStateSize\r
+  NULL,                          // CpuSaveState\r
+  0,                             // NumberOfTableEntries\r
+  NULL,                          // MmConfigurationTable\r
+  MmInstallProtocolInterface,\r
+  MmUninstallProtocolInterface,\r
+  MmHandleProtocol,\r
+  MmRegisterProtocolNotify,\r
+  MmLocateHandle,\r
+  MmLocateProtocol,\r
+  MmiManage,\r
+  MmiHandlerRegister,\r
+  MmiHandlerUnRegister\r
+};\r
+\r
+//\r
+// Flag to determine if the platform has performed a legacy boot.\r
+// If this flag is TRUE, then the runtime code and runtime data associated with the\r
+// MM IPL are converted to free memory, so the MM Core must guarantee that is\r
+// does not touch of the code/data associated with the MM IPL if this flag is TRUE.\r
+//\r
+BOOLEAN  mInLegacyBoot = FALSE;\r
+\r
+//\r
+// Table of MMI Handlers that are registered by the MM Core when it is initialized\r
+//\r
+MM_CORE_MMI_HANDLERS  mMmCoreMmiHandlers[] = {\r
+  { MmFvDispatchHandler,     &gMmFvDispatchGuid,                 NULL, TRUE  },\r
+  { MmDriverDispatchHandler, &gEfiEventDxeDispatchGuid,          NULL, TRUE  },\r
+  { MmReadyToLockHandler,    &gEfiDxeMmReadyToLockProtocolGuid,  NULL, TRUE  },\r
+  { MmEndOfDxeHandler,       &gEfiEndOfDxeEventGroupGuid,        NULL, FALSE },\r
+  { MmLegacyBootHandler,     &gEfiEventLegacyBootGuid,           NULL, FALSE },\r
+  { MmExitBootServiceHandler,&gEfiEventExitBootServicesGuid,     NULL, FALSE },\r
+  { MmReadyToBootHandler,    &gEfiEventReadyToBootGuid,          NULL, FALSE },\r
+  { NULL,                    NULL,                               NULL, FALSE },\r
+};\r
+\r
+EFI_SYSTEM_TABLE                *mEfiSystemTable;\r
+UINTN                           mMmramRangeCount;\r
+EFI_MMRAM_DESCRIPTOR            *mMmramRanges;\r
+\r
+/**\r
+  Place holder function until all the MM System Table Service are available.\r
+\r
+  Note: This function is only used by MMRAM invocation.  It is never used by DXE invocation.\r
+\r
+  @param  Arg1                   Undefined\r
+  @param  Arg2                   Undefined\r
+  @param  Arg3                   Undefined\r
+  @param  Arg4                   Undefined\r
+  @param  Arg5                   Undefined\r
+\r
+  @return EFI_NOT_AVAILABLE_YET\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MmEfiNotAvailableYetArg5 (\r
+  UINTN Arg1,\r
+  UINTN Arg2,\r
+  UINTN Arg3,\r
+  UINTN Arg4,\r
+  UINTN Arg5\r
+  )\r
+{\r
+  //\r
+  // This function should never be executed.  If it does, then the architectural protocols\r
+  // have not been designed correctly.\r
+  //\r
+  return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+  Software MMI handler that is called when a Legacy Boot event is signaled.  The MM\r
+  Core uses this signal to know that a Legacy Boot has been performed and that\r
+  gMmCorePrivate that is shared between the UEFI and MM execution environments can\r
+  not be accessed from MM anymore since that structure is considered free memory by\r
+  a legacy OS.\r
+\r
+  @param  DispatchHandle  The unique handle assigned to this handler by MmiHandlerRegister().\r
+  @param  Context         Points to an optional handler context which was specified when the handler was registered.\r
+  @param  CommBuffer      A pointer to a collection of data in memory that will\r
+                          be conveyed from a non-MM environment into an MM environment.\r
+  @param  CommBufferSize  The size of the CommBuffer.\r
+\r
+  @return Status Code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MmLegacyBootHandler (\r
+  IN     EFI_HANDLE  DispatchHandle,\r
+  IN     CONST VOID  *Context,        OPTIONAL\r
+  IN OUT VOID        *CommBuffer,     OPTIONAL\r
+  IN OUT UINTN       *CommBufferSize  OPTIONAL\r
+  )\r
+{\r
+  EFI_HANDLE  MmHandle;\r
+  EFI_STATUS  Status = EFI_SUCCESS;\r
+\r
+  if (!mInLegacyBoot) {\r
+    MmHandle = NULL;\r
+    Status = MmInstallProtocolInterface (\r
+               &MmHandle,\r
+               &gEfiEventLegacyBootGuid,\r
+               EFI_NATIVE_INTERFACE,\r
+               NULL\r
+               );\r
+  }\r
+  mInLegacyBoot = TRUE;\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Software MMI handler that is called when a ExitBoot Service event is signaled.\r
+\r
+  @param  DispatchHandle  The unique handle assigned to this handler by MmiHandlerRegister().\r
+  @param  Context         Points to an optional handler context which was specified when the handler was registered.\r
+  @param  CommBuffer      A pointer to a collection of data in memory that will\r
+                          be conveyed from a non-MM environment into an MM environment.\r
+  @param  CommBufferSize  The size of the CommBuffer.\r
+\r
+  @return Status Code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MmExitBootServiceHandler (\r
+  IN     EFI_HANDLE  DispatchHandle,\r
+  IN     CONST VOID  *Context,        OPTIONAL\r
+  IN OUT VOID        *CommBuffer,     OPTIONAL\r
+  IN OUT UINTN       *CommBufferSize  OPTIONAL\r
+  )\r
+{\r
+  EFI_HANDLE  MmHandle;\r
+  EFI_STATUS  Status = EFI_SUCCESS;\r
+  STATIC BOOLEAN mInExitBootServices = FALSE;\r
+\r
+  if (!mInExitBootServices) {\r
+    MmHandle = NULL;\r
+    Status = MmInstallProtocolInterface (\r
+               &MmHandle,\r
+               &gEfiEventExitBootServicesGuid,\r
+               EFI_NATIVE_INTERFACE,\r
+               NULL\r
+               );\r
+  }\r
+  mInExitBootServices = TRUE;\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Software MMI handler that is called when a ExitBoot Service event is signaled.\r
+\r
+  @param  DispatchHandle  The unique handle assigned to this handler by MmiHandlerRegister().\r
+  @param  Context         Points to an optional handler context which was specified when the handler was registered.\r
+  @param  CommBuffer      A pointer to a collection of data in memory that will\r
+                          be conveyed from a non-MM environment into an MM environment.\r
+  @param  CommBufferSize  The size of the CommBuffer.\r
+\r
+  @return Status Code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MmReadyToBootHandler (\r
+  IN     EFI_HANDLE  DispatchHandle,\r
+  IN     CONST VOID  *Context,        OPTIONAL\r
+  IN OUT VOID        *CommBuffer,     OPTIONAL\r
+  IN OUT UINTN       *CommBufferSize  OPTIONAL\r
+  )\r
+{\r
+  EFI_HANDLE  MmHandle;\r
+  EFI_STATUS  Status = EFI_SUCCESS;\r
+  STATIC BOOLEAN mInReadyToBoot = FALSE;\r
+\r
+  if (!mInReadyToBoot) {\r
+    MmHandle = NULL;\r
+    Status = MmInstallProtocolInterface (\r
+               &MmHandle,\r
+               &gEfiEventReadyToBootGuid,\r
+               EFI_NATIVE_INTERFACE,\r
+               NULL\r
+               );\r
+  }\r
+  mInReadyToBoot = TRUE;\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Software MMI handler that is called when the DxeMmReadyToLock protocol is added\r
+  or if gEfiEventReadyToBootGuid is signaled.  This function unregisters the\r
+  Software SMIs that are nor required after MMRAM is locked and installs the\r
+  MM Ready To Lock Protocol so MM Drivers are informed that MMRAM is about\r
+  to be locked.\r
+\r
+  @param  DispatchHandle  The unique handle assigned to this handler by MmiHandlerRegister().\r
+  @param  Context         Points to an optional handler context which was specified when the handler was registered.\r
+  @param  CommBuffer      A pointer to a collection of data in memory that will\r
+                          be conveyed from a non-MM environment into an MM environment.\r
+  @param  CommBufferSize  The size of the CommBuffer.\r
+\r
+  @return Status Code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MmReadyToLockHandler (\r
+  IN     EFI_HANDLE  DispatchHandle,\r
+  IN     CONST VOID  *Context,        OPTIONAL\r
+  IN OUT VOID        *CommBuffer,     OPTIONAL\r
+  IN OUT UINTN       *CommBufferSize  OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       Index;\r
+  EFI_HANDLE  MmHandle;\r
+\r
+  DEBUG ((DEBUG_INFO, "MmReadyToLockHandler\n"));\r
+\r
+  //\r
+  // Unregister MMI Handlers that are no longer required after the MM driver dispatch is stopped\r
+  //\r
+  for (Index = 0; mMmCoreMmiHandlers[Index].HandlerType != NULL; Index++) {\r
+    if (mMmCoreMmiHandlers[Index].UnRegister) {\r
+      MmiHandlerUnRegister (mMmCoreMmiHandlers[Index].DispatchHandle);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Install MM Ready to lock protocol\r
+  //\r
+  MmHandle = NULL;\r
+  Status = MmInstallProtocolInterface (\r
+             &MmHandle,\r
+             &gEfiMmReadyToLockProtocolGuid,\r
+             EFI_NATIVE_INTERFACE,\r
+             NULL\r
+             );\r
+\r
+  //\r
+  // Make sure MM CPU I/O 2 Protocol has been installed into the handle database\r
+  //\r
+  //Status = MmLocateProtocol (&EFI_MM_CPU_IO_PROTOCOL_GUID, NULL, &Interface);\r
+\r
+  //\r
+  // Print a message on a debug build if the MM CPU I/O 2 Protocol is not installed\r
+  //\r
+  //if (EFI_ERROR (Status)) {\r
+      //DEBUG ((DEBUG_ERROR, "\nSMM: SmmCpuIo Arch Protocol not present!!\n"));\r
+  //}\r
+\r
+\r
+  //\r
+  // Assert if the CPU I/O 2 Protocol is not installed\r
+  //\r
+  //ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Display any drivers that were not dispatched because dependency expression\r
+  // evaluated to false if this is a debug build\r
+  //\r
+  //MmDisplayDiscoveredNotDispatched ();\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Software MMI handler that is called when the EndOfDxe event is signaled.\r
+  This function installs the MM EndOfDxe Protocol so MM Drivers are informed that\r
+  platform code will invoke 3rd part code.\r
+\r
+  @param  DispatchHandle  The unique handle assigned to this handler by MmiHandlerRegister().\r
+  @param  Context         Points to an optional handler context which was specified when the handler was registered.\r
+  @param  CommBuffer      A pointer to a collection of data in memory that will\r
+                          be conveyed from a non-MM environment into an MM environment.\r
+  @param  CommBufferSize  The size of the CommBuffer.\r
+\r
+  @return Status Code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MmEndOfDxeHandler (\r
+  IN     EFI_HANDLE  DispatchHandle,\r
+  IN     CONST VOID  *Context,        OPTIONAL\r
+  IN OUT VOID        *CommBuffer,     OPTIONAL\r
+  IN OUT UINTN       *CommBufferSize  OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_HANDLE  MmHandle;\r
+\r
+  DEBUG ((DEBUG_INFO, "MmEndOfDxeHandler\n"));\r
+  //\r
+  // Install MM EndOfDxe protocol\r
+  //\r
+  MmHandle = NULL;\r
+  Status = MmInstallProtocolInterface (\r
+             &MmHandle,\r
+             &gEfiMmEndOfDxeProtocolGuid,\r
+             EFI_NATIVE_INTERFACE,\r
+             NULL\r
+             );\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  The main entry point to MM Foundation.\r
+\r
+  Note: This function is only used by MMRAM invocation.  It is never used by DXE invocation.\r
+\r
+  @param  MmEntryContext           Processor information and functionality\r
+                                    needed by MM Foundation.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+MmEntryPoint (\r
+  IN CONST EFI_MM_ENTRY_CONTEXT  *MmEntryContext\r
+)\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_MM_COMMUNICATE_HEADER  *CommunicateHeader;\r
+  BOOLEAN                     InLegacyBoot;\r
+\r
+  DEBUG ((DEBUG_INFO, "MmEntryPoint ...\n"));\r
+\r
+  //\r
+  // Update MMST using the context\r
+  //\r
+  CopyMem (&gMmCoreMmst.MmStartupThisAp, MmEntryContext, sizeof (EFI_MM_ENTRY_CONTEXT));\r
+\r
+  //\r
+  // Call platform hook before Mm Dispatch\r
+  //\r
+  //PlatformHookBeforeMmDispatch ();\r
+\r
+  //\r
+  // If a legacy boot has occured, then make sure gMmCorePrivate is not accessed\r
+  //\r
+  InLegacyBoot = mInLegacyBoot;\r
+  if (!InLegacyBoot) {\r
+    //\r
+    // TBD: Mark the InMm flag as TRUE\r
+    //\r
+    gMmCorePrivate->InMm = TRUE;\r
+\r
+    //\r
+    // Check to see if this is a Synchronous MMI sent through the MM Communication\r
+    // Protocol or an Asynchronous MMI\r
+    //\r
+    if (gMmCorePrivate->CommunicationBuffer != 0) {\r
+      //\r
+      // Synchronous MMI for MM Core or request from Communicate protocol\r
+      //\r
+      if (!MmIsBufferOutsideMmValid ((UINTN)gMmCorePrivate->CommunicationBuffer, gMmCorePrivate->BufferSize)) {\r
+        //\r
+        // If CommunicationBuffer is not in valid address scope, return EFI_INVALID_PARAMETER\r
+        //\r
+        gMmCorePrivate->CommunicationBuffer = 0;\r
+        gMmCorePrivate->ReturnStatus = EFI_INVALID_PARAMETER;\r
+      } else {\r
+        CommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)(UINTN)gMmCorePrivate->CommunicationBuffer;\r
+        gMmCorePrivate->BufferSize -= OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);\r
+        Status = MmiManage (\r
+                   &CommunicateHeader->HeaderGuid,\r
+                   NULL,\r
+                   CommunicateHeader->Data,\r
+                   (UINTN *)&gMmCorePrivate->BufferSize\r
+                   );\r
+        //\r
+        // Update CommunicationBuffer, BufferSize and ReturnStatus\r
+        // Communicate service finished, reset the pointer to CommBuffer to NULL\r
+        //\r
+        gMmCorePrivate->BufferSize += OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);\r
+        gMmCorePrivate->CommunicationBuffer = 0;\r
+        gMmCorePrivate->ReturnStatus = (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_NOT_FOUND;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Process Asynchronous MMI sources\r
+  //\r
+  MmiManage (NULL, NULL, NULL, NULL);\r
+\r
+  //\r
+  // TBD: Do not use private data structure ?\r
+  //\r
+\r
+  //\r
+  // If a legacy boot has occured, then make sure gMmCorePrivate is not accessed\r
+  //\r
+  if (!InLegacyBoot) {\r
+    //\r
+    // Clear the InMm flag as we are going to leave MM\r
+    //\r
+    gMmCorePrivate->InMm = FALSE;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "MmEntryPoint Done\n"));\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+MmConfigurationMmNotify (\r
+  IN CONST EFI_GUID *Protocol,\r
+  IN VOID           *Interface,\r
+  IN EFI_HANDLE      Handle\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_MM_CONFIGURATION_PROTOCOL  *MmConfiguration;\r
+\r
+  DEBUG ((DEBUG_INFO, "MmConfigurationMmNotify(%g) - %x\n", Protocol, Interface));\r
+\r
+  MmConfiguration = Interface;\r
+\r
+  //\r
+  // Register the MM Entry Point provided by the MM Core with the MM COnfiguration protocol\r
+  //\r
+  Status = MmConfiguration->RegisterMmEntry (MmConfiguration, (EFI_MM_ENTRY_POINT)(UINTN)gMmCorePrivate->MmEntryPoint);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Set flag to indicate that the MM Entry Point has been registered which\r
+  // means that MMIs are now fully operational.\r
+  //\r
+  gMmCorePrivate->MmEntryPointRegistered = TRUE;\r
+\r
+  //\r
+  // Print debug message showing MM Core entry point address.\r
+  //\r
+  DEBUG ((DEBUG_INFO, "MM Core registered MM Entry Point address %p\n", (VOID *)(UINTN)gMmCorePrivate->MmEntryPoint));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+UINTN\r
+GetHobListSize (\r
+  IN VOID *HobStart\r
+  )\r
+{\r
+  EFI_PEI_HOB_POINTERS  Hob;\r
+\r
+  ASSERT (HobStart != NULL);\r
+\r
+  Hob.Raw = (UINT8 *) HobStart;\r
+  while (!END_OF_HOB_LIST (Hob)) {\r
+    Hob.Raw = GET_NEXT_HOB (Hob);\r
+  }\r
+  //\r
+  // Need plus END_OF_HOB_LIST\r
+  //\r
+  return (UINTN)Hob.Raw - (UINTN)HobStart + sizeof (EFI_HOB_GENERIC_HEADER);\r
+}\r
+\r
+/**\r
+  The Entry Point for MM Core\r
+\r
+  Install DXE Protocols and reload MM Core into MMRAM and register MM Core\r
+  EntryPoint on the MMI vector.\r
+\r
+  Note: This function is called for both DXE invocation and MMRAM invocation.\r
+\r
+  @param  ImageHandle    The firmware allocated handle for the EFI image.\r
+  @param  SystemTable    A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS    The entry point is executed successfully.\r
+  @retval Other          Some error occurred when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+StandaloneMmMain (\r
+  IN VOID  *HobStart\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  UINTN                           Index;\r
+  VOID                            *MmHobStart;\r
+  UINTN                           HobSize;\r
+  VOID                            *Registration;\r
+  EFI_HOB_GUID_TYPE               *GuidHob;\r
+  MM_CORE_DATA_HOB_DATA           *DataInHob;\r
+  EFI_HOB_GUID_TYPE               *MmramRangesHob;\r
+  EFI_MMRAM_HOB_DESCRIPTOR_BLOCK  *MmramRangesHobData;\r
+  EFI_MMRAM_DESCRIPTOR            *MmramRanges;\r
+  UINT32                          MmramRangeCount;\r
+  EFI_HOB_FIRMWARE_VOLUME         *BfvHob;\r
+\r
+  ProcessLibraryConstructorList (HobStart, &gMmCoreMmst);\r
+\r
+  DEBUG ((DEBUG_INFO, "MmMain - 0x%x\n", HobStart));\r
+\r
+  //\r
+  // Determine if the caller has passed a reference to a MM_CORE_PRIVATE_DATA\r
+  // structure in the Hoblist. This choice will govern how boot information is\r
+  // extracted later.\r
+  //\r
+  GuidHob = GetNextGuidHob (&gMmCoreDataHobGuid, HobStart);\r
+  if (GuidHob == NULL) {\r
+    //\r
+    // Allocate and zero memory for a MM_CORE_PRIVATE_DATA table and then\r
+    // initialise it\r
+    //\r
+    gMmCorePrivate = (MM_CORE_PRIVATE_DATA *) AllocateRuntimePages(EFI_SIZE_TO_PAGES(sizeof (MM_CORE_PRIVATE_DATA)));\r
+    SetMem ((VOID *)(UINTN)gMmCorePrivate, sizeof (MM_CORE_PRIVATE_DATA), 0);\r
+    gMmCorePrivate->Signature = MM_CORE_PRIVATE_DATA_SIGNATURE;\r
+    gMmCorePrivate->MmEntryPointRegistered = FALSE;\r
+    gMmCorePrivate->InMm = FALSE;\r
+    gMmCorePrivate->ReturnStatus = EFI_SUCCESS;\r
+\r
+    //\r
+    // Extract the MMRAM ranges from the MMRAM descriptor HOB\r
+    //\r
+    MmramRangesHob = GetNextGuidHob (&gEfiMmPeiMmramMemoryReserveGuid, HobStart);\r
+    if (MmramRangesHob == NULL)\r
+      return EFI_UNSUPPORTED;\r
+\r
+    MmramRangesHobData = GET_GUID_HOB_DATA (MmramRangesHob);\r
+    ASSERT (MmramRangesHobData != NULL);\r
+    MmramRanges = MmramRangesHobData->Descriptor;\r
+    MmramRangeCount = MmramRangesHobData->NumberOfMmReservedRegions;\r
+    ASSERT (MmramRanges);\r
+    ASSERT (MmramRangeCount);\r
+\r
+    //\r
+    // Copy the MMRAM ranges into MM_CORE_PRIVATE_DATA table just in case any\r
+    // code relies on them being present there\r
+    //\r
+    gMmCorePrivate->MmramRangeCount = MmramRangeCount;\r
+    gMmCorePrivate->MmramRanges =\r
+      (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (MmramRangeCount * sizeof (EFI_MMRAM_DESCRIPTOR));\r
+    ASSERT (gMmCorePrivate->MmramRanges != 0);\r
+    CopyMem (\r
+      (VOID *)(UINTN)gMmCorePrivate->MmramRanges,\r
+      MmramRanges,\r
+      MmramRangeCount * sizeof (EFI_MMRAM_DESCRIPTOR)\r
+      );\r
+  } else {\r
+    DataInHob       = GET_GUID_HOB_DATA (GuidHob);\r
+    gMmCorePrivate = (MM_CORE_PRIVATE_DATA *)(UINTN)DataInHob->Address;\r
+    MmramRanges     = (EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate->MmramRanges;\r
+    MmramRangeCount = gMmCorePrivate->MmramRangeCount;\r
+  }\r
+\r
+  //\r
+  // Print the MMRAM ranges passed by the caller\r
+  //\r
+  DEBUG ((DEBUG_INFO, "MmramRangeCount - 0x%x\n", MmramRangeCount));\r
+  for (Index = 0; Index < MmramRangeCount; Index++) {\r
+          DEBUG ((DEBUG_INFO, "MmramRanges[%d]: 0x%016lx - 0x%lx\n", Index,\r
+                  MmramRanges[Index].CpuStart,\r
+                  MmramRanges[Index].PhysicalSize));\r
+  }\r
+\r
+  //\r
+  // Copy the MMRAM ranges into private MMRAM\r
+  //\r
+  mMmramRangeCount = MmramRangeCount;\r
+  DEBUG ((DEBUG_INFO, "mMmramRangeCount - 0x%x\n", mMmramRangeCount));\r
+  mMmramRanges = AllocatePool (mMmramRangeCount * sizeof (EFI_MMRAM_DESCRIPTOR));\r
+  DEBUG ((DEBUG_INFO, "mMmramRanges - 0x%x\n", mMmramRanges));\r
+  ASSERT (mMmramRanges != NULL);\r
+  CopyMem (mMmramRanges, (VOID *)(UINTN)MmramRanges, mMmramRangeCount * sizeof (EFI_MMRAM_DESCRIPTOR));\r
+\r
+  //\r
+  // Get Boot Firmware Volume address from the BFV Hob\r
+  //\r
+  BfvHob = GetFirstHob (EFI_HOB_TYPE_FV);\r
+  if (BfvHob != NULL) {\r
+    DEBUG ((DEBUG_INFO, "BFV address - 0x%x\n", BfvHob->BaseAddress));\r
+    DEBUG ((DEBUG_INFO, "BFV size    - 0x%x\n", BfvHob->Length));\r
+    gMmCorePrivate->StandaloneBfvAddress = BfvHob->BaseAddress;\r
+  }\r
+\r
+  gMmCorePrivate->Mmst          = (EFI_PHYSICAL_ADDRESS)(UINTN)&gMmCoreMmst;\r
+  gMmCorePrivate->MmEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)MmEntryPoint;\r
+\r
+  //\r
+  // No need to initialize memory service.\r
+  // It is done in constructor of StandaloneMmCoreMemoryAllocationLib(),\r
+  // so that the library linked with StandaloneMmCore can use AllocatePool() in constuctor.\r
+  //\r
+\r
+  DEBUG ((DEBUG_INFO, "MmInstallConfigurationTable For HobList\n"));\r
+  //\r
+  // Install HobList\r
+  //\r
+  HobSize = GetHobListSize (HobStart);\r
+  DEBUG ((DEBUG_INFO, "HobSize - 0x%x\n", HobSize));\r
+  MmHobStart = AllocatePool (HobSize);\r
+  DEBUG ((DEBUG_INFO, "MmHobStart - 0x%x\n", MmHobStart));\r
+  ASSERT (MmHobStart != NULL);\r
+  CopyMem (MmHobStart, HobStart, HobSize);\r
+  Status = MmInstallConfigurationTable (&gMmCoreMmst, &gEfiHobListGuid, MmHobStart, HobSize);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Register notification for EFI_MM_CONFIGURATION_PROTOCOL registration and\r
+  // use it to register the MM Foundation entrypoint\r
+  //\r
+  DEBUG ((DEBUG_INFO, "MmRegisterProtocolNotify - MmConfigurationMmProtocol\n"));\r
+  Status = MmRegisterProtocolNotify (\r
+             &gEfiMmConfigurationProtocolGuid,\r
+             MmConfigurationMmNotify,\r
+             &Registration\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Dispatch standalone BFV\r
+  //\r
+  DEBUG ((DEBUG_INFO, "Mm Dispatch StandaloneBfvAddress - 0x%08x\n", gMmCorePrivate->StandaloneBfvAddress));\r
+  if (gMmCorePrivate->StandaloneBfvAddress != 0) {\r
+    MmCoreFfsFindMmDriver ((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)gMmCorePrivate->StandaloneBfvAddress);\r
+    MmDispatcher ();\r
+  }\r
+\r
+  //\r
+  // Register all handlers in the core table\r
+  //\r
+  for (Index = 0; mMmCoreMmiHandlers[Index].HandlerType != NULL; Index++) {\r
+    Status = MmiHandlerRegister (\r
+               mMmCoreMmiHandlers[Index].Handler,\r
+               mMmCoreMmiHandlers[Index].HandlerType,\r
+               &mMmCoreMmiHandlers[Index].DispatchHandle\r
+               );\r
+    DEBUG ((DEBUG_INFO, "MmiHandlerRegister - GUID %g - Status %d\n", mMmCoreMmiHandlers[Index].HandlerType, Status));\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "MmMain Done!\n"));\r
+\r
+  return EFI_SUCCESS;\r
+}\r