SMM/MM Communication Overview

Understanding how DXE triggers and communicates with SMM

DXE Driver
Prepare Comm Buffer
Trigger SMI
SMM Processing
Return Result
S

What is SMM?

C

Why SMM Communication?

M

What is Standalone MM?

Memory Architecture

Memory regions involved in DXE-SMM communication

Normal DRAM

SMRAM (TSEG)

Communication Buffer

MM Trigger Mechanism (SMI & MMI)

Understanding how platforms transition into Management Mode

x86 Architecture: SMI Trigger

Software SMI

Hardware SMI

SMM Entry Flow

ARM Architecture: MMI & Standalone MM

Sync MMI (SMC)

Async MMI (Hardware)

StMM Entry Flow

Communication Flow

Step-by-step walkthrough of DXE-SMM communication

Step 1 / 8

Communication Buffer Internals

Understanding the EFI_MM_COMMUNICATE_HEADER structure

EFI_MM_COMMUNICATE_HEADER { HeaderGuid, MessageLength, Data[] }

HeaderGuid

MessageLength

Data[]

Buffer Validation

MM Handler Registration (SMI & MMI)

How SMM/MM drivers register handlers for dispatch

GUID-Based Handler

Hardware/Software specific Handler

Root MM Handler

MM Driver Lifecycle & Dispatch (SmiManage / MmiManage)

Standalone MM vs Traditional MM

Understanding the differences

Traditional MM

    Standalone MM

      Key Code Analysis

      Core SMM communication implementation in EDK2

      Communicate() / MmCommunicate()

      // MdeModulePkg/Core/PiSmmIpl/PiSmmIpl.c
      EFI_STATUS
      EFIAPI
      SmmCommunicationCommunicate (
        IN CONST EFI_SMM_COMMUNICATION_PROTOCOL  *This,
        IN OUT VOID                              *CommBuffer,
        IN OUT UINTN                             *CommSize OPTIONAL
        )
      {
        //
        // Validate CommBuffer and CommSize
        //
        CommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)CommBuffer;
        ...
      
        //
        // Save the comm buffer pointer in a well-known secure location
        // so MM Core can find it after Trap
        //
        gSmmCorePrivate->CommunicationBuffer = CommBuffer;
        gSmmCorePrivate->BufferSize          = TempCommSize;
      
        //
        // Trigger Hardware Trap (e.g. Software SMI via 0xB2 or SMC)
        //
        IoWrite8 (0xB2, gSmmCorePrivate->SwSmiValue); // x86 specific
        // For ARM: ArmCallSmc (SMC_ARG_SMM_COMMUNICATE...)
      
        //
        // After RSM / SMC return, execution resumes here
        // Return status is already in CommBuffer
        //
        return gSmmCorePrivate->ReturnStatus;
      }

      MmEntryPoint() / SmmEntryPoint()

      // MdeModulePkg/Core/PiSmmCore/PiSmmCore.c (or StandaloneMmCore)
      VOID
      EFIAPI
      SmmEntryPoint (
        IN CONST EFI_SMM_ENTRY_CONTEXT  *SmmEntryContext
        )
      {
        //
        // Check if this trap was triggered by Communicate()
        //
        if (gSmmCorePrivate->CommunicationBuffer != NULL) {
          CommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)
                                gSmmCorePrivate->CommunicationBuffer;
      
          //
          // Validate buffer is outside Secure Memory
          //
          BufferSize = GetCommBufferSize (CommunicateHeader);
          if (!SmmIsBufferOutsideSmmValid (
                 (UINTN)CommunicateHeader, BufferSize)) {
            gSmmCorePrivate->ReturnStatus = EFI_ACCESS_DENIED;
            return;
          }
      
          //
          // Dispatch to registered handler by GUID
          //
          gSmmCorePrivate->ReturnStatus = SmiManage ( // Or MmiManage
            &CommunicateHeader->HeaderGuid,
            NULL,
            CommunicateHeader->Data,
            &CommunicateHeader->MessageLength
            );
        }
        //
        // Also dispatch root MM handlers (NULL GUID)
        //
        SmiManage (NULL, NULL, NULL, NULL); // Or MmiManage
      }

      MmiManage() / SmiManage()

      // MdeModulePkg/Core/PiSmmCore/Smi.c (or StandaloneMmPkg Mmi.c)
      EFI_STATUS
      EFIAPI
      SmiManage ( // Or MmiManage
        IN CONST EFI_GUID  *HandlerType,
        IN CONST VOID      *Context      OPTIONAL,
        IN OUT VOID        *CommBuffer   OPTIONAL,
        IN OUT UINTN       *CommBufferSize OPTIONAL
        )
      {
        //
        // Find the handler list for this GUID
        //
        List = MmCoreFindSmiEntry (HandlerType);
        if (List == NULL) {
          return EFI_NOT_FOUND;
        }
      
        //
        // Walk through all registered handlers
        //
        for (Link = List->SmiHandlers.ForwardLink;
             Link != &List->SmiHandlers;
             Link = Link->ForwardLink) {
      
          SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
      
          Status = SmiHandler->Handler (
                     SmiHandler->DispatchHandle,
                     Context,
                     CommBuffer,
                     CommBufferSize
                     );
      
          if (Status != EFI_WARN_INTERRUPT_SOURCE_QUIESCED) {
            SuccessReturn = TRUE;
          }
        }
      
        return SuccessReturn ? EFI_SUCCESS : EFI_INTERRUPT_PENDING;
      }

      MmiHandlerRegister() Example

      // Example MM Driver registering a communication handler
      #include <Protocol/MmCommunication.h>
      
      EFI_GUID gMyHandlerGuid = { 0x12345678, 0xABCD, ... };
      EFI_HANDLE  mDispatchHandle = NULL;
      
      EFI_STATUS
      EFIAPI
      MyMmHandler (
        IN EFI_HANDLE  DispatchHandle,
        IN CONST VOID  *Context        OPTIONAL,
        IN OUT VOID    *CommBuffer     OPTIONAL,
        IN OUT UINTN   *CommBufferSize OPTIONAL
        )
      {
        MY_REQUEST  *Request;
      
        if (CommBuffer == NULL || CommBufferSize == NULL) {
          return EFI_SUCCESS;
        }
      
        //
        // Validate buffer is outside Secure Memory
        //
        if (!MmIsBufferOutsideMmValid ((UINTN)CommBuffer, *CommBufferSize)) {
          return EFI_ACCESS_DENIED;
        }
      
        Request = (MY_REQUEST *)CommBuffer;
      
        //
        // Process request and write response
        //
        switch (Request->Operation) {
          case OP_READ:
            Request->Status = DoSecureRead (Request);
            break;
          case OP_WRITE:
            Request->Status = DoSecureWrite (Request);
            break;
        }
      
        return EFI_SUCCESS;
      }
      
      EFI_STATUS
      EFIAPI
      MyDriverEntryPoint (
        IN EFI_HANDLE        ImageHandle,
        IN EFI_SYSTEM_TABLE  *SystemTable
        )
      {
        //
        // Register GUID-based MM handler
        //
        gMmst->MmiHandlerRegister ( // Or gSmst->SmiHandlerRegister
                 MyMmHandler,
                 &gMyHandlerGuid,
                 &mDispatchHandle
                 );
      
        return EFI_SUCCESS;
      }

      References

      Resources for deeper learning

      PI Specification

      EDK2 SMM Core Source

      PiSmmIpl Source

      Standalone MM Core