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 { MmReadyToLockHandler
, &gEfiDxeMmReadyToLockProtocolGuid
, NULL
, TRUE
},
103 { MmEndOfDxeHandler
, &gEfiEndOfDxeEventGroupGuid
, NULL
, FALSE
},
104 { MmLegacyBootHandler
, &gEfiEventLegacyBootGuid
, NULL
, FALSE
},
105 { MmExitBootServiceHandler
,&gEfiEventExitBootServicesGuid
, NULL
, FALSE
},
106 { MmReadyToBootHandler
, &gEfiEventReadyToBootGuid
, NULL
, FALSE
},
107 { NULL
, NULL
, NULL
, FALSE
},
110 EFI_SYSTEM_TABLE
*mEfiSystemTable
;
111 UINTN mMmramRangeCount
;
112 EFI_MMRAM_DESCRIPTOR
*mMmramRanges
;
115 Place holder function until all the MM System Table Service are available.
117 Note: This function is only used by MMRAM invocation. It is never used by DXE invocation.
119 @param Arg1 Undefined
120 @param Arg2 Undefined
121 @param Arg3 Undefined
122 @param Arg4 Undefined
123 @param Arg5 Undefined
125 @return EFI_NOT_AVAILABLE_YET
130 MmEfiNotAvailableYetArg5 (
139 // This function should never be executed. If it does, then the architectural protocols
140 // have not been designed correctly.
142 return EFI_NOT_AVAILABLE_YET
;
146 Software MMI handler that is called when a Legacy Boot event is signaled. The MM
147 Core uses this signal to know that a Legacy Boot has been performed and that
148 gMmCorePrivate that is shared between the UEFI and MM execution environments can
149 not be accessed from MM anymore since that structure is considered free memory by
152 @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
153 @param Context Points to an optional handler context which was specified when the handler was registered.
154 @param CommBuffer A pointer to a collection of data in memory that will
155 be conveyed from a non-MM environment into an MM environment.
156 @param CommBufferSize The size of the CommBuffer.
163 MmLegacyBootHandler (
164 IN EFI_HANDLE DispatchHandle
,
165 IN CONST VOID
*Context
, OPTIONAL
166 IN OUT VOID
*CommBuffer
, OPTIONAL
167 IN OUT UINTN
*CommBufferSize OPTIONAL
171 EFI_STATUS Status
= EFI_SUCCESS
;
173 if (!mInLegacyBoot
) {
175 Status
= MmInstallProtocolInterface (
177 &gEfiEventLegacyBootGuid
,
178 EFI_NATIVE_INTERFACE
,
182 mInLegacyBoot
= TRUE
;
187 Software MMI handler that is called when a ExitBoot Service event is signaled.
189 @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
190 @param Context Points to an optional handler context which was specified when the handler was registered.
191 @param CommBuffer A pointer to a collection of data in memory that will
192 be conveyed from a non-MM environment into an MM environment.
193 @param CommBufferSize The size of the CommBuffer.
200 MmExitBootServiceHandler (
201 IN EFI_HANDLE DispatchHandle
,
202 IN CONST VOID
*Context
, OPTIONAL
203 IN OUT VOID
*CommBuffer
, OPTIONAL
204 IN OUT UINTN
*CommBufferSize OPTIONAL
208 EFI_STATUS Status
= EFI_SUCCESS
;
209 STATIC BOOLEAN mInExitBootServices
= FALSE
;
211 if (!mInExitBootServices
) {
213 Status
= MmInstallProtocolInterface (
215 &gEfiEventExitBootServicesGuid
,
216 EFI_NATIVE_INTERFACE
,
220 mInExitBootServices
= TRUE
;
225 Software MMI handler that is called when a ExitBoot Service event is signaled.
227 @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
228 @param Context Points to an optional handler context which was specified when the handler was registered.
229 @param CommBuffer A pointer to a collection of data in memory that will
230 be conveyed from a non-MM environment into an MM environment.
231 @param CommBufferSize The size of the CommBuffer.
238 MmReadyToBootHandler (
239 IN EFI_HANDLE DispatchHandle
,
240 IN CONST VOID
*Context
, OPTIONAL
241 IN OUT VOID
*CommBuffer
, OPTIONAL
242 IN OUT UINTN
*CommBufferSize OPTIONAL
246 EFI_STATUS Status
= EFI_SUCCESS
;
247 STATIC BOOLEAN mInReadyToBoot
= FALSE
;
249 if (!mInReadyToBoot
) {
251 Status
= MmInstallProtocolInterface (
253 &gEfiEventReadyToBootGuid
,
254 EFI_NATIVE_INTERFACE
,
258 mInReadyToBoot
= TRUE
;
263 Software MMI handler that is called when the DxeMmReadyToLock protocol is added
264 or if gEfiEventReadyToBootGuid is signaled. This function unregisters the
265 Software SMIs that are nor required after MMRAM is locked and installs the
266 MM Ready To Lock Protocol so MM Drivers are informed that MMRAM is about
269 @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
270 @param Context Points to an optional handler context which was specified when the handler was registered.
271 @param CommBuffer A pointer to a collection of data in memory that will
272 be conveyed from a non-MM environment into an MM environment.
273 @param CommBufferSize The size of the CommBuffer.
280 MmReadyToLockHandler (
281 IN EFI_HANDLE DispatchHandle
,
282 IN CONST VOID
*Context
, OPTIONAL
283 IN OUT VOID
*CommBuffer
, OPTIONAL
284 IN OUT UINTN
*CommBufferSize OPTIONAL
291 DEBUG ((DEBUG_INFO
, "MmReadyToLockHandler\n"));
294 // Unregister MMI Handlers that are no longer required after the MM driver dispatch is stopped
296 for (Index
= 0; mMmCoreMmiHandlers
[Index
].HandlerType
!= NULL
; Index
++) {
297 if (mMmCoreMmiHandlers
[Index
].UnRegister
) {
298 MmiHandlerUnRegister (mMmCoreMmiHandlers
[Index
].DispatchHandle
);
303 // Install MM Ready to lock protocol
306 Status
= MmInstallProtocolInterface (
308 &gEfiMmReadyToLockProtocolGuid
,
309 EFI_NATIVE_INTERFACE
,
314 // Make sure MM CPU I/O 2 Protocol has been installed into the handle database
316 //Status = MmLocateProtocol (&EFI_MM_CPU_IO_PROTOCOL_GUID, NULL, &Interface);
319 // Print a message on a debug build if the MM CPU I/O 2 Protocol is not installed
321 //if (EFI_ERROR (Status)) {
322 //DEBUG ((DEBUG_ERROR, "\nSMM: SmmCpuIo Arch Protocol not present!!\n"));
327 // Assert if the CPU I/O 2 Protocol is not installed
329 //ASSERT_EFI_ERROR (Status);
332 // Display any drivers that were not dispatched because dependency expression
333 // evaluated to false if this is a debug build
335 //MmDisplayDiscoveredNotDispatched ();
341 Software MMI handler that is called when the EndOfDxe event is signaled.
342 This function installs the MM EndOfDxe Protocol so MM Drivers are informed that
343 platform code will invoke 3rd part code.
345 @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
346 @param Context Points to an optional handler context which was specified when the handler was registered.
347 @param CommBuffer A pointer to a collection of data in memory that will
348 be conveyed from a non-MM environment into an MM environment.
349 @param CommBufferSize The size of the CommBuffer.
357 IN EFI_HANDLE DispatchHandle
,
358 IN CONST VOID
*Context
, OPTIONAL
359 IN OUT VOID
*CommBuffer
, OPTIONAL
360 IN OUT UINTN
*CommBufferSize OPTIONAL
366 DEBUG ((DEBUG_INFO
, "MmEndOfDxeHandler\n"));
368 // Install MM EndOfDxe protocol
371 Status
= MmInstallProtocolInterface (
373 &gEfiMmEndOfDxeProtocolGuid
,
374 EFI_NATIVE_INTERFACE
,
383 The main entry point to MM Foundation.
385 Note: This function is only used by MMRAM invocation. It is never used by DXE invocation.
387 @param MmEntryContext Processor information and functionality
388 needed by MM Foundation.
394 IN CONST EFI_MM_ENTRY_CONTEXT
*MmEntryContext
398 EFI_MM_COMMUNICATE_HEADER
*CommunicateHeader
;
399 BOOLEAN InLegacyBoot
;
401 DEBUG ((DEBUG_INFO
, "MmEntryPoint ...\n"));
404 // Update MMST using the context
406 CopyMem (&gMmCoreMmst
.MmStartupThisAp
, MmEntryContext
, sizeof (EFI_MM_ENTRY_CONTEXT
));
409 // Call platform hook before Mm Dispatch
411 //PlatformHookBeforeMmDispatch ();
414 // If a legacy boot has occured, then make sure gMmCorePrivate is not accessed
416 InLegacyBoot
= mInLegacyBoot
;
419 // TBD: Mark the InMm flag as TRUE
421 gMmCorePrivate
->InMm
= TRUE
;
424 // Check to see if this is a Synchronous MMI sent through the MM Communication
425 // Protocol or an Asynchronous MMI
427 if (gMmCorePrivate
->CommunicationBuffer
!= 0) {
429 // Synchronous MMI for MM Core or request from Communicate protocol
431 if (!MmIsBufferOutsideMmValid ((UINTN
)gMmCorePrivate
->CommunicationBuffer
, gMmCorePrivate
->BufferSize
)) {
433 // If CommunicationBuffer is not in valid address scope, return EFI_INVALID_PARAMETER
435 gMmCorePrivate
->CommunicationBuffer
= 0;
436 gMmCorePrivate
->ReturnStatus
= EFI_INVALID_PARAMETER
;
438 CommunicateHeader
= (EFI_MM_COMMUNICATE_HEADER
*)(UINTN
)gMmCorePrivate
->CommunicationBuffer
;
439 gMmCorePrivate
->BufferSize
-= OFFSET_OF (EFI_MM_COMMUNICATE_HEADER
, Data
);
441 &CommunicateHeader
->HeaderGuid
,
443 CommunicateHeader
->Data
,
444 (UINTN
*)&gMmCorePrivate
->BufferSize
447 // Update CommunicationBuffer, BufferSize and ReturnStatus
448 // Communicate service finished, reset the pointer to CommBuffer to NULL
450 gMmCorePrivate
->BufferSize
+= OFFSET_OF (EFI_MM_COMMUNICATE_HEADER
, Data
);
451 gMmCorePrivate
->CommunicationBuffer
= 0;
452 gMmCorePrivate
->ReturnStatus
= (Status
== EFI_SUCCESS
) ? EFI_SUCCESS
: EFI_NOT_FOUND
;
458 // Process Asynchronous MMI sources
460 MmiManage (NULL
, NULL
, NULL
, NULL
);
463 // TBD: Do not use private data structure ?
467 // If a legacy boot has occured, then make sure gMmCorePrivate is not accessed
471 // Clear the InMm flag as we are going to leave MM
473 gMmCorePrivate
->InMm
= FALSE
;
476 DEBUG ((DEBUG_INFO
, "MmEntryPoint Done\n"));
481 MmConfigurationMmNotify (
482 IN CONST EFI_GUID
*Protocol
,
488 EFI_MM_CONFIGURATION_PROTOCOL
*MmConfiguration
;
490 DEBUG ((DEBUG_INFO
, "MmConfigurationMmNotify(%g) - %x\n", Protocol
, Interface
));
492 MmConfiguration
= Interface
;
495 // Register the MM Entry Point provided by the MM Core with the MM COnfiguration protocol
497 Status
= MmConfiguration
->RegisterMmEntry (MmConfiguration
, (EFI_MM_ENTRY_POINT
)(UINTN
)gMmCorePrivate
->MmEntryPoint
);
498 ASSERT_EFI_ERROR (Status
);
501 // Set flag to indicate that the MM Entry Point has been registered which
502 // means that MMIs are now fully operational.
504 gMmCorePrivate
->MmEntryPointRegistered
= TRUE
;
507 // Print debug message showing MM Core entry point address.
509 DEBUG ((DEBUG_INFO
, "MM Core registered MM Entry Point address %p\n", (VOID
*)(UINTN
)gMmCorePrivate
->MmEntryPoint
));
518 EFI_PEI_HOB_POINTERS Hob
;
520 ASSERT (HobStart
!= NULL
);
522 Hob
.Raw
= (UINT8
*) HobStart
;
523 while (!END_OF_HOB_LIST (Hob
)) {
524 Hob
.Raw
= GET_NEXT_HOB (Hob
);
527 // Need plus END_OF_HOB_LIST
529 return (UINTN
)Hob
.Raw
- (UINTN
)HobStart
+ sizeof (EFI_HOB_GENERIC_HEADER
);
533 The Entry Point for MM Core
535 Install DXE Protocols and reload MM Core into MMRAM and register MM Core
536 EntryPoint on the MMI vector.
538 Note: This function is called for both DXE invocation and MMRAM invocation.
540 @param ImageHandle The firmware allocated handle for the EFI image.
541 @param SystemTable A pointer to the EFI System Table.
543 @retval EFI_SUCCESS The entry point is executed successfully.
544 @retval Other Some error occurred when executing this entry point.
558 EFI_HOB_GUID_TYPE
*GuidHob
;
559 MM_CORE_DATA_HOB_DATA
*DataInHob
;
560 EFI_HOB_GUID_TYPE
*MmramRangesHob
;
561 EFI_MMRAM_HOB_DESCRIPTOR_BLOCK
*MmramRangesHobData
;
562 EFI_MMRAM_DESCRIPTOR
*MmramRanges
;
563 UINT32 MmramRangeCount
;
564 EFI_HOB_FIRMWARE_VOLUME
*BfvHob
;
566 ProcessLibraryConstructorList (HobStart
, &gMmCoreMmst
);
568 DEBUG ((DEBUG_INFO
, "MmMain - 0x%x\n", HobStart
));
571 // Determine if the caller has passed a reference to a MM_CORE_PRIVATE_DATA
572 // structure in the Hoblist. This choice will govern how boot information is
575 GuidHob
= GetNextGuidHob (&gMmCoreDataHobGuid
, HobStart
);
576 if (GuidHob
== NULL
) {
578 // Allocate and zero memory for a MM_CORE_PRIVATE_DATA table and then
581 gMmCorePrivate
= (MM_CORE_PRIVATE_DATA
*) AllocateRuntimePages(EFI_SIZE_TO_PAGES(sizeof (MM_CORE_PRIVATE_DATA
)));
582 SetMem ((VOID
*)(UINTN
)gMmCorePrivate
, sizeof (MM_CORE_PRIVATE_DATA
), 0);
583 gMmCorePrivate
->Signature
= MM_CORE_PRIVATE_DATA_SIGNATURE
;
584 gMmCorePrivate
->MmEntryPointRegistered
= FALSE
;
585 gMmCorePrivate
->InMm
= FALSE
;
586 gMmCorePrivate
->ReturnStatus
= EFI_SUCCESS
;
589 // Extract the MMRAM ranges from the MMRAM descriptor HOB
591 MmramRangesHob
= GetNextGuidHob (&gEfiMmPeiMmramMemoryReserveGuid
, HobStart
);
592 if (MmramRangesHob
== NULL
)
593 return EFI_UNSUPPORTED
;
595 MmramRangesHobData
= GET_GUID_HOB_DATA (MmramRangesHob
);
596 ASSERT (MmramRangesHobData
!= NULL
);
597 MmramRanges
= MmramRangesHobData
->Descriptor
;
598 MmramRangeCount
= MmramRangesHobData
->NumberOfMmReservedRegions
;
599 ASSERT (MmramRanges
);
600 ASSERT (MmramRangeCount
);
603 // Copy the MMRAM ranges into MM_CORE_PRIVATE_DATA table just in case any
604 // code relies on them being present there
606 gMmCorePrivate
->MmramRangeCount
= MmramRangeCount
;
607 gMmCorePrivate
->MmramRanges
=
608 (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (MmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
));
609 ASSERT (gMmCorePrivate
->MmramRanges
!= 0);
611 (VOID
*)(UINTN
)gMmCorePrivate
->MmramRanges
,
613 MmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
)
616 DataInHob
= GET_GUID_HOB_DATA (GuidHob
);
617 gMmCorePrivate
= (MM_CORE_PRIVATE_DATA
*)(UINTN
)DataInHob
->Address
;
618 MmramRanges
= (EFI_MMRAM_DESCRIPTOR
*)(UINTN
)gMmCorePrivate
->MmramRanges
;
619 MmramRangeCount
= gMmCorePrivate
->MmramRangeCount
;
623 // Print the MMRAM ranges passed by the caller
625 DEBUG ((DEBUG_INFO
, "MmramRangeCount - 0x%x\n", MmramRangeCount
));
626 for (Index
= 0; Index
< MmramRangeCount
; Index
++) {
627 DEBUG ((DEBUG_INFO
, "MmramRanges[%d]: 0x%016lx - 0x%lx\n", Index
,
628 MmramRanges
[Index
].CpuStart
,
629 MmramRanges
[Index
].PhysicalSize
));
633 // Copy the MMRAM ranges into private MMRAM
635 mMmramRangeCount
= MmramRangeCount
;
636 DEBUG ((DEBUG_INFO
, "mMmramRangeCount - 0x%x\n", mMmramRangeCount
));
637 mMmramRanges
= AllocatePool (mMmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
));
638 DEBUG ((DEBUG_INFO
, "mMmramRanges - 0x%x\n", mMmramRanges
));
639 ASSERT (mMmramRanges
!= NULL
);
640 CopyMem (mMmramRanges
, (VOID
*)(UINTN
)MmramRanges
, mMmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
));
643 // Get Boot Firmware Volume address from the BFV Hob
645 BfvHob
= GetFirstHob (EFI_HOB_TYPE_FV
);
646 if (BfvHob
!= NULL
) {
647 DEBUG ((DEBUG_INFO
, "BFV address - 0x%x\n", BfvHob
->BaseAddress
));
648 DEBUG ((DEBUG_INFO
, "BFV size - 0x%x\n", BfvHob
->Length
));
649 gMmCorePrivate
->StandaloneBfvAddress
= BfvHob
->BaseAddress
;
652 gMmCorePrivate
->Mmst
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&gMmCoreMmst
;
653 gMmCorePrivate
->MmEntryPoint
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)MmEntryPoint
;
656 // No need to initialize memory service.
657 // It is done in constructor of StandaloneMmCoreMemoryAllocationLib(),
658 // so that the library linked with StandaloneMmCore can use AllocatePool() in constuctor.
661 DEBUG ((DEBUG_INFO
, "MmInstallConfigurationTable For HobList\n"));
665 HobSize
= GetHobListSize (HobStart
);
666 DEBUG ((DEBUG_INFO
, "HobSize - 0x%x\n", HobSize
));
667 MmHobStart
= AllocatePool (HobSize
);
668 DEBUG ((DEBUG_INFO
, "MmHobStart - 0x%x\n", MmHobStart
));
669 ASSERT (MmHobStart
!= NULL
);
670 CopyMem (MmHobStart
, HobStart
, HobSize
);
671 Status
= MmInstallConfigurationTable (&gMmCoreMmst
, &gEfiHobListGuid
, MmHobStart
, HobSize
);
672 ASSERT_EFI_ERROR (Status
);
675 // Register notification for EFI_MM_CONFIGURATION_PROTOCOL registration and
676 // use it to register the MM Foundation entrypoint
678 DEBUG ((DEBUG_INFO
, "MmRegisterProtocolNotify - MmConfigurationMmProtocol\n"));
679 Status
= MmRegisterProtocolNotify (
680 &gEfiMmConfigurationProtocolGuid
,
681 MmConfigurationMmNotify
,
684 ASSERT_EFI_ERROR (Status
);
687 // Dispatch standalone BFV
689 DEBUG ((DEBUG_INFO
, "Mm Dispatch StandaloneBfvAddress - 0x%08x\n", gMmCorePrivate
->StandaloneBfvAddress
));
690 if (gMmCorePrivate
->StandaloneBfvAddress
!= 0) {
691 MmCoreFfsFindMmDriver ((EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)gMmCorePrivate
->StandaloneBfvAddress
);
696 // Register all handlers in the core table
698 for (Index
= 0; mMmCoreMmiHandlers
[Index
].HandlerType
!= NULL
; Index
++) {
699 Status
= MmiHandlerRegister (
700 mMmCoreMmiHandlers
[Index
].Handler
,
701 mMmCoreMmiHandlers
[Index
].HandlerType
,
702 &mMmCoreMmiHandlers
[Index
].DispatchHandle
704 DEBUG ((DEBUG_INFO
, "MmiHandlerRegister - GUID %g - Status %d\n", mMmCoreMmiHandlers
[Index
].HandlerType
, Status
));
707 DEBUG ((DEBUG_INFO
, "MmMain Done!\n"));