Newer
Older
AMI-Aptio-BIOS-Reversed / SmmControl / SmmControl.c
@Ajax Dong Ajax Dong 2 days ago 24 KB Init
/**
 * SmmControl.efi - SMM Control Driver for HR650X BIOS (Purley/PCH LBG)
 *
 * Decompiled from: HR650X_3647_AJAX_BIOS_ORIGINAL.pe_structured/pe_files/0115_SmmControl_3d5e22bb70ab/SmmControl.efi.i64
 * MD5:    73fdb81ed9d9b5280a077140f6bcf6b8
 * SHA256: 3d5e22bb70ab549bc25fbb775ebf517bbf578777201e8787bba5aa5fd6c9a2a5
 *
 * File: SmmControl.c
 * Description: SMM Control Runtime DXE driver for PCH SMI management.
 *              Provides EFI_SMM_CONTROL2_PROTOCOL and EFI_SMM_COMMUNICATION_PROTOCOL
 *              interfaces for SMI generation, status handling, and communication.
 */

#include "SmmControl.h"

//
// ---------------------------------------------------------------------------
// Global Variables
// ---------------------------------------------------------------------------
//

EFI_HANDLE              gImageHandle       = NULL;
EFI_SYSTEM_TABLE        *gSystemTable      = NULL;
EFI_BOOT_SERVICES       *gBootServices     = NULL;
EFI_RUNTIME_SERVICES    *gRuntimeServices  = NULL;
EFI_RUNTIME_SERVICES    *gRuntimeServices_0 = NULL;
EFI_RUNTIME_SERVICES    *gRuntimeServices_1 = NULL;
UINT64                  gBootServices_0    = 0;
UINT16                  gSmiIoPortBase     = 0;       // word_4458: SMI I/O port base address
EFI_SMM_CONTROL2_PROTOCOL    *gSmmControl2       = NULL;  // psub_18AC
EFI_SMM_COMMUNICATION_PROTOCOL *gSmmCommunication = NULL;  // psub_1970
UINT32                  gSignature         = 0x63736D70; // 'pmsc' = 1668494441
EFI_HANDLE              gSmmImageHandle    = NULL;
VOID                    *gMmPciUsra        = NULL;   // qword_43E0
VOID                    *gHobList          = NULL;   // qword_43E8
VOID                    *gPcdDb            = NULL;   // qword_4408
VOID                    *gDsEntry          = NULL;   // qword_43D8
VOID                    *gDebugLib         = NULL;   // qword_43D0
UINT8                   gDebugLevel        = 0;      // n113
VOID                    *gSmiHobData       = NULL;   // qword_43F0
UINT64                  gSmiHobDataCount   = 0;      // qword_43F8
UINT64                  gSmiControlAddress = 0;      // qword_4438
UINTN                   gCmCpuCount        = 0;      // n2, initialized to 2

//
// Event handles
//
EFI_EVENT               gEventRestoreTpl         = NULL;  // qword_43C0
EFI_EVENT               gEventVirtualAddrChange  = NULL;  // qword_4440
EFI_EVENT               gEventRuntimeReady       = NULL;  // qword_4450
EFI_EVENT               gEventNotify             = NULL;  // qword_43B8

//
// ---------------------------------------------------------------------------
// Forward declarations of static functions
// ---------------------------------------------------------------------------
//
static
EFI_STATUS
SmiActivate (
  VOID
  );

static
EFI_STATUS
PciExpressInit (
  VOID
  );

static
VOID
SmiClearGpeStatus (
  VOID
  );

static
EFI_STATUS
GetDebugLibProtocol (
  VOID
  );

static
EFI_STATUS
LocateProtocol (
  IN  EFI_GUID  *ProtocolGuid,
  OUT VOID      **Interface
  );

static
BOOLEAN
CompareGuid (
  IN EFI_GUID  *Guid1,
  IN EFI_GUID  *Guid2
  );

static
UINT64
ReadUnaligned64 (
  IN CONST VOID  *Buffer
  );

static
EFI_STATUS
GetConfigurationTable (
  IN  EFI_GUID  *TableGuid,
  OUT VOID      **Table
  );

//
// ===========================================================================
// I/O Port Helpers (wrappers around BaseIoLibIntrinsic with assertion)
// ===========================================================================
//

/**
 * Read a 16-bit value from an I/O port (word-aligned).
 */
UINT16
IoRead16 (
  IN UINT16  Port
  )
{
  ASSERT ((Port & 1) == 0);
  return IoRead16 (Port);
}

/**
 * Write a 16-bit value to an I/O port (word-aligned).
 */
UINT16
IoWrite16 (
  IN UINT16  Port,
  IN UINT16  Value
  )
{
  ASSERT ((Port & 1) == 0);
  return IoWrite16 (Port, Value);
}

/**
 * Read a 32-bit value from an I/O port (dword-aligned).
 */
UINT32
IoRead32 (
  IN UINT16  Port
  )
{
  ASSERT ((Port & 3) == 0);
  return IoRead32 (Port);
}

/**
 * Write a 32-bit value to an I/O port (dword-aligned).
 */
UINT32
IoWrite32 (
  IN UINT16  Port,
  IN UINT32  Value
  )
{
  ASSERT ((Port & 3) == 0);
  return IoWrite32 (Port, Value);
}

/**
 * Read a 16-bit MMIO register from PCH LPC (word-aligned MMIO address).
 */
UINT16
MmioRead16 (
  IN UINT16  *Address
  )
{
  ASSERT (((UINTN)Address & 1) == 0);
  return *Address;
}

//
// ===========================================================================
// Debug Library Protocol (dynamically located)
// ===========================================================================
//

/**
 * Initialize debug protocol -- locate EFI_DEBUG_PROTOCOL for debug output.
 */
EFI_STATUS
InitDebugLib (
  VOID
  )
{
  EFI_STATUS  Status;
  UINT64      Pages;

  if (gDebugLib != NULL) {
    return EFI_SUCCESS;
  }

  //
  // Check if BootServices is available and we have enough memory
  //
  if (gBootServices_0 != 0) {
    Pages = gBootServices_0->AllocatePages (AllocateAnyPages, EfiBootServicesData, 31);
    gBootServices_0->FreePages (Pages, 1);

    if (Pages <= 0x10) {
      //
      // Low memory condition: try to locate the debug protocol
      //
      Status = LocateProtocol (&gEfiDebugProtocolGuid, NULL, &gDebugLib);
      if (EFI_ERROR (Status)) {
        gDebugLib = NULL;
      }
      return Status;
    }
  }

  return EFI_SUCCESS;
}

/**
 * Debug print -- conditionally output to debug console based on error level.
 */
VOID
DebugPrint (
  IN UINTN        ErrorLevel,
  IN CONST CHAR8  *Format,
  ...
  )
{
  EFI_DEBUG_PROTOCOL  *DebugProtocol;
  UINTN               DebugLevel;
  UINT8               CmosIndex;
  UINT8               CmosValue;
  UINTN               AllowedLevels;
  UINTN               AllowedPrintLevel;
  VA_LIST             Va;

  DebugProtocol = (EFI_DEBUG_PROTOCOL *)InitDebugLib ();
  AllowedLevels = 0;

  if (DebugProtocol != NULL) {
    //
    // Read CMOS diagnostic register to determine current debug level
    //
    CmosIndex  = IoRead8 (0x70);
    IoWrite8 (0x70, (CmosIndex & 0x80) | 0x4B);
    DebugLevel = IoRead8 (0x71);

    if (DebugLevel > 3) {
      DebugLevel = 3;
    }

    switch (DebugLevel) {
    case 1:
      AllowedLevels  = DEBUG_ERROR;
      AllowedPrintLevel = DEBUG_ERROR;
      break;
    case 2:
      AllowedLevels  = (UINTN)-1;
      AllowedPrintLevel = DEBUG_WARN;
      break;
    case 3:
      AllowedLevels  = (UINTN)-1;
      AllowedPrintLevel = DEBUG_INFO;
      break;
    default:
      AllowedLevels  = (UINTN)-1;
      AllowedPrintLevel = DEBUG_ERROR;
      break;
    }

    if ((AllowedLevels & ErrorLevel) != 0) {
      VA_START (Va, Format);
      DebugProtocol->Print (ErrorLevel, Format, Va);
      VA_END (Va);
    }
  }
}

/**
 * Debug assert -- print assertion failure message.
 */
VOID
DebugAssert (
  IN CONST CHAR8  *FileName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *Description
  )
{
  EFI_DEBUG_PROTOCOL  *DebugProtocol;

  DebugProtocol = (EFI_DEBUG_PROTOCOL *)InitDebugLib ();
  if (DebugProtocol != NULL) {
    DebugProtocol->Assert (FileName, LineNumber, Description);
  }
}

//
// ===========================================================================
// Event Notification Callbacks
// ===========================================================================
//

/**
 * Notification callback for TPL restore event -- clears BootServices reference.
 */
VOID
EFIAPI
OnRestoreTpl (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  gBootServices_0 = 0;
}

/**
 * Notification callback for virtual address change -- unregisters the debug protocol.
 */
VOID
EFIAPI
OnVirtualAddressChange (
  VOID
  )
{
  if (gDebugLib != NULL) {
    gRuntimeServices_0->ConvertPointer (0, &gDebugLib);
  }
}

/**
 * Notification callback for runtime ready event -- unregisters runtime services pointer.
 */
VOID
EFIAPI
OnRuntimeReady (
  VOID
  )
{
  gRuntimeServices_1->ConvertPointer (0, &gRuntimeServices_1);
}

/**
 * Notification callback for SMI HOB cleanup -- frees HOB data on exit.
 */
VOID
EFIAPI
OnSmiHobCleanup (
  VOID
  )
{
  UINT64  Index;

  if (gSmiHobData != NULL && gSmiHobDataCount > 0) {
    for (Index = 0; Index < gSmiHobDataCount; Index++) {
      gRuntimeServices->ConvertPointer (0, (VOID **)((UINT8 *)gSmiHobData + 8 + Index * 16));
    }
    gRuntimeServices->ConvertPointer (0, &gSmiHobData);
  }
}

//
// ===========================================================================
// Protocol Implementation
// ===========================================================================
//

/**
 * SMM Communication Protocol: Communicate handler.
 *
 * Handles communication with SMM code via the SMM Communication Protocol.
 * Validates the CommBuffer and CommSize, triggers SMI, and returns status.
 *
 * @param[in]      This       Pointer to the EFI_SMM_COMMUNICATION_PROTOCOL instance.
 * @param[in,out]  CommBuffer Pointer to the communication buffer.
 * @param[in,out]  CommSize   Pointer to the size of the communication buffer.
 *
 * @retval EFI_SUCCESS           SMI was triggered successfully.
 * @retval EFI_INVALID_PARAMETER Invalid parameter was provided.
 */
EFI_STATUS
EFIAPI
SmmCommunicationCommunicate (
  IN CONST EFI_SMM_COMMUNICATION_PROTOCOL  *This,
  IN OUT VOID                              *CommBuffer OPTIONAL,
  IN OUT UINTN                             *CommSize OPTIONAL
  )
{
  //
  // Defer to the non-periodic activation path
  //
  if (CommBuffer != NULL && CommSize != NULL) {
    return SmmControl2Handler (
             NULL,
             (UINT8 *)CommBuffer,
             (UINT8 *)CommSize,
             FALSE,
             FALSE
             );
  }

  return EFI_INVALID_PARAMETER;
}

/**
 * SMM Control2 Protocol: Activate/Trigger SMI.
 *
 * Triggers an SMI by:
 *   1. Clearing PM1 status and SMI status
 *   2. Setting the SMI control port to generate SMI
 *   3. Writing the command/data ports (0xB3/0xB2)
 *
 * @param[in]      This       Pointer to the EFI_SMM_CONTROL2_PROTOCOL instance.
 * @param[in,out]  CommandPort Optional command port value written to 0xB3.
 * @param[in,out]  DataPort    Optional data port value written to 0xB2.
 * @param[in]      Periodic   Whether periodic activation is requested (not supported).
 * @param[in]      Activation TRUE to activate, FALSE to deactivate.
 *
 * @retval EFI_SUCCESS           SMI was triggered.
 * @retval EFI_INVALID_PARAMETER Periodic is TRUE (not supported).
 * @retval EFI_DEVICE_ERROR      Failed to clear status registers.
 */
EFI_STATUS
EFIAPI
SmmControl2Handler (
  IN CONST EFI_SMM_CONTROL2_PROTOCOL  *This,
  IN OUT UINT8                        *CommandPort OPTIONAL,
  IN OUT UINT8                        *DataPort OPTIONAL,
  IN BOOLEAN                          Periodic OPTIONAL,
  IN BOOLEAN                          Activation OPTIONAL
  )
{
  EFI_STATUS  Status;
  UINT8       CommandValue;
  UINT8       DataValue;

  if (Periodic) {
    DEBUG ((DEBUG_ERROR, "Invalid parameter\n"));
    return EFI_INVALID_PARAMETER;
  }

  CommandValue = 0xFF;
  DataValue    = 0;

  if (CommandPort != NULL) {
    CommandValue = *CommandPort;
  }

  if (DataPort != NULL) {
    DataValue = *DataPort;
  }

  Status = SmiActivate ();
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Clear SMI status and trigger SMI via control port
  //
  IoWrite32 (gSmiIoPortBase + 48, IoRead32 (gSmiIoPortBase + 48) | 0x21);
  DEBUG ((
    DEBUG_INFO,
    "The SMI Control Port at address %x will be written to %x.\n",
    gSmiIoPortBase + 48,
    IoRead32 (gSmiIoPortBase + 48) | 0x21
    ));
  IoWrite32 (gSmiIoPortBase + 48, IoRead32 (gSmiIoPortBase + 48) | 0x21);

  //
  // Write SMI command and data ports
  //
  IoWrite8 (0xB3, DataValue);
  IoWrite8 (0xB2, CommandValue);

  return EFI_SUCCESS;
}

/**
 * SMM Control2 Protocol: Clear SMI status (empty -- deferred to activation).
 */
EFI_STATUS
EFIAPI
SmmControl2Clear (
  IN CONST EFI_SMM_CONTROL2_PROTOCOL  *This,
  IN BOOLEAN                          Periodic OPTIONAL
  )
{
  if (Periodic) {
    return EFI_INVALID_PARAMETER;
  }

  return SmiActivate ();
}

//
// ===========================================================================
// SMI Activation and Status Handling
// ===========================================================================
//

/**
 * Activate SMI -- clear PM1 and SMI status, enable SMI generation.
 */
EFI_STATUS
SmiActivate (
  VOID
  )
{
  UINT16  IoPortBase;
  UINT16  Pm1Status;
  UINT16  SmiStatus;

  IoPortBase = gSmiIoPortBase;

  DEBUG ((
    DEBUG_INFO,
    "The PM1 Status Port at address %x will be written to %x.\n",
    IoPortBase,
    0x800
    ));
  IoWrite16 (IoPortBase, 0x800);

  SmiStatus = IoPortBase + 52;
  DEBUG ((
    DEBUG_INFO,
    "The SMI Status Port at address %x will be written to %x.\n",
    SmiStatus,
    0x20
    ));
  IoWrite32 (SmiStatus, 0x20);

  DEBUG ((
    DEBUG_INFO,
    "The SMI Control Port at address %x will be written to %x.\n",
    IoPortBase + 48,
    IoRead32 (IoPortBase + 48) | 2
    ));
  IoWrite32 (IoPortBase + 48, IoRead32 (IoPortBase + 48) | 2);

  return EFI_SUCCESS;
}

//
// ===========================================================================
// GPE/SMI Status Initialization
// ===========================================================================
//

/**
 * Initialize GPE and SMI status registers during entry.
 */
VOID
SmiClearGpeStatus (
  VOID
  )
{
  UINT64                        GpeCount;
  UINT64                        SmiCount;
  PCM_PCI_SMI_CONTEXT           SmiContext;
  PCM_PCI_GPE_CONTEXT           GpeContext;
  UINT64                        Index;
  UINT16                        GpeBase;
  UINT16                        SmiBase;

  //
  // Check TCO status; if not set, reset PM1/GPE status
  //
  if ((IoRead16 (gSmiIoPortBase + 4) & 1) == 0) {
    //
    // Reset PM1 status registers
    //
    IoWrite16 (gSmiIoPortBase, 0xFFFF);
    IoWrite16 (gSmiIoPortBase + 2, 0);
    IoWrite16 (gSmiIoPortBase + 4, 0);

    //
    // Clear GPE status
    //
    IoWrite32 (gSmiIoPortBase + 140, 0xFFFFFDFF);
    IoWrite32 (gSmiIoPortBase + 156, 0x40000);
  }

  //
  // Enable all GPIO GPEs
  //
  GpeContext = (PCM_PCI_SMI_CONTEXT *)GetGpioGpeInfo (&GpeCount);
  if (GpeContext != NULL) {
    for (Index = 0; Index < GpeCount; Index++) {
      if (GpeContext[Index].GpeRegNum != -1) {
        *(volatile UINT32 *)(GpeContext[Index].GpioBaseAddr | ((GpeContext[Index].GpeReg | 0xFD00) << 16)) = 0;
      }
    }
  }

  //
  // Disable all GPIO SMIs
  //
  SmiContext = (PCM_PCI_SMI_CONTEXT *)GetGpioSmiInfo (&SmiCount);
  if (SmiContext != NULL) {
    for (Index = 0; Index < SmiCount; Index++) {
      if (SmiContext[Index].SmiRegNum != -1) {
        *(volatile UINT32 *)(SmiContext[Index].GpioBaseAddr | ((SmiContext[Index].SmiReg | 0xFD00) << 16)) = (UINT32)-1;
      }
    }
  }

  //
  // Disable GPE and SMI events on the SMI I/O port
  //
  GpeBase = gSmiIoPortBase + 68;
  SmiBase = gSmiIoPortBase + 52;

  IoWrite32 (GpeBase, 0xFFFF);
  IoWrite32 (SmiBase, 0xFFFFFFFF);

  IoWrite32 (gSmiIoPortBase + 48, (IoRead32 (gSmiIoPortBase + 48) & 0x80) | 0x21);
}

//
// ===========================================================================
// PCH Support and Detection
// ===========================================================================
//

/**
 * Get GPIO GPE information for this PCH SKU.
 *
 * @param[out]  Count  Number of GPE entries.
 *
 * @return Pointer to the GPE context array, or NULL if unsupported.
 */
VOID *
GetGpioGpeInfo (
  OUT UINT64  *Count
  )
{
  UINT16  LpcDeviceId;

  if (gCmCpuCount == 2) {
    LpcDeviceId = MmioRead16 ((UINT16 *)(PchLpcMmioRead (0) + 2));
    if (((LpcDeviceId + 24128) & 0xFF70) != 0) {
      DEBUG ((DEBUG_ERROR, "Unsupported PCH SKU, LpcDeviceId: 0x%04x!\n", LpcDeviceId));
      ASSERT (FALSE);
    } else {
      gCmCpuCount = 1;
    }
  }

  if (gCmCpuCount == 1) {
    *Count = 13;
    return &gGpioGpeInfoTable;
  }

  *Count = 0;
  return NULL;
}

/**
 * Read a register via MM PCI from PCH LPC bridge.
 *
 * @param[in]  Offset  Register offset in LPC config space.
 *
 * @return 64-bit MMIO address for the register.
 */
UINT64
PchLpcMmioRead (
  IN UINT16  Offset
  )
{
  UINT64  Address;
  UINT32  Bar;
  UINT32  Data;

  Address = MmPciBase (
              DEFAULT_PCI_BUS_NUMBER,
              PCI_DEVICE_NUMBER_PCH_LPC,
              PCI_FUNCTION_NUMBER_PCH_LPC,
              0
              );
  //
  // Build a temporary MMIO address to read from LPC
  //
  Data = MmioRead32 ((UINT32 *)(UINTN)Address);
  return MmioRead32 ((UINT32 *)(UINTN)(Address + Offset));
}

//
// ===========================================================================
// PCD and Protocol Location Helpers
// ===========================================================================
//

/**
 * Locate a protocol by GUID.
 */
EFI_STATUS
LocateProtocol (
  IN  EFI_GUID  *ProtocolGuid,
  OUT VOID      **Interface
  )
{
  return gBootServices->LocateProtocol (ProtocolGuid, NULL, Interface);
}

/**
 * Compare two GUIDs (via ReadUnaligned64).
 */
BOOLEAN
CompareGuid (
  IN EFI_GUID  *Guid1,
  IN EFI_GUID  *Guid2
  )
{
  return ReadUnaligned64 (Guid1) == ReadUnaligned64 (Guid2) &&
         ReadUnaligned64 ((UINT8 *)Guid1 + 8) == ReadUnaligned64 ((UINT8 *)Guid2 + 8);
}

/**
 * Read unaligned 64-bit value (via BaseLib).
 */
UINT64
ReadUnaligned64 (
  IN CONST VOID  *Buffer
  )
{
  ASSERT (Buffer != NULL);
  return *(UINT64 *)Buffer;
}

/**
 * Read unaligned 64-bit value at offset 8.
 */
UINT64
ReadUnaligned64At8 (
  IN CONST VOID  *Buffer
  )
{
  return ReadUnaligned64 ((UINT8 *)Buffer + 8);
}

//
// ===========================================================================
// Configuration Table Lookup
// ===========================================================================
//

/**
 * Locate a configuration table by GUID.
 *
 * @param[in]   TableGuid  GUID of the table to find.
 * @param[out]  Table      Pointer to receive the table pointer.
 *
 * @retval EFI_SUCCESS           Table found.
 * @retval EFI_NOT_FOUND         Table not found.
 * @retval EFI_INVALID_PARAMETER Invalid parameter.
 */
EFI_STATUS
GetConfigurationTable (
  IN  EFI_GUID  *TableGuid,
  OUT VOID      **Table
  )
{
  EFI_STATUS       Status;
  UINTN            Index;
  EFI_CONFIGURATION_TABLE  *ConfigTable;

  if (TableGuid == NULL) {
    ASSERT (TableGuid != NULL);
    return EFI_INVALID_PARAMETER;
  }

  if (Table == NULL) {
    ASSERT (Table != NULL);
    return EFI_INVALID_PARAMETER;
  }

  *Table = NULL;

  if (gSystemTable->NumberOfTableEntries == 0) {
    return EFI_NOT_FOUND;
  }

  ConfigTable = (EFI_CONFIGURATION_TABLE *)gSystemTable->ConfigurationTable;
  for (Index = 0; Index < gSystemTable->NumberOfTableEntries; Index++) {
    if (CompareGuid (TableGuid, &ConfigTable[Index].VendorGuid)) {
      *Table = ConfigTable[Index].VendorTable;
      return EFI_SUCCESS;
    }
  }

  return EFI_NOT_FOUND;
}

/**
 * Initialize HOB list pointer from configuration table.
 */
EFI_STATUS
InitHobList (
  VOID
  )
{
  EFI_STATUS  Status;

  if (gHobList == NULL) {
    Status = GetConfigurationTable (&gEfiHobListGuid, &gHobList);
    if (EFI_ERROR (Status)) {
      DEBUG ((DEBUG_ERROR, ASSERT_EFI_ERROR (Status)));
      ASSERT (!EFI_ERROR (Status));
    }

    if (gHobList == NULL) {
      ASSERT (gHobList != NULL);
    }
  }

  return EFI_SUCCESS;
}

/**
 * Initialize PCD database pointer.
 */
EFI_STATUS
InitPcdDb (
  VOID
  )
{
  EFI_STATUS  Status;

  if (gPcdDb == NULL) {
    Status = LocateProtocol (&gEfiPcdProtocolGuid, &gPcdDb);
    if (EFI_ERROR (Status)) {
      DEBUG ((DEBUG_ERROR, ASSERT_EFI_ERROR (Status)));
      ASSERT (!EFI_ERROR (Status));
    }

    if (gPcdDb == NULL) {
      ASSERT (gPcdDb != NULL);
    }
  }

  return EFI_SUCCESS;
}

/**
 * Initialize MM PCI base library protocol.
 */
EFI_STATUS
InitMmPciBase (
  VOID
  )
{
  EFI_STATUS  Status;

  //
  // Locate MM_PCI_USRA protocol if needed
  //
  if (gMmPciUsra == NULL) {
    Status = gBootServices->LocateProtocol (&gEfiMmPciUsraProtocolGuid, NULL, &gMmPciUsra);
    if (EFI_ERROR (Status)) {
      DEBUG ((DEBUG_ERROR, ASSERT_EFI_ERROR (Status)));
      ASSERT (!EFI_ERROR (Status));
    }
    if (gMmPciUsra == NULL) {
      ASSERT (gMmPciUsra != NULL);
    }
  }

  return EFI_SUCCESS;
}

/**
 * Get the current PCD pointer via the PCD protocol.
 */
EFI_STATUS
GetPcdProtocol (
  VOID
  )
{
  return InitPcdDb ();
}

//
// ===========================================================================
// Driver Entry Point and Initialization
// ===========================================================================
//

/**
 * UEFI Driver Entry Point.
 *
 * Initializes global state, locates protocols, registers events, and
 * installs SMM Control2 and SMM Communication protocols.
 */
EFI_STATUS
EFIAPI
SmmControlDriverEntryInit (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS                    Status;
  EFI_BOOT_SERVICES             *BootServices;
  SMM_CONTROL_DRIVER_PRIVATE    *Private;
  VOID                          *Registration;

  gImageHandle  = ImageHandle;
  gSystemTable  = SystemTable;
  gBootServices = SystemTable->BootServices;
  gRuntimeServices = SystemTable->RuntimeServices;

  //
  // Assert required pointers
  //
  ASSERT (gImageHandle != NULL);
  ASSERT (gSystemTable != NULL);
  ASSERT (gBootServices != NULL);
  ASSERT (gRuntimeServices != NULL);

  //
  // Initialize the PCH SMI I/O base address from the HOB
  // and configure the SMI I/O ports
  //
  Status = SmmControlDriverEntryInit ();
  if (EFI_ERROR (Status)) {
    goto Unload;
  }

  return Status;

Unload:
  SmmControlDriverUnload ();
  return Status;
}

/**
 * Driver initialization after entry point (main init body).
 *
 * Determines the SMI I/O port base from PCH LPC decode, sets up protocol
 * interfaces, registers SMI control events, and initializes GPIO/SMI status.
 */
EFI_STATUS
SmmControlDriverEntryInit (
  VOID
  )
{
  EFI_STATUS  Status;
  UINT16      LpcDecode;
  UINT16      IoPortBase;
  UINT64      SmiControlAddr;

  DEBUG ((DEBUG_INFO, "SmmControlDriverEntryInit() Start\n"));

  Status = EFI_SUCCESS;

  //
  // Read LPC I/O decode registers via MMIO to get SMI port base
  //
  IoPortBase = MmioRead16 ((UINT16 *)(PchLpcMmioRead (2)));
  LpcDecode  = MmioRead16 ((UINT16 *)(PchLpcMmioRead (2) + 64));

  if (MmioRead16 ((UINT16 *)(UINTN)(PchLpcMmioRead (0) + 64)) == 0xFFFF) {
    //
    // PCH not initialized yet -- should not happen
    //
    ASSERT (FALSE);
    gSmiIoPortBase = LpcDecode & 0xFFFC;
  } else {
    gSmiIoPortBase = LpcDecode & 0xFFFC;
  }

  if (gSmiIoPortBase == 0) {
    DEBUG ((DEBUG_ERROR, "SMI I/O port base is zero -- PCH not initialized.\n"));
    return EFI_NOT_READY;
  }

  //
  // Initialize protocol structures
  //
  gSmiControlAddress       = 0;
  gSmmControl2             = &gSmmControl2Protocol;
  gSignature               = SIGNATURE_32 ('p', 'm', 's', 'c');
  gSmmCommunication        = &gSmmCommunicationProtocol;
  gSmmImageHandle          = ImageHandle;

  //
  // Register SMI HOB notification protocol
  //
  BootServices->RegisterProtocolNotify (
                  &gSmiHobGuid,
                  &gSmiImageHandle,
                  &gSmmControl2,
                  NULL
                  );

  //
  // Register EFI virtual address change event
  //
  Status = gBootServices->CreateEvent (
                            EVT_NOTIFY_SIGNAL,
                            TPL_NOTIFY,
                            OnVirtualAddrChange,
                            NULL,
                            &gEventVirtualAddrChange
                            );
  ASSERT_EFI_ERROR (Status);

  //
  // Initialize GPIO/SMI status
  //
  SmiInitGpe ();

  DEBUG ((DEBUG_INFO, "SmmControlDriverEntryInit() End\n"));

  return Status;
}

/**
 * Driver unload handler.
 *
 * Frees allocated resources including SMI HOB data, event handles,
 * and protocol interfaces.
 */
EFI_STATUS
SmmControlDriverUnload (
  VOID
  )
{
  //
  // Free SMI HOB data if allocated
  //
  if (gSmiHobData != NULL) {
    OnSmiHobCleanup ();
  }

  //
  // Close all registered events
  //
  if (gEventVirtualAddrChange != NULL) {
    gBootServices->CloseEvent (gEventVirtualAddrChange);
  }

  if (gEventRestoreTpl != NULL) {
    gBootServices->CloseEvent (gEventRestoreTpl);
  }

  if (gEventRuntimeReady != NULL) {
    gBootServices->CloseEvent (gEventRuntimeReady);
  }

  if (gEventNotify != NULL) {
    gBootServices->CloseEvent (gEventNotify);
  }

  //
  // Free PciExpress protocol registration
  //
  if (gPcdDb != NULL) {
    gBootServices->CloseEvent ((EFI_EVENT)gPcdDb);
  }

  return EFI_SUCCESS;
}

//
// ===========================================================================
// PCI Express Library Initialization
// ===========================================================================
//

/**
 * Initialize PCI Express library -- locate and register protocol notify
 * for PCI Express protocol.
 */
EFI_STATUS
PciExpressInit (
  VOID
  )
{
  EFI_STATUS  Status;
  EFI_EVENT   Event;

  //
  // Register for protocol notify on the MM-PCI USRA protocol
  //
  Status = gBootServices->CreateEvent (
                            EVT_NOTIFY_SIGNAL,
                            TPL_CALLBACK,
                            OnPciExpressProtocolInstall,
                            NULL,
                            &Event
                            );
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, ASSERT_EFI_ERROR (Status)));
    ASSERT (!EFI_ERROR (Status));
  }

  return Status;
}