From d64766bde654a57e3e329e8e6a906e993df6a58c Mon Sep 17 00:00:00 2001 From: Dun Tan Date: Tue, 11 Jun 2024 11:40:24 +0800 Subject: [PATCH] StandaloneMmPkg: Create some notification of protocol and Event Create the notifications of some protocols and event that the Standalone Mm requires in MmCommunicationDxe: gEfiDxeMmReadyToLockProtocolGuid gEfiEventExitBootServicesGuid gEfiEventVirtualAddressChangeGuid gEfiEndOfDxeEventGroupGuid gEfiEventReadyToBootGuid Signed-off-by: Dun Tan --- .../MmCommunicationDxe/MmCommunicationDxe.c | 223 +++++++++++++++++- .../MmCommunicationDxe/MmCommunicationDxe.h | 82 +++++++ .../MmCommunicationDxe/MmCommunicationDxe.inf | 7 +- 3 files changed, 301 insertions(+), 11 deletions(-) diff --git a/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.c b/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.c index b4c634db77..7b1e0636ff 100644 --- a/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.c +++ b/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.c @@ -25,6 +25,189 @@ EFI_MM_COMMUNICATION_PROTOCOL mMmCommunication = { MM_COMM_BUFFER mMmCommonBuffer; EFI_SMM_CONTROL2_PROTOCOL *mSmmControl2; +EFI_SMM_ACCESS2_PROTOCOL *mSmmAccess; +BOOLEAN mSmmLocked = FALSE; +BOOLEAN mEndOfDxe = FALSE; + +// +// Table of Protocol notification and GUIDed Event notifications that the Standalone Mm requires +// +MM_EVENT_NOTIFICATION mMmEvents[] = { + // + // Declare protocol notification on DxeMmReadyToLock protocols. When this notification is established, + // the associated event is immediately signalled, so the notification function will be executed and the + // DXE Mm Ready To Lock Protocol will be found if it is already in the handle database. + // + { ProtocolNotify, TRUE, &gEfiDxeMmReadyToLockProtocolGuid, MmReadyToLockEventNotify, &gEfiDxeMmReadyToLockProtocolGuid, NULL }, + // + // Declare event notification on Ready To Boot Event Group. This is an extra event notification that is + // used to make sure SMRAM is locked before any boot options are processed. + // + { EventNotify, TRUE, &gEfiEventReadyToBootGuid, MmReadyToLockEventNotify, &gEfiEventReadyToBootGuid, NULL }, + // + // Declare event notification on Ready To Boot Event Group. This is used to inform the MM Core + // to notify MM driver that system enter ready to boot. + // + { EventNotify, FALSE, &gEfiEventReadyToBootGuid, MmGuidedEventNotify, &gEfiEventReadyToBootGuid, NULL }, + // + // Declare event notification on EndOfDxe event. When this notification is established, + // the associated event is immediately signalled, so the notification function will be executed and the + // End Of Dxe Protocol will be found if it is already in the handle database. + // + { EventNotify, TRUE, &gEfiEndOfDxeEventGroupGuid, MmGuidedEventNotify, &gEfiEndOfDxeEventGroupGuid, NULL }, + // + // Declare event notification on EndOfDxe event. This is used to set EndOfDxe event signaled flag. + // + { EventNotify, TRUE, &gEfiEndOfDxeEventGroupGuid, MmEndOfDxeEventNotify, &gEfiEndOfDxeEventGroupGuid, NULL }, + // + // Declare event notification on Exit Boot Services Event Group. This is used to inform the MM Core + // to notify MM driver that system enter exit boot services. + // + { EventNotify, FALSE, &gEfiEventExitBootServicesGuid, MmGuidedEventNotify, &gEfiEventExitBootServicesGuid, NULL }, + // + // Declare event notification on SetVirtualAddressMap() Event Group. This is used to convert fixed MM communication buffer + // and MM_COMM_BUFFER_STATUS in mMmCommonBuffer, mSmmControl2 from physical addresses to virtual addresses. + // + { EventNotify, FALSE, &gEfiEventVirtualAddressChangeGuid, MmVirtualAddressChangeEvent, NULL, NULL }, + // + // Terminate the table of event notifications + // + { EndNotify, FALSE, NULL, NULL, NULL, NULL } +}; + +/** + Event notification that is fired when GUIDed Event Group is signaled. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +VOID +EFIAPI +MmGuidedEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINTN Size; + EFI_MM_COMMUNICATE_HEADER *CommunicateHeader; + + CommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)(UINTN)mMmCommonBuffer.PhysicalStart; + + // + // Use Guid to initialize EFI_MM_COMMUNICATE_HEADER structure + // + CopyGuid (&CommunicateHeader->HeaderGuid, (EFI_GUID *)Context); + CommunicateHeader->MessageLength = 1; + CommunicateHeader->Data[0] = 0; + + // + // Generate the Software SMI and return the result + // + Size = sizeof (EFI_MM_COMMUNICATE_HEADER); + MmCommunicate2 (&mMmCommunication2, CommunicateHeader, CommunicateHeader, &Size); +} + +/** + Event notification that is fired every time a DxeSmmReadyToLock protocol is added + or if gEfiEventReadyToBootGuid is signaled. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +VOID +EFIAPI +MmReadyToLockEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + VOID *Interface; + UINTN Index; + + // + // See if we are already locked + // + if (mSmmLocked) { + return; + } + + // + // Make sure this notification is for this handler + // + if (CompareGuid ((EFI_GUID *)Context, &gEfiDxeMmReadyToLockProtocolGuid)) { + Status = gBS->LocateProtocol (&gEfiDxeMmReadyToLockProtocolGuid, NULL, &Interface); + if (EFI_ERROR (Status)) { + return; + } + } else { + // + // If MM is not locked yet and we got here from gEfiEventReadyToBootGuid being + // signaled, then gEfiDxeMmReadyToLockProtocolGuid was not installed as expected. + // Print a warning on debug builds. + // + DEBUG ((DEBUG_WARN, "DXE Mm Ready To Lock Protocol not installed before Ready To Boot signal\n")); + } + + if (!mEndOfDxe) { + DEBUG ((DEBUG_ERROR, "EndOfDxe Event must be signaled before DxeSmmReadyToLock Protocol installation!\n")); + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED, + (EFI_SOFTWARE_SMM_DRIVER | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE) + ); + ASSERT (FALSE); + } + + // + // Lock the SMRAM (Note: Locking SMRAM may not be supported on all platforms) + // + mSmmAccess->Lock (mSmmAccess); + + // + // Close protocol and event notification events that do not apply after the + // DXE MM Ready To Lock Protocol has been installed or the Ready To Boot + // event has been signalled. + // + for (Index = 0; mMmEvents[Index].NotifyFunction != NULL; Index++) { + if (mMmEvents[Index].CloseOnLock) { + gBS->CloseEvent (mMmEvents[Index].Event); + } + } + + // + // Inform MM Core that the DxeSmmReadyToLock protocol was installed + // + MmGuidedEventNotify (Event, (VOID *)&gEfiDxeMmReadyToLockProtocolGuid); + + // + // Print debug message that the SMRAM window is now locked. + // + DEBUG ((DEBUG_INFO, "MmCommunicationDxe locked SMRAM window\n")); + + // + // Set flag so this operation will not be performed again + // + mSmmLocked = TRUE; +} + +/** + Event notification that is fired when EndOfDxe Event Group is signaled. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +VOID +EFIAPI +MmEndOfDxeEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + mEndOfDxe = TRUE; +} /** Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. @@ -226,6 +409,8 @@ MmCommunicationEntryPoint ( EFI_HANDLE Handle; EFI_HOB_GUID_TYPE *GuidHob; MM_COMM_BUFFER *MmCommonBuffer; + UINTN Index; + VOID *Registration; // // Locate gMmCommBufferHobGuid and cache the content @@ -241,6 +426,12 @@ MmCommunicationEntryPoint ( Status = gBS->LocateProtocol (&gEfiSmmControl2ProtocolGuid, NULL, (VOID **)&mSmmControl2); ASSERT_EFI_ERROR (Status); + // + // Get SMM Access Protocol + // + Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&mSmmAccess); + ASSERT_EFI_ERROR (Status); + Handle = NULL; Status = gBS->InstallProtocolInterface ( &Handle, @@ -259,17 +450,29 @@ MmCommunicationEntryPoint ( ASSERT_EFI_ERROR (Status); // - // Register the event to convert the pointer for runtime. + // Create the set of protocol and event notifications that the Standalone Mm requires // - Status = gBS->CreateEventEx ( - EVT_NOTIFY_SIGNAL, - TPL_NOTIFY, - MmVirtualAddressChangeEvent, - NULL, - &gEfiEventVirtualAddressChangeGuid, - NULL - ); - ASSERT_EFI_ERROR (Status); + for (Index = 0; mMmEvents[Index].NotificationType != EndNotify; Index++) { + if (mMmEvents[Index].NotificationType == ProtocolNotify) { + mMmEvents[Index].Event = EfiCreateProtocolNotifyEvent ( + mMmEvents[Index].Guid, + TPL_CALLBACK, + mMmEvents[Index].NotifyFunction, + mMmEvents[Index].NotifyContext, + &Registration + ); + } else { + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + mMmEvents[Index].NotifyFunction, + mMmEvents[Index].NotifyContext, + mMmEvents[Index].Guid, + &mMmEvents[Index].Event + ); + ASSERT_EFI_ERROR (Status); + } + } return EFI_SUCCESS; } diff --git a/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.h b/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.h index 603cc7691c..d84d8218ec 100644 --- a/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.h +++ b/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.h @@ -19,14 +19,36 @@ #include #include #include +#include #include #include #include +#include +#include #include #include +typedef enum { + EventNotify, + ProtocolNotify, + EndNotify, +} NOTIFICATION_TYPE; + +// +// Data structure used to declare a table of protocol notifications and event +// notifications required by the Standalone Mm environment +// +typedef struct { + NOTIFICATION_TYPE NotificationType; + BOOLEAN CloseOnLock; + EFI_GUID *Guid; + EFI_EVENT_NOTIFY NotifyFunction; + VOID *NotifyContext; + EFI_EVENT Event; +} MM_EVENT_NOTIFICATION; + /** Communicates with a registered handler. @@ -91,4 +113,64 @@ MmCommunicate ( IN OUT UINTN *CommSize OPTIONAL ); +/** + Event notification that is fired every time a DxeSmmReadyToLock protocol is added + or if gEfiEventReadyToBootGuid is signaled. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +VOID +EFIAPI +MmReadyToLockEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Event notification that is fired when GUIDed Event Group is signaled. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +VOID +EFIAPI +MmGuidedEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Event notification that is fired when EndOfDxe Event Group is signaled. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +VOID +EFIAPI +MmEndOfDxeEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. + + This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. + It convers pointer to new virtual address. + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +MmVirtualAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ); + #endif diff --git a/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.inf b/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.inf index c46a3ba8bb..821df02fdc 100644 --- a/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.inf +++ b/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.inf @@ -37,15 +37,20 @@ UefiBootServicesTableLib UefiLib UefiRuntimeLib + ReportStatusCodeLib [Guids] gMmCommBufferHobGuid gEfiEventVirtualAddressChangeGuid + gEfiEndOfDxeEventGroupGuid + gEfiEventExitBootServicesGuid [Protocols] gEfiMmCommunication2ProtocolGuid gEfiSmmControl2ProtocolGuid gEfiMmCommunicationProtocolGuid + gEfiDxeMmReadyToLockProtocolGuid + gEfiSmmAccess2ProtocolGuid [Depex] - gEfiSmmControl2ProtocolGuid + gEfiSmmAccess2ProtocolGuid AND gEfiSmmControl2ProtocolGuid