1 /** @file
2   MM Core Main Entry Point
3 
4   Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
5   Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
6   SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include "StandaloneMmCore.h"
11 
12 EFI_STATUS
13 MmCoreFfsFindMmDriver (
14   IN  EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader
15   );
16 
17 EFI_STATUS
18 MmDispatcher (
19   VOID
20   );
21 
22 //
23 // Globals used to initialize the protocol
24 //
25 EFI_HANDLE            mMmCpuHandle = NULL;
26 
27 //
28 // Physical pointer to private structure shared between MM IPL and the MM Core
29 //
30 MM_CORE_PRIVATE_DATA  *gMmCorePrivate;
31 
32 //
33 // MM Core global variable for MM System Table.  Only accessed as a physical structure in MMRAM.
34 //
35 EFI_MM_SYSTEM_TABLE  gMmCoreMmst = {
36 
37   // The table header for the MMST.
38   {
39     MM_MMST_SIGNATURE,
40     EFI_MM_SYSTEM_TABLE_REVISION,
41     sizeof (gMmCoreMmst.Hdr)
42   },
43   // MmFirmwareVendor
44   NULL,
45   // MmFirmwareRevision
46   0,
47   // MmInstallConfigurationTable
48   MmInstallConfigurationTable,
49   // I/O Service
50   {
51     {
52       (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5,       // MmMemRead
53       (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5        // MmMemWrite
54     },
55     {
56       (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5,       // MmIoRead
57       (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5        // MmIoWrite
58     }
59   },
60   // Runtime memory services
61   MmAllocatePool,
62   MmFreePool,
63   MmAllocatePages,
64   MmFreePages,
65   // MP service
66   NULL,                          // MmStartupThisAp
67   0,                             // CurrentlyExecutingCpu
68   0,                             // NumberOfCpus
69   NULL,                          // CpuSaveStateSize
70   NULL,                          // CpuSaveState
71   0,                             // NumberOfTableEntries
72   NULL,                          // MmConfigurationTable
73   MmInstallProtocolInterface,
74   MmUninstallProtocolInterface,
75   MmHandleProtocol,
76   MmRegisterProtocolNotify,
77   MmLocateHandle,
78   MmLocateProtocol,
79   MmiManage,
80   MmiHandlerRegister,
81   MmiHandlerUnRegister
82 };
83 
84 //
85 // Table of MMI Handlers that are registered by the MM Core when it is initialized
86 //
87 MM_CORE_MMI_HANDLERS  mMmCoreMmiHandlers[] = {
88   { MmReadyToLockHandler,    &gEfiDxeMmReadyToLockProtocolGuid,  NULL, TRUE  },
89   { MmEndOfDxeHandler,       &gEfiEndOfDxeEventGroupGuid,        NULL, FALSE },
90   { MmExitBootServiceHandler,&gEfiEventExitBootServicesGuid,     NULL, FALSE },
91   { MmReadyToBootHandler,    &gEfiEventReadyToBootGuid,          NULL, FALSE },
92   { NULL,                    NULL,                               NULL, FALSE },
93 };
94 
95 EFI_SYSTEM_TABLE                *mEfiSystemTable;
96 UINTN                           mMmramRangeCount;
97 EFI_MMRAM_DESCRIPTOR            *mMmramRanges;
98 
99 /**
100   Place holder function until all the MM System Table Service are available.
101 
102   Note: This function is only used by MMRAM invocation.  It is never used by DXE invocation.
103 
104   @param  Arg1                   Undefined
105   @param  Arg2                   Undefined
106   @param  Arg3                   Undefined
107   @param  Arg4                   Undefined
108   @param  Arg5                   Undefined
109 
110   @return EFI_NOT_AVAILABLE_YET
111 
112 **/
113 EFI_STATUS
114 EFIAPI
MmEfiNotAvailableYetArg5(UINTN Arg1,UINTN Arg2,UINTN Arg3,UINTN Arg4,UINTN Arg5)115 MmEfiNotAvailableYetArg5 (
116   UINTN Arg1,
117   UINTN Arg2,
118   UINTN Arg3,
119   UINTN Arg4,
120   UINTN Arg5
121   )
122 {
123   //
124   // This function should never be executed.  If it does, then the architectural protocols
125   // have not been designed correctly.
126   //
127   return EFI_NOT_AVAILABLE_YET;
128 }
129 
130 /**
131   Software MMI handler that is called when a ExitBoot Service event is signaled.
132 
133   @param  DispatchHandle  The unique handle assigned to this handler by MmiHandlerRegister().
134   @param  Context         Points to an optional handler context which was specified when the handler was registered.
135   @param  CommBuffer      A pointer to a collection of data in memory that will
136                           be conveyed from a non-MM environment into an MM environment.
137   @param  CommBufferSize  The size of the CommBuffer.
138 
139   @return Status Code
140 
141 **/
142 EFI_STATUS
143 EFIAPI
MmExitBootServiceHandler(IN EFI_HANDLE DispatchHandle,IN CONST VOID * Context,OPTIONAL IN OUT VOID * CommBuffer,OPTIONAL IN OUT UINTN * CommBufferSize OPTIONAL)144 MmExitBootServiceHandler (
145   IN     EFI_HANDLE  DispatchHandle,
146   IN     CONST VOID  *Context,        OPTIONAL
147   IN OUT VOID        *CommBuffer,     OPTIONAL
148   IN OUT UINTN       *CommBufferSize  OPTIONAL
149   )
150 {
151   EFI_HANDLE  MmHandle;
152   EFI_STATUS  Status = EFI_SUCCESS;
153   STATIC BOOLEAN mInExitBootServices = FALSE;
154 
155   if (!mInExitBootServices) {
156     MmHandle = NULL;
157     Status = MmInstallProtocolInterface (
158                &MmHandle,
159                &gEfiEventExitBootServicesGuid,
160                EFI_NATIVE_INTERFACE,
161                NULL
162                );
163   }
164   mInExitBootServices = TRUE;
165   return Status;
166 }
167 
168 /**
169   Software MMI handler that is called when a ExitBoot Service event is signaled.
170 
171   @param  DispatchHandle  The unique handle assigned to this handler by MmiHandlerRegister().
172   @param  Context         Points to an optional handler context which was specified when the handler was registered.
173   @param  CommBuffer      A pointer to a collection of data in memory that will
174                           be conveyed from a non-MM environment into an MM environment.
175   @param  CommBufferSize  The size of the CommBuffer.
176 
177   @return Status Code
178 
179 **/
180 EFI_STATUS
181 EFIAPI
MmReadyToBootHandler(IN EFI_HANDLE DispatchHandle,IN CONST VOID * Context,OPTIONAL IN OUT VOID * CommBuffer,OPTIONAL IN OUT UINTN * CommBufferSize OPTIONAL)182 MmReadyToBootHandler (
183   IN     EFI_HANDLE  DispatchHandle,
184   IN     CONST VOID  *Context,        OPTIONAL
185   IN OUT VOID        *CommBuffer,     OPTIONAL
186   IN OUT UINTN       *CommBufferSize  OPTIONAL
187   )
188 {
189   EFI_HANDLE  MmHandle;
190   EFI_STATUS  Status = EFI_SUCCESS;
191   STATIC BOOLEAN mInReadyToBoot = FALSE;
192 
193   if (!mInReadyToBoot) {
194     MmHandle = NULL;
195     Status = MmInstallProtocolInterface (
196                &MmHandle,
197                &gEfiEventReadyToBootGuid,
198                EFI_NATIVE_INTERFACE,
199                NULL
200                );
201   }
202   mInReadyToBoot = TRUE;
203   return Status;
204 }
205 
206 /**
207   Software MMI handler that is called when the DxeMmReadyToLock protocol is added
208   or if gEfiEventReadyToBootGuid is signaled.  This function unregisters the
209   Software SMIs that are nor required after MMRAM is locked and installs the
210   MM Ready To Lock Protocol so MM Drivers are informed that MMRAM is about
211   to be locked.
212 
213   @param  DispatchHandle  The unique handle assigned to this handler by MmiHandlerRegister().
214   @param  Context         Points to an optional handler context which was specified when the handler was registered.
215   @param  CommBuffer      A pointer to a collection of data in memory that will
216                           be conveyed from a non-MM environment into an MM environment.
217   @param  CommBufferSize  The size of the CommBuffer.
218 
219   @return Status Code
220 
221 **/
222 EFI_STATUS
223 EFIAPI
MmReadyToLockHandler(IN EFI_HANDLE DispatchHandle,IN CONST VOID * Context,OPTIONAL IN OUT VOID * CommBuffer,OPTIONAL IN OUT UINTN * CommBufferSize OPTIONAL)224 MmReadyToLockHandler (
225   IN     EFI_HANDLE  DispatchHandle,
226   IN     CONST VOID  *Context,        OPTIONAL
227   IN OUT VOID        *CommBuffer,     OPTIONAL
228   IN OUT UINTN       *CommBufferSize  OPTIONAL
229   )
230 {
231   EFI_STATUS  Status;
232   UINTN       Index;
233   EFI_HANDLE  MmHandle;
234 
235   DEBUG ((DEBUG_INFO, "MmReadyToLockHandler\n"));
236 
237   //
238   // Unregister MMI Handlers that are no longer required after the MM driver dispatch is stopped
239   //
240   for (Index = 0; mMmCoreMmiHandlers[Index].HandlerType != NULL; Index++) {
241     if (mMmCoreMmiHandlers[Index].UnRegister) {
242       MmiHandlerUnRegister (mMmCoreMmiHandlers[Index].DispatchHandle);
243     }
244   }
245 
246   //
247   // Install MM Ready to lock protocol
248   //
249   MmHandle = NULL;
250   Status = MmInstallProtocolInterface (
251              &MmHandle,
252              &gEfiMmReadyToLockProtocolGuid,
253              EFI_NATIVE_INTERFACE,
254              NULL
255              );
256 
257   //
258   // Make sure MM CPU I/O 2 Protocol has been installed into the handle database
259   //
260   //Status = MmLocateProtocol (&EFI_MM_CPU_IO_PROTOCOL_GUID, NULL, &Interface);
261 
262   //
263   // Print a message on a debug build if the MM CPU I/O 2 Protocol is not installed
264   //
265   //if (EFI_ERROR (Status)) {
266       //DEBUG ((DEBUG_ERROR, "\nSMM: SmmCpuIo Arch Protocol not present!!\n"));
267   //}
268 
269 
270   //
271   // Assert if the CPU I/O 2 Protocol is not installed
272   //
273   //ASSERT_EFI_ERROR (Status);
274 
275   //
276   // Display any drivers that were not dispatched because dependency expression
277   // evaluated to false if this is a debug build
278   //
279   //MmDisplayDiscoveredNotDispatched ();
280 
281   return Status;
282 }
283 
284 /**
285   Software MMI handler that is called when the EndOfDxe event is signaled.
286   This function installs the MM EndOfDxe Protocol so MM Drivers are informed that
287   platform code will invoke 3rd part code.
288 
289   @param  DispatchHandle  The unique handle assigned to this handler by MmiHandlerRegister().
290   @param  Context         Points to an optional handler context which was specified when the handler was registered.
291   @param  CommBuffer      A pointer to a collection of data in memory that will
292                           be conveyed from a non-MM environment into an MM environment.
293   @param  CommBufferSize  The size of the CommBuffer.
294 
295   @return Status Code
296 
297 **/
298 EFI_STATUS
299 EFIAPI
MmEndOfDxeHandler(IN EFI_HANDLE DispatchHandle,IN CONST VOID * Context,OPTIONAL IN OUT VOID * CommBuffer,OPTIONAL IN OUT UINTN * CommBufferSize OPTIONAL)300 MmEndOfDxeHandler (
301   IN     EFI_HANDLE  DispatchHandle,
302   IN     CONST VOID  *Context,        OPTIONAL
303   IN OUT VOID        *CommBuffer,     OPTIONAL
304   IN OUT UINTN       *CommBufferSize  OPTIONAL
305   )
306 {
307   EFI_STATUS  Status;
308   EFI_HANDLE  MmHandle;
309 
310   DEBUG ((DEBUG_INFO, "MmEndOfDxeHandler\n"));
311   //
312   // Install MM EndOfDxe protocol
313   //
314   MmHandle = NULL;
315   Status = MmInstallProtocolInterface (
316              &MmHandle,
317              &gEfiMmEndOfDxeProtocolGuid,
318              EFI_NATIVE_INTERFACE,
319              NULL
320              );
321   return Status;
322 }
323 
324 
325 
326 /**
327   The main entry point to MM Foundation.
328 
329   Note: This function is only used by MMRAM invocation.  It is never used by DXE invocation.
330 
331   @param  MmEntryContext           Processor information and functionality
332                                     needed by MM Foundation.
333 
334 **/
335 VOID
336 EFIAPI
MmEntryPoint(IN CONST EFI_MM_ENTRY_CONTEXT * MmEntryContext)337 MmEntryPoint (
338   IN CONST EFI_MM_ENTRY_CONTEXT  *MmEntryContext
339 )
340 {
341   EFI_STATUS                  Status;
342   EFI_MM_COMMUNICATE_HEADER  *CommunicateHeader;
343 
344   DEBUG ((DEBUG_INFO, "MmEntryPoint ...\n"));
345 
346   //
347   // Update MMST using the context
348   //
349   CopyMem (&gMmCoreMmst.MmStartupThisAp, MmEntryContext, sizeof (EFI_MM_ENTRY_CONTEXT));
350 
351   //
352   // Call platform hook before Mm Dispatch
353   //
354   //PlatformHookBeforeMmDispatch ();
355 
356   //
357   // If a legacy boot has occured, then make sure gMmCorePrivate is not accessed
358   //
359 
360   //
361   // TBD: Mark the InMm flag as TRUE
362   //
363   gMmCorePrivate->InMm = TRUE;
364 
365   //
366   // Check to see if this is a Synchronous MMI sent through the MM Communication
367   // Protocol or an Asynchronous MMI
368   //
369   if (gMmCorePrivate->CommunicationBuffer != 0) {
370     //
371     // Synchronous MMI for MM Core or request from Communicate protocol
372     //
373     if (!MmIsBufferOutsideMmValid ((UINTN)gMmCorePrivate->CommunicationBuffer, gMmCorePrivate->BufferSize)) {
374       //
375       // If CommunicationBuffer is not in valid address scope, return EFI_INVALID_PARAMETER
376       //
377       gMmCorePrivate->CommunicationBuffer = 0;
378       gMmCorePrivate->ReturnStatus = EFI_INVALID_PARAMETER;
379     } else {
380       CommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)(UINTN)gMmCorePrivate->CommunicationBuffer;
381       gMmCorePrivate->BufferSize -= OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);
382       Status = MmiManage (
383                  &CommunicateHeader->HeaderGuid,
384                  NULL,
385                  CommunicateHeader->Data,
386                  (UINTN *)&gMmCorePrivate->BufferSize
387                  );
388       //
389       // Update CommunicationBuffer, BufferSize and ReturnStatus
390       // Communicate service finished, reset the pointer to CommBuffer to NULL
391       //
392       gMmCorePrivate->BufferSize += OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);
393       gMmCorePrivate->CommunicationBuffer = 0;
394       gMmCorePrivate->ReturnStatus = (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_NOT_FOUND;
395     }
396   }
397 
398   //
399   // Process Asynchronous MMI sources
400   //
401   MmiManage (NULL, NULL, NULL, NULL);
402 
403   //
404   // TBD: Do not use private data structure ?
405   //
406 
407   //
408   // Clear the InMm flag as we are going to leave MM
409   //
410   gMmCorePrivate->InMm = FALSE;
411 
412   DEBUG ((DEBUG_INFO, "MmEntryPoint Done\n"));
413 }
414 
415 EFI_STATUS
416 EFIAPI
MmConfigurationMmNotify(IN CONST EFI_GUID * Protocol,IN VOID * Interface,IN EFI_HANDLE Handle)417 MmConfigurationMmNotify (
418   IN CONST EFI_GUID *Protocol,
419   IN VOID           *Interface,
420   IN EFI_HANDLE      Handle
421   )
422 {
423   EFI_STATUS                      Status;
424   EFI_MM_CONFIGURATION_PROTOCOL  *MmConfiguration;
425 
426   DEBUG ((DEBUG_INFO, "MmConfigurationMmNotify(%g) - %x\n", Protocol, Interface));
427 
428   MmConfiguration = Interface;
429 
430   //
431   // Register the MM Entry Point provided by the MM Core with the MM COnfiguration protocol
432   //
433   Status = MmConfiguration->RegisterMmEntry (MmConfiguration, (EFI_MM_ENTRY_POINT)(UINTN)gMmCorePrivate->MmEntryPoint);
434   ASSERT_EFI_ERROR (Status);
435 
436   //
437   // Set flag to indicate that the MM Entry Point has been registered which
438   // means that MMIs are now fully operational.
439   //
440   gMmCorePrivate->MmEntryPointRegistered = TRUE;
441 
442   //
443   // Print debug message showing MM Core entry point address.
444   //
445   DEBUG ((DEBUG_INFO, "MM Core registered MM Entry Point address %p\n", (VOID *)(UINTN)gMmCorePrivate->MmEntryPoint));
446   return EFI_SUCCESS;
447 }
448 
449 UINTN
GetHobListSize(IN VOID * HobStart)450 GetHobListSize (
451   IN VOID *HobStart
452   )
453 {
454   EFI_PEI_HOB_POINTERS  Hob;
455 
456   ASSERT (HobStart != NULL);
457 
458   Hob.Raw = (UINT8 *) HobStart;
459   while (!END_OF_HOB_LIST (Hob)) {
460     Hob.Raw = GET_NEXT_HOB (Hob);
461   }
462   //
463   // Need plus END_OF_HOB_LIST
464   //
465   return (UINTN)Hob.Raw - (UINTN)HobStart + sizeof (EFI_HOB_GENERIC_HEADER);
466 }
467 
468 /**
469   The Entry Point for MM Core
470 
471   Install DXE Protocols and reload MM Core into MMRAM and register MM Core
472   EntryPoint on the MMI vector.
473 
474   Note: This function is called for both DXE invocation and MMRAM invocation.
475 
476   @param  ImageHandle    The firmware allocated handle for the EFI image.
477   @param  SystemTable    A pointer to the EFI System Table.
478 
479   @retval EFI_SUCCESS    The entry point is executed successfully.
480   @retval Other          Some error occurred when executing this entry point.
481 
482 **/
483 EFI_STATUS
484 EFIAPI
StandaloneMmMain(IN VOID * HobStart)485 StandaloneMmMain (
486   IN VOID  *HobStart
487   )
488 {
489   EFI_STATUS                      Status;
490   UINTN                           Index;
491   VOID                            *MmHobStart;
492   UINTN                           HobSize;
493   VOID                            *Registration;
494   EFI_HOB_GUID_TYPE               *GuidHob;
495   MM_CORE_DATA_HOB_DATA           *DataInHob;
496   EFI_HOB_GUID_TYPE               *MmramRangesHob;
497   EFI_MMRAM_HOB_DESCRIPTOR_BLOCK  *MmramRangesHobData;
498   EFI_MMRAM_DESCRIPTOR            *MmramRanges;
499   UINT32                          MmramRangeCount;
500   EFI_HOB_FIRMWARE_VOLUME         *BfvHob;
501 
502   ProcessLibraryConstructorList (HobStart, &gMmCoreMmst);
503 
504   DEBUG ((DEBUG_INFO, "MmMain - 0x%x\n", HobStart));
505 
506   //
507   // Determine if the caller has passed a reference to a MM_CORE_PRIVATE_DATA
508   // structure in the Hoblist. This choice will govern how boot information is
509   // extracted later.
510   //
511   GuidHob = GetNextGuidHob (&gMmCoreDataHobGuid, HobStart);
512   if (GuidHob == NULL) {
513     //
514     // Allocate and zero memory for a MM_CORE_PRIVATE_DATA table and then
515     // initialise it
516     //
517     gMmCorePrivate = (MM_CORE_PRIVATE_DATA *) AllocateRuntimePages(EFI_SIZE_TO_PAGES(sizeof (MM_CORE_PRIVATE_DATA)));
518     SetMem ((VOID *)(UINTN)gMmCorePrivate, sizeof (MM_CORE_PRIVATE_DATA), 0);
519     gMmCorePrivate->Signature = MM_CORE_PRIVATE_DATA_SIGNATURE;
520     gMmCorePrivate->MmEntryPointRegistered = FALSE;
521     gMmCorePrivate->InMm = FALSE;
522     gMmCorePrivate->ReturnStatus = EFI_SUCCESS;
523 
524     //
525     // Extract the MMRAM ranges from the MMRAM descriptor HOB
526     //
527     MmramRangesHob = GetNextGuidHob (&gEfiMmPeiMmramMemoryReserveGuid, HobStart);
528     if (MmramRangesHob == NULL)
529       return EFI_UNSUPPORTED;
530 
531     MmramRangesHobData = GET_GUID_HOB_DATA (MmramRangesHob);
532     ASSERT (MmramRangesHobData != NULL);
533     MmramRanges = MmramRangesHobData->Descriptor;
534     MmramRangeCount = MmramRangesHobData->NumberOfMmReservedRegions;
535     ASSERT (MmramRanges);
536     ASSERT (MmramRangeCount);
537 
538     //
539     // Copy the MMRAM ranges into MM_CORE_PRIVATE_DATA table just in case any
540     // code relies on them being present there
541     //
542     gMmCorePrivate->MmramRangeCount = MmramRangeCount;
543     gMmCorePrivate->MmramRanges =
544       (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (MmramRangeCount * sizeof (EFI_MMRAM_DESCRIPTOR));
545     ASSERT (gMmCorePrivate->MmramRanges != 0);
546     CopyMem (
547       (VOID *)(UINTN)gMmCorePrivate->MmramRanges,
548       MmramRanges,
549       MmramRangeCount * sizeof (EFI_MMRAM_DESCRIPTOR)
550       );
551   } else {
552     DataInHob       = GET_GUID_HOB_DATA (GuidHob);
553     gMmCorePrivate = (MM_CORE_PRIVATE_DATA *)(UINTN)DataInHob->Address;
554     MmramRanges     = (EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate->MmramRanges;
555     MmramRangeCount = gMmCorePrivate->MmramRangeCount;
556   }
557 
558   //
559   // Print the MMRAM ranges passed by the caller
560   //
561   DEBUG ((DEBUG_INFO, "MmramRangeCount - 0x%x\n", MmramRangeCount));
562   for (Index = 0; Index < MmramRangeCount; Index++) {
563           DEBUG ((DEBUG_INFO, "MmramRanges[%d]: 0x%016lx - 0x%lx\n", Index,
564                   MmramRanges[Index].CpuStart,
565                   MmramRanges[Index].PhysicalSize));
566   }
567 
568   //
569   // Copy the MMRAM ranges into private MMRAM
570   //
571   mMmramRangeCount = MmramRangeCount;
572   DEBUG ((DEBUG_INFO, "mMmramRangeCount - 0x%x\n", mMmramRangeCount));
573   mMmramRanges = AllocatePool (mMmramRangeCount * sizeof (EFI_MMRAM_DESCRIPTOR));
574   DEBUG ((DEBUG_INFO, "mMmramRanges - 0x%x\n", mMmramRanges));
575   ASSERT (mMmramRanges != NULL);
576   CopyMem (mMmramRanges, (VOID *)(UINTN)MmramRanges, mMmramRangeCount * sizeof (EFI_MMRAM_DESCRIPTOR));
577 
578   //
579   // Get Boot Firmware Volume address from the BFV Hob
580   //
581   BfvHob = GetFirstHob (EFI_HOB_TYPE_FV);
582   if (BfvHob != NULL) {
583     DEBUG ((DEBUG_INFO, "BFV address - 0x%x\n", BfvHob->BaseAddress));
584     DEBUG ((DEBUG_INFO, "BFV size    - 0x%x\n", BfvHob->Length));
585     gMmCorePrivate->StandaloneBfvAddress = BfvHob->BaseAddress;
586   }
587 
588   gMmCorePrivate->Mmst          = (EFI_PHYSICAL_ADDRESS)(UINTN)&gMmCoreMmst;
589   gMmCorePrivate->MmEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)MmEntryPoint;
590 
591   //
592   // No need to initialize memory service.
593   // It is done in constructor of StandaloneMmCoreMemoryAllocationLib(),
594   // so that the library linked with StandaloneMmCore can use AllocatePool() in constuctor.
595   //
596 
597   DEBUG ((DEBUG_INFO, "MmInstallConfigurationTable For HobList\n"));
598   //
599   // Install HobList
600   //
601   HobSize = GetHobListSize (HobStart);
602   DEBUG ((DEBUG_INFO, "HobSize - 0x%x\n", HobSize));
603   MmHobStart = AllocatePool (HobSize);
604   DEBUG ((DEBUG_INFO, "MmHobStart - 0x%x\n", MmHobStart));
605   ASSERT (MmHobStart != NULL);
606   CopyMem (MmHobStart, HobStart, HobSize);
607   Status = MmInstallConfigurationTable (&gMmCoreMmst, &gEfiHobListGuid, MmHobStart, HobSize);
608   ASSERT_EFI_ERROR (Status);
609 
610   //
611   // Register notification for EFI_MM_CONFIGURATION_PROTOCOL registration and
612   // use it to register the MM Foundation entrypoint
613   //
614   DEBUG ((DEBUG_INFO, "MmRegisterProtocolNotify - MmConfigurationMmProtocol\n"));
615   Status = MmRegisterProtocolNotify (
616              &gEfiMmConfigurationProtocolGuid,
617              MmConfigurationMmNotify,
618              &Registration
619              );
620   ASSERT_EFI_ERROR (Status);
621 
622   //
623   // Dispatch standalone BFV
624   //
625   DEBUG ((DEBUG_INFO, "Mm Dispatch StandaloneBfvAddress - 0x%08x\n", gMmCorePrivate->StandaloneBfvAddress));
626   if (gMmCorePrivate->StandaloneBfvAddress != 0) {
627     MmCoreFfsFindMmDriver ((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)gMmCorePrivate->StandaloneBfvAddress);
628     MmDispatcher ();
629   }
630 
631   //
632   // Register all handlers in the core table
633   //
634   for (Index = 0; mMmCoreMmiHandlers[Index].HandlerType != NULL; Index++) {
635     Status = MmiHandlerRegister (
636                mMmCoreMmiHandlers[Index].Handler,
637                mMmCoreMmiHandlers[Index].HandlerType,
638                &mMmCoreMmiHandlers[Index].DispatchHandle
639                );
640     DEBUG ((DEBUG_INFO, "MmiHandlerRegister - GUID %g - Status %d\n", mMmCoreMmiHandlers[Index].HandlerType, Status));
641   }
642 
643   DEBUG ((DEBUG_INFO, "MmMain Done!\n"));
644 
645   return EFI_SUCCESS;
646 }
647