From cf9b5684059e9740ff63da9af7bbc8172c9247dd Mon Sep 17 00:00:00 2001 From: Dun Tan Date: Wed, 12 Jun 2024 11:04:37 +0800 Subject: [PATCH] StandaloneMmPkg: Install gEfiMmCommunication2ProtocolGuid Install gEfiMmCommunication2ProtocolGuid in the MmCommunicationDxe driver. Signed-off-by: Dun Tan --- .../MmCommunicationDxe/MmCommunicationDxe.c | 196 ++++++++++++++++++ .../MmCommunicationDxe/MmCommunicationDxe.h | 51 +++++ .../MmCommunicationDxe/MmCommunicationDxe.inf | 13 ++ 3 files changed, 260 insertions(+) diff --git a/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.c b/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.c index a985d9b803..e216de529f 100644 --- a/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.c +++ b/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.c @@ -9,6 +9,161 @@ #include "MmCommunicationDxe.h" +// +// PI 1.7 MM Communication Protocol 2 instance +// +EFI_MM_COMMUNICATION2_PROTOCOL mMmCommunication2 = { + MmCommunicate2 +}; + +MM_COMM_BUFFER mMmCommonBuffer; +EFI_SMM_CONTROL2_PROTOCOL *mSmmControl2; + +/** + 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 + ) +{ + EfiConvertPointer (0x0, (VOID **)&mMmCommonBuffer.Status); + EfiConvertPointer (0x0, (VOID **)&mMmCommonBuffer.PhysicalStart); + EfiConvertPointer (0x0, (VOID **)&mSmmControl2); +} + +/** + Processes the communication buffer for Mm communication protocols. + + This function encapsulates the common logic for handling communication buffers + used by MmCommunicate2 functions. + + @param[in, out] CommBuffer Pointer to the MM communication buffer + @param[in, out] CommSize The size of the data buffer being passed in. On exit, the size of data + being returned. Zero if the handler does not wish to reply with any data. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The message was successfully posted. + @retval EFI_INVALID_PARAMETER The CommBuffer was NULL. + @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation. + If this error is returned, the MessageLength field + in the CommBuffer header or the integer pointed by + CommSize, are updated to reflect the maximum payload + size the implementation can accommodate. + @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter, + if not omitted, are in address range that cannot be + accessed by the MM environment. +**/ +EFI_STATUS +EFIAPI +ProcessCommunicationBuffer ( + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommSize OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_MM_COMMUNICATE_HEADER *CommunicateHeader; + MM_COMM_BUFFER_STATUS *CommonBufferStatus; + UINTN BufferSize; + + // + // Check parameters + // + if (CommBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + CommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)CommBuffer; + BufferSize = OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data) + CommunicateHeader->MessageLength; + + if (CommSize != NULL) { + ASSERT (*CommSize == BufferSize); + } + + CommonBufferStatus = (MM_COMM_BUFFER_STATUS *)(UINTN)mMmCommonBuffer.Status; + + // + // Copy the content at input CommBuffer to fixed MM communication buffer + // if CommBuffer is not equal to fixed MM communication buffer. + // + if ((UINTN)CommBuffer != mMmCommonBuffer.PhysicalStart) { + CopyMem ((VOID *)(UINTN)mMmCommonBuffer.PhysicalStart, CommBuffer, BufferSize); + } + + CommonBufferStatus->IsCommBufferValid = TRUE; + + // + // Generate Software SMI + // + Status = mSmmControl2->Trigger (mSmmControl2, NULL, NULL, FALSE, 0); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + // + // Copy the returned data to the non-mmram buffer (CommBuffer) + // + if ((UINTN)CommBuffer != mMmCommonBuffer.PhysicalStart) { + CopyMem (CommBuffer, (VOID *)(UINTN)mMmCommonBuffer.PhysicalStart, CommonBufferStatus->ReturnBufferSize); + } + + // + // Retrieve BufferSize and return status from CommonBufferStatus + // + if (CommSize != NULL) { + *CommSize = CommonBufferStatus->ReturnBufferSize; + } + + CommonBufferStatus->IsCommBufferValid = FALSE; + + return CommonBufferStatus->ReturnStatus; +} + +/** + Communicates with a registered handler. + + This function provides a service to send and receive messages from a registered UEFI service. + + @param[in] This The EFI_MM_COMMUNICATION_PROTOCOL instance. + @param[in, out] CommBufferPhysical Physical address of the MM communication buffer. + @param[in, out] CommBufferVirtual Virtual address of the MM communication buffer. + @param[in, out] CommSize The size of the data buffer being passed in. On exit, the size of data + being returned. Zero if the handler does not wish to reply with any data. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The message was successfully posted. + @retval EFI_INVALID_PARAMETER The CommBuffer was NULL. + @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation. + If this error is returned, the MessageLength field + in the CommBuffer header or the integer pointed by + CommSize, are updated to reflect the maximum payload + size the implementation can accommodate. + @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter, + if not omitted, are in address range that cannot be + accessed by the MM environment. + +**/ +EFI_STATUS +EFIAPI +MmCommunicate2 ( + IN CONST EFI_MM_COMMUNICATION2_PROTOCOL *This, + IN OUT VOID *CommBufferPhysical, + IN OUT VOID *CommBufferVirtual, + IN OUT UINTN *CommSize OPTIONAL + ) +{ + return ProcessCommunicationBuffer (CommBufferVirtual, CommSize); +} + /** The Entry Point for MmCommunicateDxe driver. @@ -26,5 +181,46 @@ MmCommunicationEntryPoint ( IN EFI_SYSTEM_TABLE *SystemTable ) { + EFI_STATUS Status; + EFI_HANDLE Handle; + EFI_HOB_GUID_TYPE *GuidHob; + MM_COMM_BUFFER *MmCommonBuffer; + + // + // Locate gMmCommBufferHobGuid and cache the content + // + GuidHob = GetFirstGuidHob (&gMmCommBufferHobGuid); + ASSERT (GuidHob != NULL); + MmCommonBuffer = GET_GUID_HOB_DATA (GuidHob); + CopyMem (&mMmCommonBuffer, MmCommonBuffer, sizeof (MM_COMM_BUFFER)); + + // + // Get SMM Control2 Protocol + // + Status = gBS->LocateProtocol (&gEfiSmmControl2ProtocolGuid, NULL, (VOID **)&mSmmControl2); + ASSERT_EFI_ERROR (Status); + + Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &Handle, + &gEfiMmCommunication2ProtocolGuid, + EFI_NATIVE_INTERFACE, + &mMmCommunication2 + ); + ASSERT_EFI_ERROR (Status); + + // + // Register the event to convert the pointer for runtime. + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + MmVirtualAddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + NULL + ); + ASSERT_EFI_ERROR (Status); + return EFI_SUCCESS; } diff --git a/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.h b/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.h index 1e98aa1e8b..90cab5e64f 100644 --- a/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.h +++ b/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.h @@ -8,4 +8,55 @@ #ifndef MM_COMMUNICATION_DXE_H_ #define MM_COMMUNICATION_DXE_H_ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +/** + Communicates with a registered handler. + + This function provides a service to send and receive messages from a registered UEFI service. + + @param[in] This The EFI_MM_COMMUNICATION_PROTOCOL instance. + @param[in, out] CommBufferPhysical Physical address of the MM communication buffer. + @param[in, out] CommBufferVirtual Virtual address of the MM communication buffer. + @param[in, out] CommSize The size of the data buffer being passed in. On exit, the size of data + being returned. Zero if the handler does not wish to reply with any data. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The message was successfully posted. + @retval EFI_INVALID_PARAMETER The CommBuffer was NULL. + @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation. + If this error is returned, the MessageLength field + in the CommBuffer header or the integer pointed by + CommSize, are updated to reflect the maximum payload + size the implementation can accommodate. + @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter, + if not omitted, are in address range that cannot be + accessed by the MM environment. + +**/ +EFI_STATUS +EFIAPI +MmCommunicate2 ( + IN CONST EFI_MM_COMMUNICATION2_PROTOCOL *This, + IN OUT VOID *CommBufferPhysical, + IN OUT VOID *CommBufferVirtual, + IN OUT UINTN *CommSize OPTIONAL + ); + #endif diff --git a/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.inf b/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.inf index acfc5e433c..55c6611258 100644 --- a/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.inf +++ b/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.inf @@ -29,9 +29,22 @@ [LibraryClasses] UefiDriverEntryPoint + BaseLib + DebugLib + HobLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiLib + UefiRuntimeLib [Guids] + gMmCommBufferHobGuid + gEfiEventVirtualAddressChangeGuid [Protocols] + gEfiMmCommunication2ProtocolGuid + gEfiSmmControl2ProtocolGuid [Depex] + gEfiSmmControl2ProtocolGuid