2 MM Core Main Entry Point
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
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.
16 #include "StandaloneMmCore.h"
19 MmCoreFfsFindMmDriver (
20 IN EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
29 // Globals used to initialize the protocol
31 EFI_HANDLE mMmCpuHandle
= NULL
;
34 // Physical pointer to private structure shared between MM IPL and the MM Core
36 MM_CORE_PRIVATE_DATA
*gMmCorePrivate
;
39 // MM Core global variable for MM System Table. Only accessed as a physical structure in MMRAM.
41 EFI_MM_SYSTEM_TABLE gMmCoreMmst
= {
43 // The table header for the MMST.
46 EFI_MM_SYSTEM_TABLE_REVISION
,
47 sizeof (gMmCoreMmst
.Hdr
)
53 // MmInstallConfigurationTable
54 MmInstallConfigurationTable
,
58 (EFI_MM_CPU_IO
) MmEfiNotAvailableYetArg5
, // MmMemRead
59 (EFI_MM_CPU_IO
) MmEfiNotAvailableYetArg5
// MmMemWrite
62 (EFI_MM_CPU_IO
) MmEfiNotAvailableYetArg5
, // MmIoRead
63 (EFI_MM_CPU_IO
) MmEfiNotAvailableYetArg5
// MmIoWrite
66 // Runtime memory services
72 NULL
, // MmStartupThisAp
73 0, // CurrentlyExecutingCpu
75 NULL
, // CpuSaveStateSize
77 0, // NumberOfTableEntries
78 NULL
, // MmConfigurationTable
79 MmInstallProtocolInterface
,
80 MmUninstallProtocolInterface
,
82 MmRegisterProtocolNotify
,
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.
96 BOOLEAN mInLegacyBoot
= FALSE
;
99 // Table of MMI Handlers that are registered by the MM Core when it is initialized
101 MM_CORE_MMI_HANDLERS mMmCoreMmiHandlers
[] = {
102 { MmFvDispatchHandler
, &gMmFvDispatchGuid
, NULL
, TRUE
},
103 { MmReadyToLockHandler
, &gEfiDxeMmReadyToLockProtocolGuid
, NULL
, TRUE
},
104 { MmEndOfDxeHandler
, &gEfiEndOfDxeEventGroupGuid
, NULL
, FALSE
},
105 { MmLegacyBootHandler
, &gEfiEventLegacyBootGuid
, NULL
, FALSE
},
106 { MmExitBootServiceHandler
,&gEfiEventExitBootServicesGuid
, NULL
, FALSE
},
107 { MmReadyToBootHandler
, &gEfiEventReadyToBootGuid
, NULL
, FALSE
},
108 { NULL
, NULL
, NULL
, FALSE
},
111 EFI_SYSTEM_TABLE
*mEfiSystemTable
;
112 UINTN mMmramRangeCount
;
113 EFI_MMRAM_DESCRIPTOR
*mMmramRanges
;
116 Place holder function until all the MM System Table Service are available.
118 Note: This function is only used by MMRAM invocation. It is never used by DXE invocation.
120 @param Arg1 Undefined
121 @param Arg2 Undefined
122 @param Arg3 Undefined
123 @param Arg4 Undefined
124 @param Arg5 Undefined
126 @return EFI_NOT_AVAILABLE_YET
131 MmEfiNotAvailableYetArg5 (
140 // This function should never be executed. If it does, then the architectural protocols
141 // have not been designed correctly.
143 return EFI_NOT_AVAILABLE_YET
;
147 Software MMI handler that is called when a Legacy Boot event is signaled. The MM
148 Core uses this signal to know that a Legacy Boot has been performed and that
149 gMmCorePrivate that is shared between the UEFI and MM execution environments can
150 not be accessed from MM anymore since that structure is considered free memory by
153 @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
154 @param Context Points to an optional handler context which was specified when the handler was registered.
155 @param CommBuffer A pointer to a collection of data in memory that will
156 be conveyed from a non-MM environment into an MM environment.
157 @param CommBufferSize The size of the CommBuffer.
164 MmLegacyBootHandler (
165 IN EFI_HANDLE DispatchHandle
,
166 IN CONST VOID
*Context
, OPTIONAL
167 IN OUT VOID
*CommBuffer
, OPTIONAL
168 IN OUT UINTN
*CommBufferSize OPTIONAL
172 EFI_STATUS Status
= EFI_SUCCESS
;
174 if (!mInLegacyBoot
) {
176 Status
= MmInstallProtocolInterface (
178 &gEfiEventLegacyBootGuid
,
179 EFI_NATIVE_INTERFACE
,
183 mInLegacyBoot
= TRUE
;
188 Software MMI handler that is called when a ExitBoot Service event is signaled.
190 @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
191 @param Context Points to an optional handler context which was specified when the handler was registered.
192 @param CommBuffer A pointer to a collection of data in memory that will
193 be conveyed from a non-MM environment into an MM environment.
194 @param CommBufferSize The size of the CommBuffer.
201 MmExitBootServiceHandler (
202 IN EFI_HANDLE DispatchHandle
,
203 IN CONST VOID
*Context
, OPTIONAL
204 IN OUT VOID
*CommBuffer
, OPTIONAL
205 IN OUT UINTN
*CommBufferSize OPTIONAL
209 EFI_STATUS Status
= EFI_SUCCESS
;
210 STATIC BOOLEAN mInExitBootServices
= FALSE
;
212 if (!mInExitBootServices
) {
214 Status
= MmInstallProtocolInterface (
216 &gEfiEventExitBootServicesGuid
,
217 EFI_NATIVE_INTERFACE
,
221 mInExitBootServices
= TRUE
;
226 Software MMI handler that is called when a ExitBoot Service event is signaled.
228 @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
229 @param Context Points to an optional handler context which was specified when the handler was registered.
230 @param CommBuffer A pointer to a collection of data in memory that will
231 be conveyed from a non-MM environment into an MM environment.
232 @param CommBufferSize The size of the CommBuffer.
239 MmReadyToBootHandler (
240 IN EFI_HANDLE DispatchHandle
,
241 IN CONST VOID
*Context
, OPTIONAL
242 IN OUT VOID
*CommBuffer
, OPTIONAL
243 IN OUT UINTN
*CommBufferSize OPTIONAL
247 EFI_STATUS Status
= EFI_SUCCESS
;
248 STATIC BOOLEAN mInReadyToBoot
= FALSE
;
250 if (!mInReadyToBoot
) {
252 Status
= MmInstallProtocolInterface (
254 &gEfiEventReadyToBootGuid
,
255 EFI_NATIVE_INTERFACE
,
259 mInReadyToBoot
= TRUE
;
264 Software MMI handler that is called when the DxeMmReadyToLock protocol is added
265 or if gEfiEventReadyToBootGuid is signaled. This function unregisters the
266 Software SMIs that are nor required after MMRAM is locked and installs the
267 MM Ready To Lock Protocol so MM Drivers are informed that MMRAM is about
270 @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
271 @param Context Points to an optional handler context which was specified when the handler was registered.
272 @param CommBuffer A pointer to a collection of data in memory that will
273 be conveyed from a non-MM environment into an MM environment.
274 @param CommBufferSize The size of the CommBuffer.
281 MmReadyToLockHandler (
282 IN EFI_HANDLE DispatchHandle
,
283 IN CONST VOID
*Context
, OPTIONAL
284 IN OUT VOID
*CommBuffer
, OPTIONAL
285 IN OUT UINTN
*CommBufferSize OPTIONAL
292 DEBUG ((DEBUG_INFO
, "MmReadyToLockHandler\n"));
295 // Unregister MMI Handlers that are no longer required after the MM driver dispatch is stopped
297 for (Index
= 0; mMmCoreMmiHandlers
[Index
].HandlerType
!= NULL
; Index
++) {
298 if (mMmCoreMmiHandlers
[Index
].UnRegister
) {
299 MmiHandlerUnRegister (mMmCoreMmiHandlers
[Index
].DispatchHandle
);
304 // Install MM Ready to lock protocol
307 Status
= MmInstallProtocolInterface (
309 &gEfiMmReadyToLockProtocolGuid
,
310 EFI_NATIVE_INTERFACE
,
315 // Make sure MM CPU I/O 2 Protocol has been installed into the handle database
317 //Status = MmLocateProtocol (&EFI_MM_CPU_IO_PROTOCOL_GUID, NULL, &Interface);
320 // Print a message on a debug build if the MM CPU I/O 2 Protocol is not installed
322 //if (EFI_ERROR (Status)) {
323 //DEBUG ((DEBUG_ERROR, "\nSMM: SmmCpuIo Arch Protocol not present!!\n"));
328 // Assert if the CPU I/O 2 Protocol is not installed
330 //ASSERT_EFI_ERROR (Status);
333 // Display any drivers that were not dispatched because dependency expression
334 // evaluated to false if this is a debug build
336 //MmDisplayDiscoveredNotDispatched ();
342 Software MMI handler that is called when the EndOfDxe event is signaled.
343 This function installs the MM EndOfDxe Protocol so MM Drivers are informed that
344 platform code will invoke 3rd part code.
346 @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
347 @param Context Points to an optional handler context which was specified when the handler was registered.
348 @param CommBuffer A pointer to a collection of data in memory that will
349 be conveyed from a non-MM environment into an MM environment.
350 @param CommBufferSize The size of the CommBuffer.
358 IN EFI_HANDLE DispatchHandle
,
359 IN CONST VOID
*Context
, OPTIONAL
360 IN OUT VOID
*CommBuffer
, OPTIONAL
361 IN OUT UINTN
*CommBufferSize OPTIONAL
367 DEBUG ((DEBUG_INFO
, "MmEndOfDxeHandler\n"));
369 // Install MM EndOfDxe protocol
372 Status
= MmInstallProtocolInterface (
374 &gEfiMmEndOfDxeProtocolGuid
,
375 EFI_NATIVE_INTERFACE
,
384 The main entry point to MM Foundation.
386 Note: This function is only used by MMRAM invocation. It is never used by DXE invocation.
388 @param MmEntryContext Processor information and functionality
389 needed by MM Foundation.
395 IN CONST EFI_MM_ENTRY_CONTEXT
*MmEntryContext
399 EFI_MM_COMMUNICATE_HEADER
*CommunicateHeader
;
400 BOOLEAN InLegacyBoot
;
402 DEBUG ((DEBUG_INFO
, "MmEntryPoint ...\n"));
405 // Update MMST using the context
407 CopyMem (&gMmCoreMmst
.MmStartupThisAp
, MmEntryContext
, sizeof (EFI_MM_ENTRY_CONTEXT
));
410 // Call platform hook before Mm Dispatch
412 //PlatformHookBeforeMmDispatch ();
415 // If a legacy boot has occured, then make sure gMmCorePrivate is not accessed
417 InLegacyBoot
= mInLegacyBoot
;
420 // TBD: Mark the InMm flag as TRUE
422 gMmCorePrivate
->InMm
= TRUE
;
425 // Check to see if this is a Synchronous MMI sent through the MM Communication
426 // Protocol or an Asynchronous MMI
428 if (gMmCorePrivate
->CommunicationBuffer
!= 0) {
430 // Synchronous MMI for MM Core or request from Communicate protocol
432 if (!MmIsBufferOutsideMmValid ((UINTN
)gMmCorePrivate
->CommunicationBuffer
, gMmCorePrivate
->BufferSize
)) {
434 // If CommunicationBuffer is not in valid address scope, return EFI_INVALID_PARAMETER
436 gMmCorePrivate
->CommunicationBuffer
= 0;
437 gMmCorePrivate
->ReturnStatus
= EFI_INVALID_PARAMETER
;
439 CommunicateHeader
= (EFI_MM_COMMUNICATE_HEADER
*)(UINTN
)gMmCorePrivate
->CommunicationBuffer
;
440 gMmCorePrivate
->BufferSize
-= OFFSET_OF (EFI_MM_COMMUNICATE_HEADER
, Data
);
442 &CommunicateHeader
->HeaderGuid
,
444 CommunicateHeader
->Data
,
445 (UINTN
*)&gMmCorePrivate
->BufferSize
448 // Update CommunicationBuffer, BufferSize and ReturnStatus
449 // Communicate service finished, reset the pointer to CommBuffer to NULL
451 gMmCorePrivate
->BufferSize
+= OFFSET_OF (EFI_MM_COMMUNICATE_HEADER
, Data
);
452 gMmCorePrivate
->CommunicationBuffer
= 0;
453 gMmCorePrivate
->ReturnStatus
= (Status
== EFI_SUCCESS
) ? EFI_SUCCESS
: EFI_NOT_FOUND
;
459 // Process Asynchronous MMI sources
461 MmiManage (NULL
, NULL
, NULL
, NULL
);
464 // TBD: Do not use private data structure ?
468 // If a legacy boot has occured, then make sure gMmCorePrivate is not accessed
472 // Clear the InMm flag as we are going to leave MM
474 gMmCorePrivate
->InMm
= FALSE
;
477 DEBUG ((DEBUG_INFO
, "MmEntryPoint Done\n"));
482 MmConfigurationMmNotify (
483 IN CONST EFI_GUID
*Protocol
,
489 EFI_MM_CONFIGURATION_PROTOCOL
*MmConfiguration
;
491 DEBUG ((DEBUG_INFO
, "MmConfigurationMmNotify(%g) - %x\n", Protocol
, Interface
));
493 MmConfiguration
= Interface
;
496 // Register the MM Entry Point provided by the MM Core with the MM COnfiguration protocol
498 Status
= MmConfiguration
->RegisterMmEntry (MmConfiguration
, (EFI_MM_ENTRY_POINT
)(UINTN
)gMmCorePrivate
->MmEntryPoint
);
499 ASSERT_EFI_ERROR (Status
);
502 // Set flag to indicate that the MM Entry Point has been registered which
503 // means that MMIs are now fully operational.
505 gMmCorePrivate
->MmEntryPointRegistered
= TRUE
;
508 // Print debug message showing MM Core entry point address.
510 DEBUG ((DEBUG_INFO
, "MM Core registered MM Entry Point address %p\n", (VOID
*)(UINTN
)gMmCorePrivate
->MmEntryPoint
));
519 EFI_PEI_HOB_POINTERS Hob
;
521 ASSERT (HobStart
!= NULL
);
523 Hob
.Raw
= (UINT8
*) HobStart
;
524 while (!END_OF_HOB_LIST (Hob
)) {
525 Hob
.Raw
= GET_NEXT_HOB (Hob
);
528 // Need plus END_OF_HOB_LIST
530 return (UINTN
)Hob
.Raw
- (UINTN
)HobStart
+ sizeof (EFI_HOB_GENERIC_HEADER
);
534 The Entry Point for MM Core
536 Install DXE Protocols and reload MM Core into MMRAM and register MM Core
537 EntryPoint on the MMI vector.
539 Note: This function is called for both DXE invocation and MMRAM invocation.
541 @param ImageHandle The firmware allocated handle for the EFI image.
542 @param SystemTable A pointer to the EFI System Table.
544 @retval EFI_SUCCESS The entry point is executed successfully.
545 @retval Other Some error occurred when executing this entry point.
559 EFI_HOB_GUID_TYPE
*GuidHob
;
560 MM_CORE_DATA_HOB_DATA
*DataInHob
;
561 EFI_HOB_GUID_TYPE
*MmramRangesHob
;
562 EFI_MMRAM_HOB_DESCRIPTOR_BLOCK
*MmramRangesHobData
;
563 EFI_MMRAM_DESCRIPTOR
*MmramRanges
;
564 UINT32 MmramRangeCount
;
565 EFI_HOB_FIRMWARE_VOLUME
*BfvHob
;
567 ProcessLibraryConstructorList (HobStart
, &gMmCoreMmst
);
569 DEBUG ((DEBUG_INFO
, "MmMain - 0x%x\n", HobStart
));
572 // Determine if the caller has passed a reference to a MM_CORE_PRIVATE_DATA
573 // structure in the Hoblist. This choice will govern how boot information is
576 GuidHob
= GetNextGuidHob (&gMmCoreDataHobGuid
, HobStart
);
577 if (GuidHob
== NULL
) {
579 // Allocate and zero memory for a MM_CORE_PRIVATE_DATA table and then
582 gMmCorePrivate
= (MM_CORE_PRIVATE_DATA
*) AllocateRuntimePages(EFI_SIZE_TO_PAGES(sizeof (MM_CORE_PRIVATE_DATA
)));
583 SetMem ((VOID
*)(UINTN
)gMmCorePrivate
, sizeof (MM_CORE_PRIVATE_DATA
), 0);
584 gMmCorePrivate
->Signature
= MM_CORE_PRIVATE_DATA_SIGNATURE
;
585 gMmCorePrivate
->MmEntryPointRegistered
= FALSE
;
586 gMmCorePrivate
->InMm
= FALSE
;
587 gMmCorePrivate
->ReturnStatus
= EFI_SUCCESS
;
590 // Extract the MMRAM ranges from the MMRAM descriptor HOB
592 MmramRangesHob
= GetNextGuidHob (&gEfiMmPeiMmramMemoryReserveGuid
, HobStart
);
593 if (MmramRangesHob
== NULL
)
594 return EFI_UNSUPPORTED
;
596 MmramRangesHobData
= GET_GUID_HOB_DATA (MmramRangesHob
);
597 ASSERT (MmramRangesHobData
!= NULL
);
598 MmramRanges
= MmramRangesHobData
->Descriptor
;
599 MmramRangeCount
= MmramRangesHobData
->NumberOfMmReservedRegions
;
600 ASSERT (MmramRanges
);
601 ASSERT (MmramRangeCount
);
604 // Copy the MMRAM ranges into MM_CORE_PRIVATE_DATA table just in case any
605 // code relies on them being present there
607 gMmCorePrivate
->MmramRangeCount
= MmramRangeCount
;
608 gMmCorePrivate
->MmramRanges
=
609 (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (MmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
));
610 ASSERT (gMmCorePrivate
->MmramRanges
!= 0);
612 (VOID
*)(UINTN
)gMmCorePrivate
->MmramRanges
,
614 MmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
)
617 DataInHob
= GET_GUID_HOB_DATA (GuidHob
);
618 gMmCorePrivate
= (MM_CORE_PRIVATE_DATA
*)(UINTN
)DataInHob
->Address
;
619 MmramRanges
= (EFI_MMRAM_DESCRIPTOR
*)(UINTN
)gMmCorePrivate
->MmramRanges
;
620 MmramRangeCount
= gMmCorePrivate
->MmramRangeCount
;
624 // Print the MMRAM ranges passed by the caller
626 DEBUG ((DEBUG_INFO
, "MmramRangeCount - 0x%x\n", MmramRangeCount
));
627 for (Index
= 0; Index
< MmramRangeCount
; Index
++) {
628 DEBUG ((DEBUG_INFO
, "MmramRanges[%d]: 0x%016lx - 0x%lx\n", Index
,
629 MmramRanges
[Index
].CpuStart
,
630 MmramRanges
[Index
].PhysicalSize
));
634 // Copy the MMRAM ranges into private MMRAM
636 mMmramRangeCount
= MmramRangeCount
;
637 DEBUG ((DEBUG_INFO
, "mMmramRangeCount - 0x%x\n", mMmramRangeCount
));
638 mMmramRanges
= AllocatePool (mMmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
));
639 DEBUG ((DEBUG_INFO
, "mMmramRanges - 0x%x\n", mMmramRanges
));
640 ASSERT (mMmramRanges
!= NULL
);
641 CopyMem (mMmramRanges
, (VOID
*)(UINTN
)MmramRanges
, mMmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
));
644 // Get Boot Firmware Volume address from the BFV Hob
646 BfvHob
= GetFirstHob (EFI_HOB_TYPE_FV
);
647 if (BfvHob
!= NULL
) {
648 DEBUG ((DEBUG_INFO
, "BFV address - 0x%x\n", BfvHob
->BaseAddress
));
649 DEBUG ((DEBUG_INFO
, "BFV size - 0x%x\n", BfvHob
->Length
));
650 gMmCorePrivate
->StandaloneBfvAddress
= BfvHob
->BaseAddress
;
653 gMmCorePrivate
->Mmst
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&gMmCoreMmst
;
654 gMmCorePrivate
->MmEntryPoint
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)MmEntryPoint
;
657 // No need to initialize memory service.
658 // It is done in constructor of StandaloneMmCoreMemoryAllocationLib(),
659 // so that the library linked with StandaloneMmCore can use AllocatePool() in constuctor.
662 DEBUG ((DEBUG_INFO
, "MmInstallConfigurationTable For HobList\n"));
666 HobSize
= GetHobListSize (HobStart
);
667 DEBUG ((DEBUG_INFO
, "HobSize - 0x%x\n", HobSize
));
668 MmHobStart
= AllocatePool (HobSize
);
669 DEBUG ((DEBUG_INFO
, "MmHobStart - 0x%x\n", MmHobStart
));
670 ASSERT (MmHobStart
!= NULL
);
671 CopyMem (MmHobStart
, HobStart
, HobSize
);
672 Status
= MmInstallConfigurationTable (&gMmCoreMmst
, &gEfiHobListGuid
, MmHobStart
, HobSize
);
673 ASSERT_EFI_ERROR (Status
);
676 // Register notification for EFI_MM_CONFIGURATION_PROTOCOL registration and
677 // use it to register the MM Foundation entrypoint
679 DEBUG ((DEBUG_INFO
, "MmRegisterProtocolNotify - MmConfigurationMmProtocol\n"));
680 Status
= MmRegisterProtocolNotify (
681 &gEfiMmConfigurationProtocolGuid
,
682 MmConfigurationMmNotify
,
685 ASSERT_EFI_ERROR (Status
);
688 // Dispatch standalone BFV
690 DEBUG ((DEBUG_INFO
, "Mm Dispatch StandaloneBfvAddress - 0x%08x\n", gMmCorePrivate
->StandaloneBfvAddress
));
691 if (gMmCorePrivate
->StandaloneBfvAddress
!= 0) {
692 MmCoreFfsFindMmDriver ((EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)gMmCorePrivate
->StandaloneBfvAddress
);
697 // Register all handlers in the core table
699 for (Index
= 0; mMmCoreMmiHandlers
[Index
].HandlerType
!= NULL
; Index
++) {
700 Status
= MmiHandlerRegister (
701 mMmCoreMmiHandlers
[Index
].Handler
,
702 mMmCoreMmiHandlers
[Index
].HandlerType
,
703 &mMmCoreMmiHandlers
[Index
].DispatchHandle
705 DEBUG ((DEBUG_INFO
, "MmiHandlerRegister - GUID %g - Status %d\n", mMmCoreMmiHandlers
[Index
].HandlerType
, Status
));
708 DEBUG ((DEBUG_INFO
, "MmMain Done!\n"));