Newer
Older
AMI-Aptio-BIOS-Reversed / PurleyPlatPkg / Legacy / Dxe / LegacyInterrupt / LegacyInterrupt.c
@Ajax Dong Ajax Dong 2 days ago 13 KB Full restructure
/** @file
  LegacyInterrupt.c - Purley/Lewisburg PCH Legacy Interrupt DXE driver.

  Installs the EFI_LEGACY_INTERRUPT_PROTOCOL for managing legacy
  PCI interrupt routing on Intel Purley (Lewisburg PCH) platforms.

  Source: PurleySktPkg/SouthClusterLbg/LegacyInterrupt/Dxe/
  Image:  0123_LegacyInterrupt.efi
*/

#include "LegacyInterrupt.h"

//
// GUID definitions used by this module
//
// 0x12c0 - Unknown vendor GUID
// 0x12d0 - gMmPciUsraProtocolGuid (from CpRcPkg/DxeMmPciBaseLib)
// 0x12e0 - gEfiPcdProtocolGuid    (11B34006-D85B-4D0A-A290-D5A571310EF7)
// 0x12f0 - gEfiLegacyInterruptProtocolGuid (31CE593D-108A-485D-ADB2-78F21F2966BE)
// 0x1300 - gEfiHobListGuid        (7739F24C-93D7-11D4-9A3A-0090273FC14D)
// 0x1310 - gEfiDxeServicesTableGuid (05AD34BA-6F02-4214-952E-4DA0398E2BB9)

//
// Function pointer table for LegacyInterrupt protocol
// (at offset 0x1320 in .data)
//
STATIC CONST LEGACY_INTERRUPT_PROTOCOL_INSTANCE mLegacyInterruptInterface = {
  LegacyInterruptGetStatus,   // offset 0x1320 -> 0x638
  LegacyInterruptGetVector,   // offset 0x1328 -> 0x640
  LegacyInterruptReadVector,  // offset 0x1330 -> 0x650
  LegacyInterruptWriteVector  // offset 0x1338 -> 0x680
};

//
// Global state variables
//
// 0x1340 - mPchStepping (UINT8, initially 3 = PCH_STEPPING_UNKNOWN)
// 0x1348 - Protocol image handle (initially NULL)
//
STATIC UINT8  mPchStepping = PCH_STEPPING_UNKNOWN;

#pragma section(".data", read, write)

//
// Library constructor - initializes UEFI boot/libraries
//
EFI_STATUS
EFIAPI
LibConstructor (
  IN EFI_HANDLE         ImageHandle,
  IN EFI_SYSTEM_TABLE   *SystemTable
  )
{
  EFI_STATUS  Status;

  // Save globals
  gImageHandle = ImageHandle;
  if (ImageHandle == NULL) {
    DebugAssert (__FILE__, __LINE__, "gImageHandle != ((void *) 0)");
  }

  gSystemTable = SystemTable;
  if (SystemTable == NULL) {
    DebugAssert (__FILE__, __LINE__, "gST != ((void *) 0)");
  }

  gBootServices = SystemTable->BootServices;
  if (gBootServices == NULL) {
    DebugAssert (__FILE__, __LINE__, "gBS != ((void *) 0)");
  }

  gRuntimeServices = SystemTable->RuntimeServices;
  if (gRuntimeServices == NULL) {
    DebugAssert (__FILE__, __LINE__, "gRT != ((void *) 0)");
  }

  // Get DxeServicesTable from system configuration
  Status = EfiGetSystemConfigurationTable (
             &gEfiDxeServicesTableGuid,
             (VOID **)&gDxeServicesTable
             );
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
    DebugAssert (__FILE__, __LINE__, "!EFI_ERROR (Status)");
  }
  if (gDxeServicesTable == NULL) {
    DebugAssert (__FILE__, __LINE__, "gDS != ((void *) 0)");
  }

  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
    DebugAssert (__FILE__, __LINE__, "!EFI_ERROR (Status)");
  }

  // Locate MmPciUsra protocol (for PCI config access via MMIO)
  if (mPciUsra == NULL) {
    Status = gBootServices->LocateProtocol (
                              &gMmPciUsraProtocolGuid,
                              NULL,
                              &mPciUsra
                              );
    if (EFI_ERROR (Status)) {
      DEBUG ((DEBUG_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
      DebugAssert (__FILE__, __LINE__, "!EFI_ERROR (Status)");
    }
    if (mPciUsra == NULL) {
      DebugAssert (__FILE__, __LINE__, "mPciUsra != ((void *) 0)");
    }
  }

  // Get HOB list
  GetHobList ();

  // Get PCD protocol
  mPcd = GetPcdProtocol ();

  // Read PCD: PcdLegacyInterruptPchStepping (token=5)
  return PcdGet8 (5);
}

//
// Install the LegacyInterrupt protocol
//
EFI_STATUS
LegacyInterruptInstall (
  VOID
  )
{
  EFI_STATUS  Status;

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

  // Check if protocol already installed
  Status = gBootServices->LocateProtocol (
                            &gEfiLegacyInterruptProtocolGuid,
                            NULL,
                            (VOID **)&mLegacyInterruptInterface
                            );
  if (!EFI_ERROR (Status)) {
    DebugAssert (
      __FILE__,
      178,
      "&gEfiLegacyInterruptProtocolGuid already installed in database"
      );
  }

  // Install protocol interface
  Status = gBootServices->InstallProtocolInterface (
                            &gImageHandle,
                            &gEfiLegacyInterruptProtocolGuid,
                            EFI_NATIVE_INTERFACE,
                            (VOID *)&mLegacyInterruptInterface
                            );
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
    DebugAssert (__FILE__, 189, "!EFI_ERROR (Status)");
  }

  DEBUG ((DEBUG_INFO, "LegacyInterruptInstall() End\n"));
  return Status;
}

//
// EFI_LEGACY_INTERRUPT_PROTOCOL.GetStatus
//
EFI_STATUS
EFIAPI
LegacyInterruptGetStatus (
  IN     EFI_LEGACY_INTERRUPT_PROTOCOL  *This,
  OUT    UINT8                          *Status
  )
{
  *Status = 8;  // PIC mode, 8 IRQ lines active
  return EFI_SUCCESS;
}

//
// EFI_LEGACY_INTERRUPT_PROTOCOL.GetVector
//
EFI_STATUS
EFIAPI
LegacyInterruptGetVector (
  IN     EFI_LEGACY_INTERRUPT_PROTOCOL  *This,
  OUT    UINT8                          *Vector,
  OUT    UINT8                          *LevelMask,
  OUT    UINT8                          *LevelSense
  )
{
  *Vector    = 0;   // Default IRQ0
  *LevelMask = 31;  // All IRQs level-triggered (bitmask: IRQ0-IRQ4)
  *LevelSense = 0;  // Active high
  return EFI_SUCCESS;
}

//
// EFI_LEGACY_INTERRUPT_PROTOCOL.ReadVector
//
EFI_STATUS
EFIAPI
LegacyInterruptReadVector (
  IN     EFI_LEGACY_INTERRUPT_PROTOCOL  *This,
  IN     UINT8                          Vector,
  OUT    UINT8                          *Value
  )
{
  if (Vector >= 8) {
    return EFI_INVALID_PARAMETER;
  }

  // Read from LPC interrupt control register
  *Value = MmioRead8 (LPC_ADDR (Vector + LEGACY_INTERRUPT_BASE_PORT)) & 0x7F;
  return EFI_SUCCESS;
}

//
// EFI_LEGACY_INTERRUPT_PROTOCOL.WriteVector
//
EFI_STATUS
EFIAPI
LegacyInterruptWriteVector (
  IN     EFI_LEGACY_INTERRUPT_PROTOCOL  *This,
  IN     UINT8                          Vector,
  IN     UINT8                          Value
  )
{
  if (Vector >= 8) {
    return EFI_INVALID_PARAMETER;
  }

  LpcWriteRegister (
    (UINT16)(Vector + LEGACY_INTERRUPT_BASE_PORT),
    Value
    );
  return EFI_SUCCESS;
}

//
// Write to LPC register via MMIO
//
VOID
LpcWriteRegister (
  UINT16  Offset,
  UINT8   Value
  )
{
  // Call PCH detection (lazy init)
  PchGetStepping ();

  // Write MMIO register in LPC bridge space
  MmioWrite8 (LPC_ADDR (Offset), Value);
}

//
// Get the DebugOutput protocol instance (lazy init)
//
VOID *
GetDebugOutputProtocol (
  VOID
  )
{
  UINTN   Pages;
  EFI_STATUS Status;

  if (mDebugOutputProtocol == NULL) {
    Pages = gBootServices->GetMemoryMap (&Pages, NULL, NULL, NULL, NULL);
    gBootServices->AllocatePool (EfiBootServicesData, Pages, &mMemoryMapBuffer);

    if (Pages <= 16) {
      Status = gBootServices->LocateProtocol (
                                &gEfiDebugOutputProtocolGuid,
                                NULL,
                                &mDebugOutputProtocol
                                );
      if (EFI_ERROR (Status)) {
        mDebugOutputProtocol = NULL;
      }
      return mDebugOutputProtocol;
    }
    return NULL;
  }
  return mDebugOutputProtocol;
}

//
// Debug print function with board/platform detection
//
UINT8
DebugPrint (
  IN UINTN        ErrorLevel,
  IN CONST CHAR8  *Format,
  ...
  )
{
  VA_LIST                         Marker;
  EFI_DEBUG_OUTPUT_PROTOCOL       *DebugProtocol;
  UINT64                          DebugMask;
  UINT8                           NmiValue;
  UINT8                           BoardType;

  DebugProtocol = (EFI_DEBUG_OUTPUT_PROTOCOL *)GetDebugOutputProtocol ();
  DebugMask = 0;

  if (DebugProtocol != NULL) {
    // Read CMOS status for board detection
    NmiValue = IoRead8 (RTC_INDEX_PORT);
    IoWrite8 (RTC_INDEX_PORT, (NmiValue & RTC_NMI_MASK) | RTC_INDEX_NMI_DISABLE);
    BoardType = IoRead8 (RTC_DATA_PORT);

    if (BoardType > 3) {
      if (BoardType == 0) {
        BoardType = (IoRead8 ((UINT8 *)0xFDAF0490) & 2) | 1;
      }
    }

    if ((BoardType - 1) <= 0xFD) {
      DebugMask = 0x80000000;
      if (BoardType == 1) {
        DebugMask = 0x80000004;
      }
    }

    if ((DebugMask & ErrorLevel) != 0) {
      VA_START (Marker, Format);
      DebugProtocol->OutputString (ErrorLevel, Format, Marker);
      VA_END (Marker);
    }
  }
}

//
// Debug assert handler
//
VOID
DebugAssert (
  IN CONST CHAR8  *FileName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *Description
  )
{
  VOID *DebugProtocol;

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

//
// Read 16-bit value from I/O port
//
UINT16
EFIAPI
IoRead16 (
  IN UINT16  *Address
  )
{
  if (((UINTN)Address & 1) != 0) {
    DebugAssert (__FILE__, 151, "(Address & 1) == 0");
  }
  return *Address;
}

//
// Get system configuration table by GUID
//
EFI_STATUS
EfiGetSystemConfigurationTable (
  IN EFI_GUID  *TableGuid,
  OUT VOID     **Table
  )
{
  UINTN       Index;
  UINTN       NumberOfEntries;
  EFI_CONFIGURATION_TABLE  *ConfigurationTable;

  if (TableGuid == NULL) {
    DebugAssert (__FILE__, 97, "TableGuid != ((void *) 0)");
  }
  if (Table == NULL) {
    DebugAssert (__FILE__, 98, "Table != ((void *) 0)");
  }

  *Table = NULL;
  NumberOfEntries = gSystemTable->NumberOfTableEntries;
  ConfigurationTable = gSystemTable->ConfigurationTable;

  if (ConfigurationTable == NULL) {
    return EFI_NOT_FOUND;
  }

  for (Index = 0; Index < NumberOfEntries; Index++) {
    if (CompareGuid (TableGuid, &ConfigurationTable[Index].VendorGuid)) {
      *Table = ConfigurationTable[Index].VendorTable;
      return EFI_SUCCESS;
    }
  }

  return EFI_NOT_FOUND;
}

//
// MMIO PCI config read (via MmPciUsra protocol)
//
UINT32
MmPciReadConfig (
  VOID
  )
{
  UINT32  PciAddress[6];

  PciAddress[0] = 0xF8000;      // Base address
  PciAddress[1] = 0;            // Bus 0
  PciAddress[2] = 0x200;        // Device 0x20, Func 0
  PciAddress[3] = 0;

  // Call into MmPciUsra protocol
  return ((MM_PCI_USRA_PROTOCOL *)mPciUsra)->ReadConfig (PciAddress);
}

//
// Get HOB list pointer
//
VOID *
GetHobList (
  VOID
  )
{
  EFI_STATUS  Status;

  if (mHobList == NULL) {
    Status = EfiGetSystemConfigurationTable (
               &gEfiHobListGuid,
               &mHobList
               );
    if (EFI_ERROR (Status)) {
      DEBUG ((DEBUG_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
      DebugAssert (__FILE__, 54, "!EFI_ERROR (Status)");
    }
    if (mHobList == NULL) {
      DebugAssert (__FILE__, 55, "mHobList != ((void *) 0)");
    }
  }

  return mHobList;
}

//
// Get PCD protocol pointer
//
PCD_PROTOCOL *
GetPcdProtocol (
  VOID
  )
{
  EFI_STATUS  Status;

  if (mPcd == NULL) {
    Status = gBootServices->LocateProtocol (
                              &gEfiPcdProtocolGuid,
                              NULL,
                              (VOID **)&mPcd
                              );
    if (EFI_ERROR (Status)) {
      DEBUG ((DEBUG_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
      DebugAssert (__FILE__, 78, "!EFI_ERROR (Status)");
    }
    if (mPcd == NULL) {
      DebugAssert (__FILE__, 79, "mPcd != ((void *) 0)");
    }
  }

  return mPcd;
}

//
// Compare two GUIDs (via unaligned 64-bit read)
//
BOOLEAN
CompareGuid (
  IN EFI_GUID  *Guid1,
  IN EFI_GUID  *Guid2
  )
{
  UINT64  Guid1Low;
  UINT64  Guid1High;
  UINT64  Guid2Low;
  UINT64  Guid2High;

  // Read as 64-bit values (handles unaligned)
  Guid1Low  = ReadUnaligned64 (Guid1);
  Guid1High = ReadUnaligned64 ((VOID *)((UINT8 *)Guid1 + 8));
  Guid2Low  = ReadUnaligned64 (Guid2);
  Guid2High = ReadUnaligned64 ((VOID *)((UINT8 *)Guid2 + 8));

  return (Guid1Low == Guid2Low && Guid1High == Guid2High);
}

//
// Determine PCH stepping based on LPC device ID
//
UINT8
PchGetStepping (
  VOID
  )
{
  UINT32  PciData;
  UINT16  LpcDeviceId;

  if (mPchStepping == PCH_STEPPING_UNKNOWN) {
    // Read LPC device ID via MMIO PCI config
    PciData = MmPciReadConfig ();
    LpcDeviceId = IoRead16 ((UINT16 *)(PciData + 2));

    if (((LpcDeviceId + 0x5E40) & LPC_DEVICE_ID_H_MASK) != 0) {
      // Check if LP-series
      if ((UINT16)(LpcDeviceId + 0x62C0) <= 8) {
        // Bit test: LPC device IDs matching LP
        mPchStepping = PCH_STEPPING_LP;
      } else {
        DEBUG ((DEBUG_ERROR, "Unsupported PCH SKU, LpcDeviceId: 0x%04x!\n", LpcDeviceId));
        DebugAssert (__FILE__, 252, "((BOOLEAN)(0==1))");
      }
    } else {
      mPchStepping = PCH_STEPPING_H;
    }
  }

  return mPchStepping;
}

//
// Read unaligned 64-bit value
//
UINT64
ReadUnaligned64 (
  IN CONST VOID  *Buffer
  )
{
  if (Buffer == NULL) {
    DebugAssert (__FILE__, 192, "Buffer != ((void *) 0)");
  }
  return *(const UINT64 *)Buffer;
}

//
// Driver entry point
//
EFI_STATUS
EFIAPI
LegacyInterruptEntryPoint (
  IN EFI_HANDLE         ImageHandle,
  IN EFI_SYSTEM_TABLE   *SystemTable
  )
{
  EFI_STATUS  Status;

  Status = LibConstructor (ImageHandle, SystemTable);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = LegacyInterruptInstall ();
  return Status;
}