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