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 <dun.tan@intel.com>
This commit is contained in:
Dun Tan 2024-06-11 11:40:24 +08:00 committed by mergify[bot]
parent a2a8558958
commit d64766bde6
3 changed files with 301 additions and 11 deletions

View File

@ -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;
}

View File

@ -19,14 +19,36 @@
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiRuntimeLib.h>
#include <Library/ReportStatusCodeLib.h>
#include <Protocol/SmmControl2.h>
#include <Protocol/MmCommunication2.h>
#include <Protocol/MmCommunication.h>
#include <Protocol/DxeMmReadyToLock.h>
#include <Protocol/SmmAccess2.h>
#include <Guid/MmCommBuffer.h>
#include <Guid/EventGroup.h>
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

View File

@ -37,15 +37,20 @@
UefiBootServicesTableLib
UefiLib
UefiRuntimeLib
ReportStatusCodeLib
[Guids]
gMmCommBufferHobGuid
gEfiEventVirtualAddressChangeGuid
gEfiEndOfDxeEventGroupGuid
gEfiEventExitBootServicesGuid
[Protocols]
gEfiMmCommunication2ProtocolGuid
gEfiSmmControl2ProtocolGuid
gEfiMmCommunicationProtocolGuid
gEfiDxeMmReadyToLockProtocolGuid
gEfiSmmAccess2ProtocolGuid
[Depex]
gEfiSmmControl2ProtocolGuid
gEfiSmmAccess2ProtocolGuid AND gEfiSmmControl2ProtocolGuid