D
DioProcess

SMI Communication

The kernel driver communicates with the SMM handler via a shared buffer + software SMI. The buffer's physical address is published to NVRAM at boot time by DioProcessDxe.efi.

Software SMI is Platform-Specific

Software SMI is typically triggered by writing to I/O port 0xB2 (Intel APM_CNT). The exact behavior depends on the chipset; QEMU/OVMF emulates the standard PIIX4/ICH9 behavior.

NVRAM Variable

At DXE phase, DioProcessDxe.efi allocates a communication buffer and publishes its physical address to a runtime-accessible NVRAM variable so the OS can find it.

  • GUID: {D10PR0C5-1337-4242-BEEF-CAFEBABE0002}
  • Name: DioProcessSmmBuffer
  • Value: 64-bit physical address of the communication buffer
  • Attributes: BS+RT (Boot Service + Runtime Access)

Kernel-Side SMI Trigger

// kernelmode/DioProcess/DioProcessDriver/SMM/SmmCommunication.cpp
NTSTATUS TriggerSmi(SMM_COMM_BUFFER* Cmd) {
    // 1. Read buffer address from NVRAM
    ULONG64 BufferPa = ReadNvramU64(&kSmmBufferGuid, L"DioProcessSmmBuffer");
    if (!BufferPa) return STATUS_NOT_FOUND;

    // 2. Map buffer into kernel VA
    PHYSICAL_ADDRESS Pa = { .QuadPart = BufferPa };
    PVOID BufferVa = MmMapIoSpace(Pa, sizeof(*Cmd), MmNonCached);
    if (!BufferVa) return STATUS_INSUFFICIENT_RESOURCES;

    // 3. Copy command into shared buffer
    RtlCopyMemory(BufferVa, Cmd, sizeof(*Cmd));

    // 4. Trigger software SMI (OUT 0xB2, cmd)
    __outbyte(0xB2, 0x00);   // SMI command byte — SMM handler ignores value

    // 5. Read response back
    RtlCopyMemory(Cmd, BufferVa, sizeof(*Cmd));

    // 6. Unmap
    MmUnmapIoSpace(BufferVa, sizeof(*Cmd));
    return STATUS_SUCCESS;
}

SMM-Side Handler

// efi/DioProcessSmm/Smi.c
EFI_STATUS EFIAPI SmiHandler(
    IN EFI_HANDLE  DispatchHandle,
    IN CONST VOID *Context OPTIONAL,
    IN OUT VOID  *CommBuffer OPTIONAL,
    IN OUT UINTN *CommBufferSize OPTIONAL
) {
    SMM_COMM_BUFFER *Cmd = (SMM_COMM_BUFFER *)CommBuffer;
    if (Cmd->Signature != SIGNATURE_32('D','P','S','M')) {
        return EFI_INVALID_PARAMETER;
    }

    switch (Cmd->Command) {
        case CMD_READ_PHYS:  Cmd->Status = HandleReadPhys(Cmd);  break;
        case CMD_WRITE_PHYS: Cmd->Status = HandleWritePhys(Cmd); break;
        case CMD_TRANSLATE:  Cmd->Status = HandleTranslate(Cmd); break;
        case CMD_PING:       Cmd->Status = STATUS_OK;            break;
        default:             Cmd->Status = STATUS_INVALID_CMD;   break;
    }
    return EFI_SUCCESS;
}

Handler Registration (DXE Side)

The SMM driver registers itself with the SMM IPL when dispatched into SMRAM. It uses gSmst->SmiHandlerRegister with a unique GUID so the kernel side can target this specific handler if multiple SMM drivers coexist.

// efi/DioProcessSmm/SmmMain.c
EFI_STATUS EFIAPI DioProcessSmmEntry(
    IN EFI_HANDLE        ImageHandle,
    IN EFI_SYSTEM_TABLE *SystemTable
) {
    EFI_HANDLE Handle = NULL;
    return gSmst->SmiHandlerRegister(
        SmiHandler,
        &gDioProcessSmiHandlerGuid,
        &Handle
    );
}

Serial Debug Output

When running under QEMU with OVMF, SMM debug prints appear on the serial console. This is the primary way to trace SMM initialization and command dispatch.

=[ DioProcess DXE ]=
[ DXE ] EFI_MM_COMMUNICATION2_PROTOCOL discovered
[ DXE ] Buffer allocated @ 0x7EFB1000
[ DXE ] NVRAM variable DioProcessSmmBuffer set
=[ DioProcess SMM ]=
=[ Ring -2 Memory Operations ]=
[ SMM ] SMM driver invoked by SMM IPL, initializing...
[ SMM ] SMI handler registered (GUID: D10PR0C5-...-0002)
[ SMM ] SMM driver has been initialized
[ SMM ] SMI fired — cmd=0x01 (READ_PHYS)
[ SMM ] ReadPhys 0x1000, 4096 bytes — OK

Implementation

LayerLocation
Kernel SMI triggerkernelmode/.../SMM/SmmCommunication.cpp
SMM handlerefi/DioProcessSmm/Smi.c
DXE buffer publisherefi/DioProcessDxe/DxeMain.c