2 MM Core Main Entry Point
4 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "StandaloneMmCore.h"
13 MmCoreFfsFindMmDriver (
14 IN EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
23 // Globals used to initialize the protocol
25 EFI_HANDLE mMmCpuHandle
= NULL
;
28 // Physical pointer to private structure shared between MM IPL and the MM Core
30 MM_CORE_PRIVATE_DATA
*gMmCorePrivate
;
33 // MM Core global variable for MM System Table. Only accessed as a physical structure in MMRAM.
35 EFI_MM_SYSTEM_TABLE gMmCoreMmst
= {
37 // The table header for the MMST.
40 EFI_MM_SYSTEM_TABLE_REVISION
,
41 sizeof (gMmCoreMmst
.Hdr
)
47 // MmInstallConfigurationTable
48 MmInstallConfigurationTable
,
52 (EFI_MM_CPU_IO
) MmEfiNotAvailableYetArg5
, // MmMemRead
53 (EFI_MM_CPU_IO
) MmEfiNotAvailableYetArg5
// MmMemWrite
56 (EFI_MM_CPU_IO
) MmEfiNotAvailableYetArg5
, // MmIoRead
57 (EFI_MM_CPU_IO
) MmEfiNotAvailableYetArg5
// MmIoWrite
60 // Runtime memory services
66 NULL
, // MmStartupThisAp
67 0, // CurrentlyExecutingCpu
69 NULL
, // CpuSaveStateSize
71 0, // NumberOfTableEntries
72 NULL
, // MmConfigurationTable
73 MmInstallProtocolInterface
,
74 MmUninstallProtocolInterface
,
76 MmRegisterProtocolNotify
,
85 // Table of MMI Handlers that are registered by the MM Core when it is initialized
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
},
95 EFI_SYSTEM_TABLE
*mEfiSystemTable
;
96 UINTN mMmramRangeCount
;
97 EFI_MMRAM_DESCRIPTOR
*mMmramRanges
;
100 Place holder function until all the MM System Table Service are available.
102 Note: This function is only used by MMRAM invocation. It is never used by DXE invocation.
104 @param Arg1 Undefined
105 @param Arg2 Undefined
106 @param Arg3 Undefined
107 @param Arg4 Undefined
108 @param Arg5 Undefined
110 @return EFI_NOT_AVAILABLE_YET
115 MmEfiNotAvailableYetArg5 (
124 // This function should never be executed. If it does, then the architectural protocols
125 // have not been designed correctly.
127 return EFI_NOT_AVAILABLE_YET
;
131 Software MMI handler that is called when a ExitBoot Service event is signaled.
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.
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
153 STATIC BOOLEAN mInExitBootServices
= FALSE
;
155 Status
= EFI_SUCCESS
;
156 if (!mInExitBootServices
) {
158 Status
= MmInstallProtocolInterface (
160 &gEfiEventExitBootServicesGuid
,
161 EFI_NATIVE_INTERFACE
,
165 mInExitBootServices
= TRUE
;
170 Software MMI handler that is called when a ExitBoot Service event is signaled.
172 @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
173 @param Context Points to an optional handler context which was specified when the handler was registered.
174 @param CommBuffer A pointer to a collection of data in memory that will
175 be conveyed from a non-MM environment into an MM environment.
176 @param CommBufferSize The size of the CommBuffer.
183 MmReadyToBootHandler (
184 IN EFI_HANDLE DispatchHandle
,
185 IN CONST VOID
*Context OPTIONAL
,
186 IN OUT VOID
*CommBuffer OPTIONAL
,
187 IN OUT UINTN
*CommBufferSize OPTIONAL
192 STATIC BOOLEAN mInReadyToBoot
= FALSE
;
194 Status
= EFI_SUCCESS
;
195 if (!mInReadyToBoot
) {
197 Status
= MmInstallProtocolInterface (
199 &gEfiEventReadyToBootGuid
,
200 EFI_NATIVE_INTERFACE
,
204 mInReadyToBoot
= TRUE
;
209 Software MMI handler that is called when the DxeMmReadyToLock protocol is added
210 or if gEfiEventReadyToBootGuid is signaled. This function unregisters the
211 Software SMIs that are nor required after MMRAM is locked and installs the
212 MM Ready To Lock Protocol so MM Drivers are informed that MMRAM is about
215 @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
216 @param Context Points to an optional handler context which was specified when the handler was registered.
217 @param CommBuffer A pointer to a collection of data in memory that will
218 be conveyed from a non-MM environment into an MM environment.
219 @param CommBufferSize The size of the CommBuffer.
226 MmReadyToLockHandler (
227 IN EFI_HANDLE DispatchHandle
,
228 IN CONST VOID
*Context OPTIONAL
,
229 IN OUT VOID
*CommBuffer OPTIONAL
,
230 IN OUT UINTN
*CommBufferSize OPTIONAL
237 DEBUG ((DEBUG_INFO
, "MmReadyToLockHandler\n"));
240 // Unregister MMI Handlers that are no longer required after the MM driver dispatch is stopped
242 for (Index
= 0; mMmCoreMmiHandlers
[Index
].HandlerType
!= NULL
; Index
++) {
243 if (mMmCoreMmiHandlers
[Index
].UnRegister
) {
244 MmiHandlerUnRegister (mMmCoreMmiHandlers
[Index
].DispatchHandle
);
249 // Install MM Ready to lock protocol
252 Status
= MmInstallProtocolInterface (
254 &gEfiMmReadyToLockProtocolGuid
,
255 EFI_NATIVE_INTERFACE
,
260 // Make sure MM CPU I/O 2 Protocol has been installed into the handle database
262 //Status = MmLocateProtocol (&EFI_MM_CPU_IO_PROTOCOL_GUID, NULL, &Interface);
265 // Print a message on a debug build if the MM CPU I/O 2 Protocol is not installed
267 //if (EFI_ERROR (Status)) {
268 //DEBUG ((DEBUG_ERROR, "\nSMM: SmmCpuIo Arch Protocol not present!!\n"));
273 // Assert if the CPU I/O 2 Protocol is not installed
275 //ASSERT_EFI_ERROR (Status);
278 // Display any drivers that were not dispatched because dependency expression
279 // evaluated to false if this is a debug build
281 //MmDisplayDiscoveredNotDispatched ();
287 Software MMI handler that is called when the EndOfDxe event is signaled.
288 This function installs the MM EndOfDxe Protocol so MM Drivers are informed that
289 platform code will invoke 3rd part code.
291 @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
292 @param Context Points to an optional handler context which was specified when the handler was registered.
293 @param CommBuffer A pointer to a collection of data in memory that will
294 be conveyed from a non-MM environment into an MM environment.
295 @param CommBufferSize The size of the CommBuffer.
303 IN EFI_HANDLE DispatchHandle
,
304 IN CONST VOID
*Context OPTIONAL
,
305 IN OUT VOID
*CommBuffer OPTIONAL
,
306 IN OUT UINTN
*CommBufferSize OPTIONAL
312 DEBUG ((DEBUG_INFO
, "MmEndOfDxeHandler\n"));
314 // Install MM EndOfDxe protocol
317 Status
= MmInstallProtocolInterface (
319 &gEfiMmEndOfDxeProtocolGuid
,
320 EFI_NATIVE_INTERFACE
,
329 The main entry point to MM Foundation.
331 Note: This function is only used by MMRAM invocation. It is never used by DXE invocation.
333 @param MmEntryContext Processor information and functionality
334 needed by MM Foundation.
340 IN CONST EFI_MM_ENTRY_CONTEXT
*MmEntryContext
344 EFI_MM_COMMUNICATE_HEADER
*CommunicateHeader
;
346 DEBUG ((DEBUG_INFO
, "MmEntryPoint ...\n"));
349 // Update MMST using the context
351 CopyMem (&gMmCoreMmst
.MmStartupThisAp
, MmEntryContext
, sizeof (EFI_MM_ENTRY_CONTEXT
));
354 // Call platform hook before Mm Dispatch
356 //PlatformHookBeforeMmDispatch ();
359 // If a legacy boot has occurred, then make sure gMmCorePrivate is not accessed
363 // TBD: Mark the InMm flag as TRUE
365 gMmCorePrivate
->InMm
= TRUE
;
368 // Check to see if this is a Synchronous MMI sent through the MM Communication
369 // Protocol or an Asynchronous MMI
371 if (gMmCorePrivate
->CommunicationBuffer
!= 0) {
373 // Synchronous MMI for MM Core or request from Communicate protocol
375 if (!MmIsBufferOutsideMmValid ((UINTN
)gMmCorePrivate
->CommunicationBuffer
, gMmCorePrivate
->BufferSize
)) {
377 // If CommunicationBuffer is not in valid address scope, return EFI_INVALID_PARAMETER
379 gMmCorePrivate
->CommunicationBuffer
= 0;
380 gMmCorePrivate
->ReturnStatus
= EFI_INVALID_PARAMETER
;
382 CommunicateHeader
= (EFI_MM_COMMUNICATE_HEADER
*)(UINTN
)gMmCorePrivate
->CommunicationBuffer
;
383 gMmCorePrivate
->BufferSize
-= OFFSET_OF (EFI_MM_COMMUNICATE_HEADER
, Data
);
385 &CommunicateHeader
->HeaderGuid
,
387 CommunicateHeader
->Data
,
388 (UINTN
*)&gMmCorePrivate
->BufferSize
391 // Update CommunicationBuffer, BufferSize and ReturnStatus
392 // Communicate service finished, reset the pointer to CommBuffer to NULL
394 gMmCorePrivate
->BufferSize
+= OFFSET_OF (EFI_MM_COMMUNICATE_HEADER
, Data
);
395 gMmCorePrivate
->CommunicationBuffer
= 0;
396 gMmCorePrivate
->ReturnStatus
= (Status
== EFI_SUCCESS
) ? EFI_SUCCESS
: EFI_NOT_FOUND
;
401 // Process Asynchronous MMI sources
403 MmiManage (NULL
, NULL
, NULL
, NULL
);
406 // TBD: Do not use private data structure ?
410 // Clear the InMm flag as we are going to leave MM
412 gMmCorePrivate
->InMm
= FALSE
;
414 DEBUG ((DEBUG_INFO
, "MmEntryPoint Done\n"));
417 /** Register the MM Entry Point provided by the MM Core with the
418 MM Configuration protocol.
420 @param [in] Protocol Pointer to the protocol.
421 @param [in] Interface Pointer to the MM Configuration protocol.
422 @param [in] Handle Handle.
424 @retval EFI_SUCCESS Success.
428 MmConfigurationMmNotify (
429 IN CONST EFI_GUID
*Protocol
,
435 EFI_MM_CONFIGURATION_PROTOCOL
*MmConfiguration
;
437 DEBUG ((DEBUG_INFO
, "MmConfigurationMmNotify(%g) - %x\n", Protocol
, Interface
));
439 MmConfiguration
= Interface
;
442 // Register the MM Entry Point provided by the MM Core with the MM COnfiguration protocol
444 Status
= MmConfiguration
->RegisterMmEntry (MmConfiguration
, (EFI_MM_ENTRY_POINT
)(UINTN
)gMmCorePrivate
->MmEntryPoint
);
445 ASSERT_EFI_ERROR (Status
);
448 // Set flag to indicate that the MM Entry Point has been registered which
449 // means that MMIs are now fully operational.
451 gMmCorePrivate
->MmEntryPointRegistered
= TRUE
;
454 // Print debug message showing MM Core entry point address.
456 DEBUG ((DEBUG_INFO
, "MM Core registered MM Entry Point address %p\n", (VOID
*)(UINTN
)gMmCorePrivate
->MmEntryPoint
));
460 /** Returns the HOB list size.
462 @param [in] HobStart Pointer to the start of the HOB list.
464 @retval Size of the HOB list.
471 EFI_PEI_HOB_POINTERS Hob
;
473 ASSERT (HobStart
!= NULL
);
475 Hob
.Raw
= (UINT8
*) HobStart
;
476 while (!END_OF_HOB_LIST (Hob
)) {
477 Hob
.Raw
= GET_NEXT_HOB (Hob
);
480 // Need plus END_OF_HOB_LIST
482 return (UINTN
)Hob
.Raw
- (UINTN
)HobStart
+ sizeof (EFI_HOB_GENERIC_HEADER
);
486 The Entry Point for MM Core
488 Install DXE Protocols and reload MM Core into MMRAM and register MM Core
489 EntryPoint on the MMI vector.
491 Note: This function is called for both DXE invocation and MMRAM invocation.
493 @param HobStart Pointer to the start of the HOB list.
495 @retval EFI_SUCCESS Success.
496 @retval EFI_UNSUPPORTED Unsupported operation.
509 EFI_HOB_GUID_TYPE
*GuidHob
;
510 MM_CORE_DATA_HOB_DATA
*DataInHob
;
511 EFI_HOB_GUID_TYPE
*MmramRangesHob
;
512 EFI_MMRAM_HOB_DESCRIPTOR_BLOCK
*MmramRangesHobData
;
513 EFI_MMRAM_DESCRIPTOR
*MmramRanges
;
514 UINTN MmramRangeCount
;
515 EFI_HOB_FIRMWARE_VOLUME
*BfvHob
;
517 ProcessLibraryConstructorList (HobStart
, &gMmCoreMmst
);
519 DEBUG ((DEBUG_INFO
, "MmMain - 0x%x\n", HobStart
));
522 // Determine if the caller has passed a reference to a MM_CORE_PRIVATE_DATA
523 // structure in the Hoblist. This choice will govern how boot information is
526 GuidHob
= GetNextGuidHob (&gMmCoreDataHobGuid
, HobStart
);
527 if (GuidHob
== NULL
) {
529 // Allocate and zero memory for a MM_CORE_PRIVATE_DATA table and then
532 gMmCorePrivate
= (MM_CORE_PRIVATE_DATA
*) AllocateRuntimePages(EFI_SIZE_TO_PAGES(sizeof (MM_CORE_PRIVATE_DATA
)));
533 SetMem ((VOID
*)(UINTN
)gMmCorePrivate
, sizeof (MM_CORE_PRIVATE_DATA
), 0);
534 gMmCorePrivate
->Signature
= MM_CORE_PRIVATE_DATA_SIGNATURE
;
535 gMmCorePrivate
->MmEntryPointRegistered
= FALSE
;
536 gMmCorePrivate
->InMm
= FALSE
;
537 gMmCorePrivate
->ReturnStatus
= EFI_SUCCESS
;
540 // Extract the MMRAM ranges from the MMRAM descriptor HOB
542 MmramRangesHob
= GetNextGuidHob (&gEfiMmPeiMmramMemoryReserveGuid
, HobStart
);
543 if (MmramRangesHob
== NULL
)
544 return EFI_UNSUPPORTED
;
546 MmramRangesHobData
= GET_GUID_HOB_DATA (MmramRangesHob
);
547 ASSERT (MmramRangesHobData
!= NULL
);
548 MmramRanges
= MmramRangesHobData
->Descriptor
;
549 MmramRangeCount
= (UINTN
)MmramRangesHobData
->NumberOfMmReservedRegions
;
550 ASSERT (MmramRanges
);
551 ASSERT (MmramRangeCount
);
554 // Copy the MMRAM ranges into MM_CORE_PRIVATE_DATA table just in case any
555 // code relies on them being present there
557 gMmCorePrivate
->MmramRangeCount
= (UINT64
)MmramRangeCount
;
558 gMmCorePrivate
->MmramRanges
=
559 (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (MmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
));
560 ASSERT (gMmCorePrivate
->MmramRanges
!= 0);
562 (VOID
*)(UINTN
)gMmCorePrivate
->MmramRanges
,
564 MmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
)
567 DataInHob
= GET_GUID_HOB_DATA (GuidHob
);
568 gMmCorePrivate
= (MM_CORE_PRIVATE_DATA
*)(UINTN
)DataInHob
->Address
;
569 MmramRanges
= (EFI_MMRAM_DESCRIPTOR
*)(UINTN
)gMmCorePrivate
->MmramRanges
;
570 MmramRangeCount
= (UINTN
)gMmCorePrivate
->MmramRangeCount
;
574 // Print the MMRAM ranges passed by the caller
576 DEBUG ((DEBUG_INFO
, "MmramRangeCount - 0x%x\n", MmramRangeCount
));
577 for (Index
= 0; Index
< MmramRangeCount
; Index
++) {
578 DEBUG ((DEBUG_INFO
, "MmramRanges[%d]: 0x%016lx - 0x%lx\n", Index
,
579 MmramRanges
[Index
].CpuStart
,
580 MmramRanges
[Index
].PhysicalSize
));
584 // Copy the MMRAM ranges into private MMRAM
586 mMmramRangeCount
= MmramRangeCount
;
587 DEBUG ((DEBUG_INFO
, "mMmramRangeCount - 0x%x\n", mMmramRangeCount
));
588 mMmramRanges
= AllocatePool (mMmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
));
589 DEBUG ((DEBUG_INFO
, "mMmramRanges - 0x%x\n", mMmramRanges
));
590 ASSERT (mMmramRanges
!= NULL
);
591 CopyMem (mMmramRanges
, (VOID
*)(UINTN
)MmramRanges
, mMmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
));
594 // Get Boot Firmware Volume address from the BFV Hob
596 BfvHob
= GetFirstHob (EFI_HOB_TYPE_FV
);
597 if (BfvHob
!= NULL
) {
598 DEBUG ((DEBUG_INFO
, "BFV address - 0x%x\n", BfvHob
->BaseAddress
));
599 DEBUG ((DEBUG_INFO
, "BFV size - 0x%x\n", BfvHob
->Length
));
600 gMmCorePrivate
->StandaloneBfvAddress
= BfvHob
->BaseAddress
;
603 gMmCorePrivate
->Mmst
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&gMmCoreMmst
;
604 gMmCorePrivate
->MmEntryPoint
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)MmEntryPoint
;
607 // No need to initialize memory service.
608 // It is done in the constructor of StandaloneMmCoreMemoryAllocationLib(),
609 // so that the library linked with StandaloneMmCore can use AllocatePool() in
612 DEBUG ((DEBUG_INFO
, "MmInstallConfigurationTable For HobList\n"));
616 HobSize
= GetHobListSize (HobStart
);
617 DEBUG ((DEBUG_INFO
, "HobSize - 0x%x\n", HobSize
));
618 MmHobStart
= AllocatePool (HobSize
);
619 DEBUG ((DEBUG_INFO
, "MmHobStart - 0x%x\n", MmHobStart
));
620 ASSERT (MmHobStart
!= NULL
);
621 CopyMem (MmHobStart
, HobStart
, HobSize
);
622 Status
= MmInstallConfigurationTable (&gMmCoreMmst
, &gEfiHobListGuid
, MmHobStart
, HobSize
);
623 ASSERT_EFI_ERROR (Status
);
626 // Register notification for EFI_MM_CONFIGURATION_PROTOCOL registration and
627 // use it to register the MM Foundation entrypoint
629 DEBUG ((DEBUG_INFO
, "MmRegisterProtocolNotify - MmConfigurationMmProtocol\n"));
630 Status
= MmRegisterProtocolNotify (
631 &gEfiMmConfigurationProtocolGuid
,
632 MmConfigurationMmNotify
,
635 ASSERT_EFI_ERROR (Status
);
638 // Dispatch standalone BFV
640 DEBUG ((DEBUG_INFO
, "Mm Dispatch StandaloneBfvAddress - 0x%08x\n", gMmCorePrivate
->StandaloneBfvAddress
));
641 if (gMmCorePrivate
->StandaloneBfvAddress
!= 0) {
642 MmCoreFfsFindMmDriver ((EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)gMmCorePrivate
->StandaloneBfvAddress
);
647 // Register all handlers in the core table
649 for (Index
= 0; mMmCoreMmiHandlers
[Index
].HandlerType
!= NULL
; Index
++) {
650 Status
= MmiHandlerRegister (
651 mMmCoreMmiHandlers
[Index
].Handler
,
652 mMmCoreMmiHandlers
[Index
].HandlerType
,
653 &mMmCoreMmiHandlers
[Index
].DispatchHandle
655 DEBUG ((DEBUG_INFO
, "MmiHandlerRegister - GUID %g - Status %d\n", mMmCoreMmiHandlers
[Index
].HandlerType
, Status
));
658 DEBUG ((DEBUG_INFO
, "MmMain Done!\n"));