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"));
419 MmConfigurationMmNotify (
420 IN CONST EFI_GUID
*Protocol
,
426 EFI_MM_CONFIGURATION_PROTOCOL
*MmConfiguration
;
428 DEBUG ((DEBUG_INFO
, "MmConfigurationMmNotify(%g) - %x\n", Protocol
, Interface
));
430 MmConfiguration
= Interface
;
433 // Register the MM Entry Point provided by the MM Core with the MM COnfiguration protocol
435 Status
= MmConfiguration
->RegisterMmEntry (MmConfiguration
, (EFI_MM_ENTRY_POINT
)(UINTN
)gMmCorePrivate
->MmEntryPoint
);
436 ASSERT_EFI_ERROR (Status
);
439 // Set flag to indicate that the MM Entry Point has been registered which
440 // means that MMIs are now fully operational.
442 gMmCorePrivate
->MmEntryPointRegistered
= TRUE
;
445 // Print debug message showing MM Core entry point address.
447 DEBUG ((DEBUG_INFO
, "MM Core registered MM Entry Point address %p\n", (VOID
*)(UINTN
)gMmCorePrivate
->MmEntryPoint
));
456 EFI_PEI_HOB_POINTERS Hob
;
458 ASSERT (HobStart
!= NULL
);
460 Hob
.Raw
= (UINT8
*) HobStart
;
461 while (!END_OF_HOB_LIST (Hob
)) {
462 Hob
.Raw
= GET_NEXT_HOB (Hob
);
465 // Need plus END_OF_HOB_LIST
467 return (UINTN
)Hob
.Raw
- (UINTN
)HobStart
+ sizeof (EFI_HOB_GENERIC_HEADER
);
471 The Entry Point for MM Core
473 Install DXE Protocols and reload MM Core into MMRAM and register MM Core
474 EntryPoint on the MMI vector.
476 Note: This function is called for both DXE invocation and MMRAM invocation.
478 @param ImageHandle The firmware allocated handle for the EFI image.
479 @param SystemTable A pointer to the EFI System Table.
481 @retval EFI_SUCCESS The entry point is executed successfully.
482 @retval Other Some error occurred when executing this entry point.
496 EFI_HOB_GUID_TYPE
*GuidHob
;
497 MM_CORE_DATA_HOB_DATA
*DataInHob
;
498 EFI_HOB_GUID_TYPE
*MmramRangesHob
;
499 EFI_MMRAM_HOB_DESCRIPTOR_BLOCK
*MmramRangesHobData
;
500 EFI_MMRAM_DESCRIPTOR
*MmramRanges
;
501 UINT32 MmramRangeCount
;
502 EFI_HOB_FIRMWARE_VOLUME
*BfvHob
;
504 ProcessLibraryConstructorList (HobStart
, &gMmCoreMmst
);
506 DEBUG ((DEBUG_INFO
, "MmMain - 0x%x\n", HobStart
));
509 // Determine if the caller has passed a reference to a MM_CORE_PRIVATE_DATA
510 // structure in the Hoblist. This choice will govern how boot information is
513 GuidHob
= GetNextGuidHob (&gMmCoreDataHobGuid
, HobStart
);
514 if (GuidHob
== NULL
) {
516 // Allocate and zero memory for a MM_CORE_PRIVATE_DATA table and then
519 gMmCorePrivate
= (MM_CORE_PRIVATE_DATA
*) AllocateRuntimePages(EFI_SIZE_TO_PAGES(sizeof (MM_CORE_PRIVATE_DATA
)));
520 SetMem ((VOID
*)(UINTN
)gMmCorePrivate
, sizeof (MM_CORE_PRIVATE_DATA
), 0);
521 gMmCorePrivate
->Signature
= MM_CORE_PRIVATE_DATA_SIGNATURE
;
522 gMmCorePrivate
->MmEntryPointRegistered
= FALSE
;
523 gMmCorePrivate
->InMm
= FALSE
;
524 gMmCorePrivate
->ReturnStatus
= EFI_SUCCESS
;
527 // Extract the MMRAM ranges from the MMRAM descriptor HOB
529 MmramRangesHob
= GetNextGuidHob (&gEfiMmPeiMmramMemoryReserveGuid
, HobStart
);
530 if (MmramRangesHob
== NULL
)
531 return EFI_UNSUPPORTED
;
533 MmramRangesHobData
= GET_GUID_HOB_DATA (MmramRangesHob
);
534 ASSERT (MmramRangesHobData
!= NULL
);
535 MmramRanges
= MmramRangesHobData
->Descriptor
;
536 MmramRangeCount
= MmramRangesHobData
->NumberOfMmReservedRegions
;
537 ASSERT (MmramRanges
);
538 ASSERT (MmramRangeCount
);
541 // Copy the MMRAM ranges into MM_CORE_PRIVATE_DATA table just in case any
542 // code relies on them being present there
544 gMmCorePrivate
->MmramRangeCount
= MmramRangeCount
;
545 gMmCorePrivate
->MmramRanges
=
546 (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (MmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
));
547 ASSERT (gMmCorePrivate
->MmramRanges
!= 0);
549 (VOID
*)(UINTN
)gMmCorePrivate
->MmramRanges
,
551 MmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
)
554 DataInHob
= GET_GUID_HOB_DATA (GuidHob
);
555 gMmCorePrivate
= (MM_CORE_PRIVATE_DATA
*)(UINTN
)DataInHob
->Address
;
556 MmramRanges
= (EFI_MMRAM_DESCRIPTOR
*)(UINTN
)gMmCorePrivate
->MmramRanges
;
557 MmramRangeCount
= gMmCorePrivate
->MmramRangeCount
;
561 // Print the MMRAM ranges passed by the caller
563 DEBUG ((DEBUG_INFO
, "MmramRangeCount - 0x%x\n", MmramRangeCount
));
564 for (Index
= 0; Index
< MmramRangeCount
; Index
++) {
565 DEBUG ((DEBUG_INFO
, "MmramRanges[%d]: 0x%016lx - 0x%lx\n", Index
,
566 MmramRanges
[Index
].CpuStart
,
567 MmramRanges
[Index
].PhysicalSize
));
571 // Copy the MMRAM ranges into private MMRAM
573 mMmramRangeCount
= MmramRangeCount
;
574 DEBUG ((DEBUG_INFO
, "mMmramRangeCount - 0x%x\n", mMmramRangeCount
));
575 mMmramRanges
= AllocatePool (mMmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
));
576 DEBUG ((DEBUG_INFO
, "mMmramRanges - 0x%x\n", mMmramRanges
));
577 ASSERT (mMmramRanges
!= NULL
);
578 CopyMem (mMmramRanges
, (VOID
*)(UINTN
)MmramRanges
, mMmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
));
581 // Get Boot Firmware Volume address from the BFV Hob
583 BfvHob
= GetFirstHob (EFI_HOB_TYPE_FV
);
584 if (BfvHob
!= NULL
) {
585 DEBUG ((DEBUG_INFO
, "BFV address - 0x%x\n", BfvHob
->BaseAddress
));
586 DEBUG ((DEBUG_INFO
, "BFV size - 0x%x\n", BfvHob
->Length
));
587 gMmCorePrivate
->StandaloneBfvAddress
= BfvHob
->BaseAddress
;
590 gMmCorePrivate
->Mmst
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&gMmCoreMmst
;
591 gMmCorePrivate
->MmEntryPoint
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)MmEntryPoint
;
594 // No need to initialize memory service.
595 // It is done in the constructor of StandaloneMmCoreMemoryAllocationLib(),
596 // so that the library linked with StandaloneMmCore can use AllocatePool() in
599 DEBUG ((DEBUG_INFO
, "MmInstallConfigurationTable For HobList\n"));
603 HobSize
= GetHobListSize (HobStart
);
604 DEBUG ((DEBUG_INFO
, "HobSize - 0x%x\n", HobSize
));
605 MmHobStart
= AllocatePool (HobSize
);
606 DEBUG ((DEBUG_INFO
, "MmHobStart - 0x%x\n", MmHobStart
));
607 ASSERT (MmHobStart
!= NULL
);
608 CopyMem (MmHobStart
, HobStart
, HobSize
);
609 Status
= MmInstallConfigurationTable (&gMmCoreMmst
, &gEfiHobListGuid
, MmHobStart
, HobSize
);
610 ASSERT_EFI_ERROR (Status
);
613 // Register notification for EFI_MM_CONFIGURATION_PROTOCOL registration and
614 // use it to register the MM Foundation entrypoint
616 DEBUG ((DEBUG_INFO
, "MmRegisterProtocolNotify - MmConfigurationMmProtocol\n"));
617 Status
= MmRegisterProtocolNotify (
618 &gEfiMmConfigurationProtocolGuid
,
619 MmConfigurationMmNotify
,
622 ASSERT_EFI_ERROR (Status
);
625 // Dispatch standalone BFV
627 DEBUG ((DEBUG_INFO
, "Mm Dispatch StandaloneBfvAddress - 0x%08x\n", gMmCorePrivate
->StandaloneBfvAddress
));
628 if (gMmCorePrivate
->StandaloneBfvAddress
!= 0) {
629 MmCoreFfsFindMmDriver ((EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)gMmCorePrivate
->StandaloneBfvAddress
);
634 // Register all handlers in the core table
636 for (Index
= 0; mMmCoreMmiHandlers
[Index
].HandlerType
!= NULL
; Index
++) {
637 Status
= MmiHandlerRegister (
638 mMmCoreMmiHandlers
[Index
].Handler
,
639 mMmCoreMmiHandlers
[Index
].HandlerType
,
640 &mMmCoreMmiHandlers
[Index
].DispatchHandle
642 DEBUG ((DEBUG_INFO
, "MmiHandlerRegister - GUID %g - Status %d\n", mMmCoreMmiHandlers
[Index
].HandlerType
, Status
));
645 DEBUG ((DEBUG_INFO
, "MmMain Done!\n"));