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 // Table of MMI Handlers that are registered by the MM Core when it is initialized
93 MM_CORE_MMI_HANDLERS mMmCoreMmiHandlers
[] = {
94 { MmReadyToLockHandler
, &gEfiDxeMmReadyToLockProtocolGuid
, NULL
, TRUE
},
95 { MmEndOfDxeHandler
, &gEfiEndOfDxeEventGroupGuid
, NULL
, FALSE
},
96 { MmExitBootServiceHandler
,&gEfiEventExitBootServicesGuid
, NULL
, FALSE
},
97 { MmReadyToBootHandler
, &gEfiEventReadyToBootGuid
, NULL
, FALSE
},
98 { NULL
, NULL
, NULL
, FALSE
},
101 EFI_SYSTEM_TABLE
*mEfiSystemTable
;
102 UINTN mMmramRangeCount
;
103 EFI_MMRAM_DESCRIPTOR
*mMmramRanges
;
106 Place holder function until all the MM System Table Service are available.
108 Note: This function is only used by MMRAM invocation. It is never used by DXE invocation.
110 @param Arg1 Undefined
111 @param Arg2 Undefined
112 @param Arg3 Undefined
113 @param Arg4 Undefined
114 @param Arg5 Undefined
116 @return EFI_NOT_AVAILABLE_YET
121 MmEfiNotAvailableYetArg5 (
130 // This function should never be executed. If it does, then the architectural protocols
131 // have not been designed correctly.
133 return EFI_NOT_AVAILABLE_YET
;
137 Software MMI handler that is called when a ExitBoot Service event is signaled.
139 @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
140 @param Context Points to an optional handler context which was specified when the handler was registered.
141 @param CommBuffer A pointer to a collection of data in memory that will
142 be conveyed from a non-MM environment into an MM environment.
143 @param CommBufferSize The size of the CommBuffer.
150 MmExitBootServiceHandler (
151 IN EFI_HANDLE DispatchHandle
,
152 IN CONST VOID
*Context
, OPTIONAL
153 IN OUT VOID
*CommBuffer
, OPTIONAL
154 IN OUT UINTN
*CommBufferSize OPTIONAL
158 EFI_STATUS Status
= EFI_SUCCESS
;
159 STATIC BOOLEAN mInExitBootServices
= FALSE
;
161 if (!mInExitBootServices
) {
163 Status
= MmInstallProtocolInterface (
165 &gEfiEventExitBootServicesGuid
,
166 EFI_NATIVE_INTERFACE
,
170 mInExitBootServices
= TRUE
;
175 Software MMI handler that is called when a ExitBoot Service event is signaled.
177 @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
178 @param Context Points to an optional handler context which was specified when the handler was registered.
179 @param CommBuffer A pointer to a collection of data in memory that will
180 be conveyed from a non-MM environment into an MM environment.
181 @param CommBufferSize The size of the CommBuffer.
188 MmReadyToBootHandler (
189 IN EFI_HANDLE DispatchHandle
,
190 IN CONST VOID
*Context
, OPTIONAL
191 IN OUT VOID
*CommBuffer
, OPTIONAL
192 IN OUT UINTN
*CommBufferSize OPTIONAL
196 EFI_STATUS Status
= EFI_SUCCESS
;
197 STATIC BOOLEAN mInReadyToBoot
= FALSE
;
199 if (!mInReadyToBoot
) {
201 Status
= MmInstallProtocolInterface (
203 &gEfiEventReadyToBootGuid
,
204 EFI_NATIVE_INTERFACE
,
208 mInReadyToBoot
= TRUE
;
213 Software MMI handler that is called when the DxeMmReadyToLock protocol is added
214 or if gEfiEventReadyToBootGuid is signaled. This function unregisters the
215 Software SMIs that are nor required after MMRAM is locked and installs the
216 MM Ready To Lock Protocol so MM Drivers are informed that MMRAM is about
219 @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
220 @param Context Points to an optional handler context which was specified when the handler was registered.
221 @param CommBuffer A pointer to a collection of data in memory that will
222 be conveyed from a non-MM environment into an MM environment.
223 @param CommBufferSize The size of the CommBuffer.
230 MmReadyToLockHandler (
231 IN EFI_HANDLE DispatchHandle
,
232 IN CONST VOID
*Context
, OPTIONAL
233 IN OUT VOID
*CommBuffer
, OPTIONAL
234 IN OUT UINTN
*CommBufferSize OPTIONAL
241 DEBUG ((DEBUG_INFO
, "MmReadyToLockHandler\n"));
244 // Unregister MMI Handlers that are no longer required after the MM driver dispatch is stopped
246 for (Index
= 0; mMmCoreMmiHandlers
[Index
].HandlerType
!= NULL
; Index
++) {
247 if (mMmCoreMmiHandlers
[Index
].UnRegister
) {
248 MmiHandlerUnRegister (mMmCoreMmiHandlers
[Index
].DispatchHandle
);
253 // Install MM Ready to lock protocol
256 Status
= MmInstallProtocolInterface (
258 &gEfiMmReadyToLockProtocolGuid
,
259 EFI_NATIVE_INTERFACE
,
264 // Make sure MM CPU I/O 2 Protocol has been installed into the handle database
266 //Status = MmLocateProtocol (&EFI_MM_CPU_IO_PROTOCOL_GUID, NULL, &Interface);
269 // Print a message on a debug build if the MM CPU I/O 2 Protocol is not installed
271 //if (EFI_ERROR (Status)) {
272 //DEBUG ((DEBUG_ERROR, "\nSMM: SmmCpuIo Arch Protocol not present!!\n"));
277 // Assert if the CPU I/O 2 Protocol is not installed
279 //ASSERT_EFI_ERROR (Status);
282 // Display any drivers that were not dispatched because dependency expression
283 // evaluated to false if this is a debug build
285 //MmDisplayDiscoveredNotDispatched ();
291 Software MMI handler that is called when the EndOfDxe event is signaled.
292 This function installs the MM EndOfDxe Protocol so MM Drivers are informed that
293 platform code will invoke 3rd part code.
295 @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
296 @param Context Points to an optional handler context which was specified when the handler was registered.
297 @param CommBuffer A pointer to a collection of data in memory that will
298 be conveyed from a non-MM environment into an MM environment.
299 @param CommBufferSize The size of the CommBuffer.
307 IN EFI_HANDLE DispatchHandle
,
308 IN CONST VOID
*Context
, OPTIONAL
309 IN OUT VOID
*CommBuffer
, OPTIONAL
310 IN OUT UINTN
*CommBufferSize OPTIONAL
316 DEBUG ((DEBUG_INFO
, "MmEndOfDxeHandler\n"));
318 // Install MM EndOfDxe protocol
321 Status
= MmInstallProtocolInterface (
323 &gEfiMmEndOfDxeProtocolGuid
,
324 EFI_NATIVE_INTERFACE
,
333 The main entry point to MM Foundation.
335 Note: This function is only used by MMRAM invocation. It is never used by DXE invocation.
337 @param MmEntryContext Processor information and functionality
338 needed by MM Foundation.
344 IN CONST EFI_MM_ENTRY_CONTEXT
*MmEntryContext
348 EFI_MM_COMMUNICATE_HEADER
*CommunicateHeader
;
350 DEBUG ((DEBUG_INFO
, "MmEntryPoint ...\n"));
353 // Update MMST using the context
355 CopyMem (&gMmCoreMmst
.MmStartupThisAp
, MmEntryContext
, sizeof (EFI_MM_ENTRY_CONTEXT
));
358 // Call platform hook before Mm Dispatch
360 //PlatformHookBeforeMmDispatch ();
363 // If a legacy boot has occured, then make sure gMmCorePrivate is not accessed
367 // TBD: Mark the InMm flag as TRUE
369 gMmCorePrivate
->InMm
= TRUE
;
372 // Check to see if this is a Synchronous MMI sent through the MM Communication
373 // Protocol or an Asynchronous MMI
375 if (gMmCorePrivate
->CommunicationBuffer
!= 0) {
377 // Synchronous MMI for MM Core or request from Communicate protocol
379 if (!MmIsBufferOutsideMmValid ((UINTN
)gMmCorePrivate
->CommunicationBuffer
, gMmCorePrivate
->BufferSize
)) {
381 // If CommunicationBuffer is not in valid address scope, return EFI_INVALID_PARAMETER
383 gMmCorePrivate
->CommunicationBuffer
= 0;
384 gMmCorePrivate
->ReturnStatus
= EFI_INVALID_PARAMETER
;
386 CommunicateHeader
= (EFI_MM_COMMUNICATE_HEADER
*)(UINTN
)gMmCorePrivate
->CommunicationBuffer
;
387 gMmCorePrivate
->BufferSize
-= OFFSET_OF (EFI_MM_COMMUNICATE_HEADER
, Data
);
389 &CommunicateHeader
->HeaderGuid
,
391 CommunicateHeader
->Data
,
392 (UINTN
*)&gMmCorePrivate
->BufferSize
395 // Update CommunicationBuffer, BufferSize and ReturnStatus
396 // Communicate service finished, reset the pointer to CommBuffer to NULL
398 gMmCorePrivate
->BufferSize
+= OFFSET_OF (EFI_MM_COMMUNICATE_HEADER
, Data
);
399 gMmCorePrivate
->CommunicationBuffer
= 0;
400 gMmCorePrivate
->ReturnStatus
= (Status
== EFI_SUCCESS
) ? EFI_SUCCESS
: EFI_NOT_FOUND
;
405 // Process Asynchronous MMI sources
407 MmiManage (NULL
, NULL
, NULL
, NULL
);
410 // TBD: Do not use private data structure ?
414 // Clear the InMm flag as we are going to leave MM
416 gMmCorePrivate
->InMm
= FALSE
;
418 DEBUG ((DEBUG_INFO
, "MmEntryPoint Done\n"));
423 MmConfigurationMmNotify (
424 IN CONST EFI_GUID
*Protocol
,
430 EFI_MM_CONFIGURATION_PROTOCOL
*MmConfiguration
;
432 DEBUG ((DEBUG_INFO
, "MmConfigurationMmNotify(%g) - %x\n", Protocol
, Interface
));
434 MmConfiguration
= Interface
;
437 // Register the MM Entry Point provided by the MM Core with the MM COnfiguration protocol
439 Status
= MmConfiguration
->RegisterMmEntry (MmConfiguration
, (EFI_MM_ENTRY_POINT
)(UINTN
)gMmCorePrivate
->MmEntryPoint
);
440 ASSERT_EFI_ERROR (Status
);
443 // Set flag to indicate that the MM Entry Point has been registered which
444 // means that MMIs are now fully operational.
446 gMmCorePrivate
->MmEntryPointRegistered
= TRUE
;
449 // Print debug message showing MM Core entry point address.
451 DEBUG ((DEBUG_INFO
, "MM Core registered MM Entry Point address %p\n", (VOID
*)(UINTN
)gMmCorePrivate
->MmEntryPoint
));
460 EFI_PEI_HOB_POINTERS Hob
;
462 ASSERT (HobStart
!= NULL
);
464 Hob
.Raw
= (UINT8
*) HobStart
;
465 while (!END_OF_HOB_LIST (Hob
)) {
466 Hob
.Raw
= GET_NEXT_HOB (Hob
);
469 // Need plus END_OF_HOB_LIST
471 return (UINTN
)Hob
.Raw
- (UINTN
)HobStart
+ sizeof (EFI_HOB_GENERIC_HEADER
);
475 The Entry Point for MM Core
477 Install DXE Protocols and reload MM Core into MMRAM and register MM Core
478 EntryPoint on the MMI vector.
480 Note: This function is called for both DXE invocation and MMRAM invocation.
482 @param ImageHandle The firmware allocated handle for the EFI image.
483 @param SystemTable A pointer to the EFI System Table.
485 @retval EFI_SUCCESS The entry point is executed successfully.
486 @retval Other Some error occurred when executing this entry point.
500 EFI_HOB_GUID_TYPE
*GuidHob
;
501 MM_CORE_DATA_HOB_DATA
*DataInHob
;
502 EFI_HOB_GUID_TYPE
*MmramRangesHob
;
503 EFI_MMRAM_HOB_DESCRIPTOR_BLOCK
*MmramRangesHobData
;
504 EFI_MMRAM_DESCRIPTOR
*MmramRanges
;
505 UINT32 MmramRangeCount
;
506 EFI_HOB_FIRMWARE_VOLUME
*BfvHob
;
508 ProcessLibraryConstructorList (HobStart
, &gMmCoreMmst
);
510 DEBUG ((DEBUG_INFO
, "MmMain - 0x%x\n", HobStart
));
513 // Determine if the caller has passed a reference to a MM_CORE_PRIVATE_DATA
514 // structure in the Hoblist. This choice will govern how boot information is
517 GuidHob
= GetNextGuidHob (&gMmCoreDataHobGuid
, HobStart
);
518 if (GuidHob
== NULL
) {
520 // Allocate and zero memory for a MM_CORE_PRIVATE_DATA table and then
523 gMmCorePrivate
= (MM_CORE_PRIVATE_DATA
*) AllocateRuntimePages(EFI_SIZE_TO_PAGES(sizeof (MM_CORE_PRIVATE_DATA
)));
524 SetMem ((VOID
*)(UINTN
)gMmCorePrivate
, sizeof (MM_CORE_PRIVATE_DATA
), 0);
525 gMmCorePrivate
->Signature
= MM_CORE_PRIVATE_DATA_SIGNATURE
;
526 gMmCorePrivate
->MmEntryPointRegistered
= FALSE
;
527 gMmCorePrivate
->InMm
= FALSE
;
528 gMmCorePrivate
->ReturnStatus
= EFI_SUCCESS
;
531 // Extract the MMRAM ranges from the MMRAM descriptor HOB
533 MmramRangesHob
= GetNextGuidHob (&gEfiMmPeiMmramMemoryReserveGuid
, HobStart
);
534 if (MmramRangesHob
== NULL
)
535 return EFI_UNSUPPORTED
;
537 MmramRangesHobData
= GET_GUID_HOB_DATA (MmramRangesHob
);
538 ASSERT (MmramRangesHobData
!= NULL
);
539 MmramRanges
= MmramRangesHobData
->Descriptor
;
540 MmramRangeCount
= MmramRangesHobData
->NumberOfMmReservedRegions
;
541 ASSERT (MmramRanges
);
542 ASSERT (MmramRangeCount
);
545 // Copy the MMRAM ranges into MM_CORE_PRIVATE_DATA table just in case any
546 // code relies on them being present there
548 gMmCorePrivate
->MmramRangeCount
= MmramRangeCount
;
549 gMmCorePrivate
->MmramRanges
=
550 (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocatePool (MmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
));
551 ASSERT (gMmCorePrivate
->MmramRanges
!= 0);
553 (VOID
*)(UINTN
)gMmCorePrivate
->MmramRanges
,
555 MmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
)
558 DataInHob
= GET_GUID_HOB_DATA (GuidHob
);
559 gMmCorePrivate
= (MM_CORE_PRIVATE_DATA
*)(UINTN
)DataInHob
->Address
;
560 MmramRanges
= (EFI_MMRAM_DESCRIPTOR
*)(UINTN
)gMmCorePrivate
->MmramRanges
;
561 MmramRangeCount
= gMmCorePrivate
->MmramRangeCount
;
565 // Print the MMRAM ranges passed by the caller
567 DEBUG ((DEBUG_INFO
, "MmramRangeCount - 0x%x\n", MmramRangeCount
));
568 for (Index
= 0; Index
< MmramRangeCount
; Index
++) {
569 DEBUG ((DEBUG_INFO
, "MmramRanges[%d]: 0x%016lx - 0x%lx\n", Index
,
570 MmramRanges
[Index
].CpuStart
,
571 MmramRanges
[Index
].PhysicalSize
));
575 // Copy the MMRAM ranges into private MMRAM
577 mMmramRangeCount
= MmramRangeCount
;
578 DEBUG ((DEBUG_INFO
, "mMmramRangeCount - 0x%x\n", mMmramRangeCount
));
579 mMmramRanges
= AllocatePool (mMmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
));
580 DEBUG ((DEBUG_INFO
, "mMmramRanges - 0x%x\n", mMmramRanges
));
581 ASSERT (mMmramRanges
!= NULL
);
582 CopyMem (mMmramRanges
, (VOID
*)(UINTN
)MmramRanges
, mMmramRangeCount
* sizeof (EFI_MMRAM_DESCRIPTOR
));
585 // Get Boot Firmware Volume address from the BFV Hob
587 BfvHob
= GetFirstHob (EFI_HOB_TYPE_FV
);
588 if (BfvHob
!= NULL
) {
589 DEBUG ((DEBUG_INFO
, "BFV address - 0x%x\n", BfvHob
->BaseAddress
));
590 DEBUG ((DEBUG_INFO
, "BFV size - 0x%x\n", BfvHob
->Length
));
591 gMmCorePrivate
->StandaloneBfvAddress
= BfvHob
->BaseAddress
;
594 gMmCorePrivate
->Mmst
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&gMmCoreMmst
;
595 gMmCorePrivate
->MmEntryPoint
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)MmEntryPoint
;
598 // No need to initialize memory service.
599 // It is done in constructor of StandaloneMmCoreMemoryAllocationLib(),
600 // so that the library linked with StandaloneMmCore can use AllocatePool() in constuctor.
603 DEBUG ((DEBUG_INFO
, "MmInstallConfigurationTable For HobList\n"));
607 HobSize
= GetHobListSize (HobStart
);
608 DEBUG ((DEBUG_INFO
, "HobSize - 0x%x\n", HobSize
));
609 MmHobStart
= AllocatePool (HobSize
);
610 DEBUG ((DEBUG_INFO
, "MmHobStart - 0x%x\n", MmHobStart
));
611 ASSERT (MmHobStart
!= NULL
);
612 CopyMem (MmHobStart
, HobStart
, HobSize
);
613 Status
= MmInstallConfigurationTable (&gMmCoreMmst
, &gEfiHobListGuid
, MmHobStart
, HobSize
);
614 ASSERT_EFI_ERROR (Status
);
617 // Register notification for EFI_MM_CONFIGURATION_PROTOCOL registration and
618 // use it to register the MM Foundation entrypoint
620 DEBUG ((DEBUG_INFO
, "MmRegisterProtocolNotify - MmConfigurationMmProtocol\n"));
621 Status
= MmRegisterProtocolNotify (
622 &gEfiMmConfigurationProtocolGuid
,
623 MmConfigurationMmNotify
,
626 ASSERT_EFI_ERROR (Status
);
629 // Dispatch standalone BFV
631 DEBUG ((DEBUG_INFO
, "Mm Dispatch StandaloneBfvAddress - 0x%08x\n", gMmCorePrivate
->StandaloneBfvAddress
));
632 if (gMmCorePrivate
->StandaloneBfvAddress
!= 0) {
633 MmCoreFfsFindMmDriver ((EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)gMmCorePrivate
->StandaloneBfvAddress
);
638 // Register all handlers in the core table
640 for (Index
= 0; mMmCoreMmiHandlers
[Index
].HandlerType
!= NULL
; Index
++) {
641 Status
= MmiHandlerRegister (
642 mMmCoreMmiHandlers
[Index
].Handler
,
643 mMmCoreMmiHandlers
[Index
].HandlerType
,
644 &mMmCoreMmiHandlers
[Index
].DispatchHandle
646 DEBUG ((DEBUG_INFO
, "MmiHandlerRegister - GUID %g - Status %d\n", mMmCoreMmiHandlers
[Index
].HandlerType
, Status
));
649 DEBUG ((DEBUG_INFO
, "MmMain Done!\n"));