--- /dev/null
+/** @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