Newer
Older
AMI-Aptio-BIOS-Reversed / OpromUpdateDxeLightningRidgeEXECB2 / OpromUpdateDxeLightningRidgeEXECB2.c
@Ajax Dong Ajax Dong 2 days ago 29 KB Init
/**
 * @file OpromUpdateDxeLightningRidgeEXECB2.c
 * @brief UBA OpromUpdate DXE driver for the LightningRidge (C621/C622) EXEC B2 board.
 *
 * This driver is part of Intel's UBA (Unified BIOS Architecture) OpromUpdate subsystem.
 * It provides board-specific PCIe slot configuration data and population detection
 * for the LightningRidge PCH (Lewisburg/C620 series) EXEC B2 server board variant.
 *
 * The driver is tiny (< 4KB) and stateless. All its data is baked into the .rdata/.data
 * sections. It does not install any protocols -- instead, it registers callbacks with
 * the UBA Config Protocol so that the OpromUpdate DXE driver can call back into this
 * board-specific implementation when it needs slot/port information.
 */

#include "OpromUpdateDxeLightningRidgeEXECB2.h"

//=============================================================================
// GUID Instances
//=============================================================================

///
/// EFI_PCI_IO_PROTOCOL GUID - used to read PCI config space via LocateProtocol
/// {2f707ebb-4a1a-11d4-9a38-0090273fc14d}
/// Reference at .rdata:0xCE0
///
STATIC CONST EFI_GUID  mEfiPciIoProtocolGuid = EFI_PCI_IO_PROTOCOL_GUID;

///
/// UBA Debug Protocol GUID - used to locate the debug output protocol
/// {36232936-0e76-31c8-a13a-3af2fc1c3932}
/// Reference at .rdata:0xCF0
///
STATIC CONST EFI_GUID  mUbaDebugProtocolGuid = UBA_DEBUG_PROTOCOL_GUID;

///
/// UBA Config Protocol GUID - main protocol for registering board config
/// {e03e0d46-5263-4845-b0a4-58d57b3177e2}
/// Reference at .rdata:0xD00
///
STATIC CONST EFI_GUID  mUbaConfigProtocolGuid = UBA_CONFIG_PROTOCOL_GUID;

///
/// EFI Guided Section Extraction Protocol GUID (unused by this driver)
/// {7739f24c-93d7-11d4-9a3a-0090273fc14d}
/// Reference at .rdata:0xD10
///
STATIC CONST EFI_GUID  mEfiGuidedSectionExtractionProtocolGuid =
  EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID;

//
// NOTE: mEfiGuidedSectionExtractionProtocolGuid is stored at 0xD10 in the
// .rdata section but is NOT referenced by any code in this driver. It may
// be used by the UBA framework or by external consumers of the data section.
//

///
/// OpromUpdate LightningRidge EXEC B2 Board Registration GUID
/// {371bd79c-de79-4c5f-aa2b-bc9ebefa988f}
/// Reference at .rdata:0xEF0
///
STATIC CONST EFI_GUID  mOpromUpdateBoardGuid = OPROM_UPDATE_BOARD_GUID;

//=============================================================================
// PCIe Root Port BDF Lookup Table (.data@0xED1)
//=============================================================================

///
/// PCIe Root Port BDF lookup table.
/// Maps 8 PCIe root port indices to Bus:Device:Function addresses.
/// Used by IsFunctionInPopulatedSlot() to locate root port config space.
///
/// Format: each entry is a 3-byte descriptor (at stride 4):
///   byte 0 = Register offset (in the encoding: shifted to bits [15:8])
///   byte 1 = [2:0]=Function, [7:3]=Device (in the encoding: shifted to bits [23:16])
///   byte 2 = Bus number (in the encoding: shifted to bits [31:24])
///
/// The "in the encoding" means combined as:
///   EFI_PCI_IO_PROTOCOL_PCI_ADDRESS(Bus, Dev, Func, Reg) =
///     Reg | (Func << 8) | (Dev << 11) | (Bus << 16) | BIT28 (extended cfg)
///
/// Decoded entries (from 0xED1 data):
///   Entry 0: { 0x00, 0x03, 0x00 } -> B=0  D=0 F=3  Reg=0x00  (PCH internal)
///   Entry 1: { 0x00, 0x01, 0x80 } -> B=128 D=0 F=1  Reg=0x00  (PCIe domain)
///   Entry 2: { 0x00, 0x02, 0x80 } -> B=128 D=0 F=2  Reg=0x00  (PCIe domain)
///   Entry 3: { 0x02, 0x03, 0x80 } -> B=128 D=0 F=3  Reg=0x02  (PCIe domain)
///   Entry 4: { 0x00, 0x02, 0x00 } -> B=0  D=0 F=2  Reg=0x00  (PCH internal)
///   Entry 5: { 0x00, 0x01, 0x00 } -> B=0  D=0 F=1  Reg=0x00  (PCH internal)
///   Entry 6: { 0x05, 0x1c, 0x00 } -> B=0  D=3 F=4  Reg=0x05  (PCH internal)
///   Entry 7: { 0x00, 0x03, 0x80 } -> B=128 D=0 F=3  Reg=0x00  (PCIe domain, dup)
///
/// Bus 0x80 (128) entries are in the PCIe domain range (typically bus 128+).
/// Bus 0 entries are PCH-internal PCIe root ports in the legacy bus 0 range.
///
STATIC CONST UINT8  mPcieRootPortBdfTable[MAX_PCIE_ROOT_PORTS * 4] __attribute__((aligned(4))) = {
  // Each entry: { RegOffset, DevFunc, Bus, Pad } (4 bytes)
  0x00, 0x03, 0x00, 0x00,   // Entry 0
  0x00, 0x01, 0x80, 0x00,   // Entry 1
  0x00, 0x02, 0x80, 0x00,   // Entry 2
  0x02, 0x03, 0x80, 0x00,   // Entry 3
  0x00, 0x02, 0x00, 0x00,   // Entry 4
  0x00, 0x01, 0x00, 0x00,   // Entry 5
  0x05, 0x1C, 0x00, 0x00,   // Entry 6
  0x00, 0x03, 0x80, 0x00    // Entry 7
};

//=============================================================================
// PCIe Slot Configuration Tables (.data section)
//=============================================================================

///
/// PCIe Slot Configuration Table 1 (at .data@0xD60).
/// Contains 6 entries describing PCIe slot-to-BDF mappings.
///
/// Each entry encodes slot port info, capability flags, and PCI address.
/// Used by GetSlotConfig1() callback.
///
STATIC CONST PCIE_SLOT_CONFIG_ENTRY  mSlotConfigTable1[MAX_SLOT_CONFIG1_ENTRIES] = {
  { 0x00000001, 0x00020001, 0x15288086 },
  { 0x48010802, 0x01000000, 0x0000002D },
  { 0x00000001, 0x0000002C, 0x00000001 },
  { 0xFF2FFF2E, 0x00000100, 0x02000100 },
  { 0x21808600, 0x01010215, 0x00000048 },
  { 0x00002D01, 0x00000100, 0x00002C00 }
};

///
/// PCIe Slot Configuration Table 2 (at .data@0xE60).
/// Contains 10 entries describing additional PCIe slot-to-BDF mappings.
///
/// Used by GetSlotConfig2() callback.
///
STATIC CONST PCIE_SLOT_CONFIG_ENTRY  mSlotConfigTable2[MAX_SLOT_CONFIG2_ENTRIES] = {
  { 0x358010D3, 0x00010100, 0x15210000 },
  { 0x01003580, 0x00000001, 0x35B01521 },
  { 0x00010100, 0x15220000, 0x01003580 },
  { 0x00000001, 0x35561521, 0x00010100 },
  { 0x10FB0000, 0x01013557, 0x00000101 },
  { 0x35581528, 0x01010101, 0x15280000 },
  { 0x010135C5, 0x00000101, 0x10031003 },
  { 0x00000000, 0x15280001, 0x010135A0 },
  { 0x00000101, 0x00000000, 0x00000000 },
  { 0x03000000, 0x01000000, 0x02000080 }
};

//=============================================================================
// Empty Board Info Structure (.data@0xD20)
//=============================================================================

///
/// Empty board info structure. LightningRidge EXEC B2 does not provide
/// any additional board-specific data beyond the PCIe slot config tables.
///
STATIC CONST UINT64  mEmptyBoardInfo[8] = { 0 };

//=============================================================================
// PBDS Board Config Registration Structure (.data@0xEF0)
//=============================================================================

///
/// PBDS board config registration structure.
/// Contains the board GUID and 4 callback function RVAs.
/// Registered with UBA Config Protocol at driver entry.
///
/// Layout (48 bytes):
///   offset 0:  Board GUID (OPROM_UPDATE_BOARD_GUID, 16 bytes)
///   offset 16: PBDS_CONFIG_SIGNATURE ("PBDS", 4 bytes)
///   offset 20: Version (1, 4 bytes)
///   offset 24: Callback 0 - IsFunctionInPopulatedSlot (8 bytes, relocatable RVA)
///   offset 32: Callback 1 - GetBoardInfo (8 bytes, relocatable RVA)
///   offset 40: Callback 2 - GetSlotConfig1 (8 bytes, relocatable RVA)
///   offset 48 (= 0x30): Callback 3 - GetSlotConfig2 (8 bytes, relocatable RVA)
///
/// Total from start of GUID: 16 + 32 = 48 bytes
///
typedef struct {
  EFI_GUID  BoardGuid;
  UINT32    Signature;   ///< "PBDS"
  UINT32    Version;     ///< 1
  UINT64    Callbacks[4];///< Relocatable callback pointers
} PBDS_REGISTRATION;

STATIC CONST PBDS_REGISTRATION  mBoardRegistration = {
  OPROM_UPDATE_BOARD_GUID,
  SIGNATURE_32('P', 'B', 'D', 'S'),
  1,
  { (UINT64)(UINTN)IsFunctionInPopulatedSlot,
    (UINT64)(UINTN)GetBoardInfo,
    (UINT64)(UINTN)GetSlotConfig1,
    (UINT64)(UINTN)GetSlotConfig2 }
};

//=============================================================================
// Global Variables (.data section)
//=============================================================================

///
/// Cached pointer to the UEFI System Table.
/// Initialized in _ModuleEntryPoint().
///
EFI_SYSTEM_TABLE  *gSystemTable = NULL;

///
/// Cached pointer to the UEFI Boot Services Table.
/// Initialized in _ModuleEntryPoint().
///
EFI_BOOT_SERVICES  *gBootServices = NULL;

///
/// Cached pointer to the UEFI Runtime Services Table.
/// Initialized in _ModuleEntryPoint().
///
EFI_RUNTIME_SERVICES  *gRuntimeServices = NULL;

///
/// Cached pointer to the UBA Debug Protocol interface.
/// Lazily initialized by LocateDebugProtocol().
///
VOID  *gDebugProtocol = NULL;

///
/// Cached pointer to the HOB (Hand-Off Block) list.
/// Populated by GetHobList().
///
VOID  *gHobList = NULL;

///
/// Debug output control flags.
/// Determines whether debug output is suppressed or displayed.
///
UINTN  gDebugFlags = 0;

//=============================================================================
// Helper: ReadUnaligned64
//=============================================================================

/**
 * Reads a 64-bit value from an unaligned memory address.
 *
 * @param[in] Buffer   Memory address (possibly unaligned)
 * @return UINT64      The 64-bit value at the address
 */
UINT64
EFIAPI
ReadUnaligned64 (
  IN CONST VOID  *Buffer
  )
{
  if (Buffer == NULL) {
    //
    // Trigger assertion using UBA Debug Protocol assert handler.
    //
    ReportAssert (
      "e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
      192,
      "Buffer != ((void *) 0)"
      );
  }

  return *(CONST UINT64 *)Buffer;
}

//=============================================================================
// Helper: ReportAssert
//=============================================================================

/**
 * Reports an assertion failure to the UBA Debug Protocol.
 *
 * If the debug protocol is available (cached in gDebugProtocol),
 * invokes its ReportAssert function at interface+0.
 *
 * @param[in] FileName      Source file where assertion failed
 * @param[in] LineNumber    Line number of failure
 * @param[in] Description   Assert condition string
 *
 * @return EFI_STATUS from debug protocol assert handler, or EFI_NOT_FOUND
 */
EFI_STATUS
EFIAPI
ReportAssert (
  IN CONST CHAR8  *FileName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *Description
  )
{
  EFI_STATUS  Status;
  VOID        *DebugProtocol;

  //
  // Lazily locate the UBA Debug Protocol if not yet cached.
  //
  DebugProtocol = LocateDebugProtocol ();
  if (DebugProtocol != NULL) {
    //
    // Call the ReportAssert function at interface offset +0.
    // The debug protocol interface has:
    //   +0: ReportAssert(FileName, LineNumber, Description)
    //   +8: Report(ErrorLevel, Format, ...)
    //
    Status = ((EFI_STATUS (EFIAPI *)(CONST CHAR8 *, UINTN, CONST CHAR8 *))DebugProtocol)(
               FileName,
               LineNumber,
               Description
               );
    return Status;
  }

  return EFI_NOT_FOUND;
}

//=============================================================================
// Helper: DebugPrint
//=============================================================================

/**
 * Outputs a debug message via the UBA Debug Protocol.
 *
 * Performs a CMOS status check before printing:
 *   - Reads CMOS index 0x4B (CMOS status register)
 *   - Checks if the CMOS byte indicates debug verbosity level
 *   - Only prints if the requested ErrorLevel matches configured level
 *
 * @param[in] ErrorLevel   Debug severity bitmask
 * @param[in] Format       Format string
 * @param[in] ...          Variable arguments
 *
 * @retval 0   Message was suppressed (protocol unavailable or level mismatch)
 * @retval 1   Message was printed successfully
 */
UINT8
EFIAPI
DebugPrint (
  IN UINTN       ErrorLevel,
  IN CONST CHAR8 *Format,
  ...
  )
{
  VA_LIST                VaList;
  VOID                   *DebugProtocol;
  UINT8                  DebugLevel;
  UINTN                  EffectiveErrorLevel;

  DebugProtocol = LocateDebugProtocol ();
  if (DebugProtocol == NULL) {
    return 0;
  }

  //
  // Check CMOS debug verbosity configuration.
  // CMOS index 0x4B (at I/O ports 0x70/0x71) stores board-specific
  // debug output control bits.
  //
  // CMOS register 0x4B layout:
  //   bit 7    = valid flag (if set, use configured level)
  //   bits [6:0] = debug verbosity level
  //
  // Read CMOS by writing index to 0x70, then reading data from 0x71.
  // The index byte preserves bit 7 of the CMOS index register
  // (NMI enable/disable).
  //
  {
    UINT8  IndexReg;
    UINT8  DataByte;

    IndexReg = __inbyte (0x70);
    __outbyte (0x70, (UINT8)(IndexReg & 0x80) | 0x4B);
    DataByte = __inbyte (0x71);

    if (DataByte > 3 && DataByte == 0) {
      //
      // If the debug level is > 3 AND also 0... this is a hardware quirk
      // for this platform.  Check an additional hardware register for
      // the override flag.
      //
      // NOTE: MEMORY[0xFDAF0490] is a platform-specific MMIO register
      // that provides debug override. This is specific to the C620
      // chipset/LightningRidge PCH memory-mapped configuration space.
      // bit 1 = debug enable
      //
      // This MMIO address is a virtual/physical address in the
      // chipset's MMIO configuration space (typically mapped by
      // the PCH root complex).
      //
      DataByte = (*(volatile UINT8 *)0xFDAF0490 & 2) | 1;
    }

    DebugLevel = DataByte;
  }

  //
  // Determine if our error level matches the CMOS-configured level.
  // The CMOS level is 0-based (0=disable, 1=error, 2=warn, 3=info, 4+=verbose)
  // while ErrorLevel is a UEFI-style bitmask.
  //
  EffectiveErrorLevel = 0x80000000;  // DEBUG_INFO = bit 31
  if (DebugLevel == 1) {
    EffectiveErrorLevel = 0x80000004;  // DEBUG_ERROR = bit 2
  }

  if ((EffectiveErrorLevel & ErrorLevel) == 0) {
    //
    // The requested error level is not enabled in the current debug config.
    //
    return 0;
  }

  //
  // Call the UBA Debug Protocol's Report function at interface offset +8.
  // Takes (ErrorLevel, FormatString, VariableArgs) as parameters.
  //
  va_start (VaList, Format);

  ((VOID (EFIAPI *)(UINTN, CONST CHAR8 *, VA_LIST))((UINT8 *)DebugProtocol + 8))(
    ErrorLevel,
    Format,
    VaList
    );

  va_end (VaList);

  return 1;
}

//=============================================================================
// Helper: LocateDebugProtocol
//=============================================================================

/**
 * Lazily locates and caches the UBA Debug Protocol.
 *
 * This function uses a trick to detect if it has been called before
 * in a high-TPL context (where protocol lookup would be dangerous):
 * it raises TPL to TPL_NOTIFY (31), restores, and checks if old TPL was
 * <= 0x10 (TPL_APPLICATION level). If so, it is safe to locate the protocol.
 *
 * The protocol interface is located via gBS->LocateProtocol() and cached
 * in gDebugProtocol for subsequent calls.
 *
 * @return Pointer to the UBA Debug Protocol interface, or NULL on failure
 */
VOID *
LocateDebugProtocol (
  VOID
  )
{
  EFI_STATUS  Status;
  UINT64      PagesAndMemory;

  if (gDebugProtocol != NULL) {
    //
    // Already cached.
    //
    return gDebugProtocol;
  }

  //
  // Raise TPL to TPL_NOTIFY (31) to prevent any callbacks during
  // our critical section (protocol location can re-enter).
  //
  // gBS->RaiseTPL (TPL_NOTIFY) returns the old TPL level.
  // We save the old TPL and immediately restore it.
  //
  PagesAndMemory = gBS->RaiseTPL (TPL_NOTIFY);
  gBS->RestoreTPL ((EFI_TPL)PagesAndMemory);

  //
  // If the old TPL was <= TPL_APPLICATION (16 = 0x10),
  // we are in a safe context to locate the protocol.
  //
  if (PagesAndMemory <= 0x10) {
    //
    // Locate the UBA Debug Protocol.
    //
    Status = gBS->LocateProtocol (
                   &mUbaDebugProtocolGuid,
                   NULL,                     // Registration (not used)
                   &gDebugProtocol
                   );

    if (EFI_ERROR (Status)) {
      //
      // Protocol not found; clear the cached pointer.
      //
      gDebugProtocol = NULL;
    }
  }

  return gDebugProtocol;
}

//=============================================================================
// Helper: CompareGuid
//=============================================================================

/**
 * Compares two GUIDs for byte-level equality.
 *
 * @param[in] Guid1   Pointer to first GUID
 * @param[in] Guid2   Pointer to second GUID
 * @retval TRUE       GUIDs are equal
 * @retval FALSE      GUIDs differ or either pointer is NULL
 */
BOOLEAN
EFIAPI
CompareGuid (
  IN EFI_GUID  *Guid1,
  IN EFI_GUID  *Guid2
  )
{
  CONST UINT64  *Guid1Data;
  CONST UINT64  *Guid2Data;

  if (Guid1 == NULL || Guid2 == NULL) {
    //
    // Trigger assertion via UBA Debug Protocol.
    //
    ReportAssert (
      "e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
      192,
      "Buffer != ((void *) 0)"
      );
    return FALSE;
  }

  //
  // Compare as two 64-bit values. The GUID structure is:
  //   Data1: UINT32 at offset 0
  //   Data2: UINT16 at offset 4
  //   Data3: UINT16 at offset 6
  //   Data4: UINT8[8] at offset 8
  //
  // For 64-bit comparison, first 8 bytes and last 8 bytes.
  // Use ReadUnaligned64 for safe access (GUID may not be aligned).
  //
  Guid1Data = (CONST UINT64 *)Guid1;
  Guid2Data = (CONST UINT64 *)Guid2;

  //
  // WARNING: The original binary uses ReadUnaligned64 which reads
  // a full UINT64 from the given address. GUID comparison in the
  // original code is: ((UINT64 *)Guid1)[0] == ((UINT64 *)Guid2)[0] &&
  // ((UINT64 *)Guid1)[1] == ((UINT64 *)Guid2)[1]
  //
  if (ReadUnaligned64 (Guid1) == ReadUnaligned64 (Guid2) &&
      ReadUnaligned64 ((UINT8 *)Guid1 + 8) == ReadUnaligned64 ((UINT8 *)Guid2 + 8)) {
    return TRUE;
  }

  return FALSE;
}

//=============================================================================
// Helper: GetHobList
//=============================================================================

/**
 * Locates and caches the HOB (Hand-Off Block) list pointer.
 *
 * The HOB list pointer is stored in the UEFI SystemTable's
 * configuration table. The SystemTable->ConfigurationTable is an array
 * of EFI_CONFIGURATION_TABLE entries. This function scans the table
 * for an entry whose VendorGuid matches gHobListGuid
 * ({ 0x7739f24c, 0x93d7, 0xd4, ... } = gEfiHobListGuid),
 * then caches the HOB list pointer.
 *
 * @return Pointer to the HOB list, or NULL if not found
 */
VOID *
GetHobList (
  VOID
  )
{
  UINTN                 Index;
  EFI_CONFIGURATION_TABLE  *ConfigTable;
  UINTN                 NumberOfTableEntries;

  if (gHobList != NULL) {
    //
    // Already cached.
    //
    return gHobList;
  }

  gHobList = NULL;

  //
  // Get the configuration table pointer.
  // SystemTable->ConfigurationTable is at offset 0x70.
  // SystemTable->NumberOfTableEntries is at offset 0x68.
  //
  // In the original binary's compiled code:
  //   NumberOfTableEntries = *(UINTN *)(SystemTable + 0x68)
  //   ConfigTable          = *(VOID **)(SystemTable + 0x70)
  //
  NumberOfTableEntries = gSystemTable->NumberOfTableEntries;
  ConfigTable          = gSystemTable->ConfigurationTable;

  if (NumberOfTableEntries > 0) {
    for (Index = 0; Index < NumberOfTableEntries; Index++) {
      //
      // Compare the GUID of each configuration table entry
      // against the HOB list GUID.
      //
      if (CompareGuid (&(gHobListGuid), &(ConfigTable[Index].VendorGuid))) {
        //
        // Found the HOB list entry.
        // ConfigTable[Index].VendorTable is the pointer to the HOB list.
        //
        gHobList = ConfigTable[Index].VendorTable;
        break;
      }
    }

    if (gHobList == NULL) {
      //
      // Failed to find the HOB list in the configuration table.
      // Report assert.
      //
      DebugPrint (0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", 0x800000000000000EULL);
      ReportAssert (
        "e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
        54,
        "!EFI_ERROR (Status)"
        );
    }
  }

  if (gHobList == NULL) {
    ReportAssert (
      "e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
      55,
      "mHobList != ((void *) 0)"
      );
  }

  return gHobList;
}

//=============================================================================
// Board-Specific Callbacks
//=============================================================================

/**
 * Checks if a PCI function belongs to a populated PCIe slot.
 *
 * Iterates the 8-entry PCIe root port BDF table. For each root port
 * i where (SlotBitmask >> i) & 1 == 0 (slot is populated), reads
 * the root port's PCI Express Device Capabilities register to
 * determine the supported function number range.
 *
 * The root port config space is read at offsets:
 *   BDF_Base | 0x19 = PCI Express Device Capabilities (lower byte = First Function Number)
 *   BDF_Base | 0x1A = PCI Express Device Capabilities 2 (lower byte = Last Function?)
 *
 * Where BDF_Base is the EFI_PCI_IO_PROTOCOL_PCI_ADDRESS encoded address
 * from the root port BDF entry.
 *
 * Uses EFI_PCI_IO_PROTOCOL->Pci.Read() via a per-call LocateProtocol.
 *
 * @param[in] FuncNum       The PCI function number to test
 * @param[in] SlotBitmask   8-bit mask: bit=0 means populated slot to check
 *
 * @retval TRUE             The function number is within range of a populated slot
 * @retval FALSE            Not behind any populated slot
 */
BOOLEAN
EFIAPI
IsFunctionInPopulatedSlot (
  IN UINT64   FuncNum,
  IN UINT32   SlotBitmask
  )
{
  UINTN                  Index;
  BOOLEAN                IsInRange;
  UINT32                 RegBase;
  UINT32                 PciAddr;
  EFI_PCI_IO_PROTOCOL    *PciIo;
  EFI_STATUS             Status;
  UINT8                  CapFuncMin;
  UINT8                  CapFuncMax;
  CONST PCIE_ROOT_PORT_BDF_ENTRY  *RootPortEntry;

  RootPortEntry = (CONST PCIE_ROOT_PORT_BDF_ENTRY *)mPcieRootPortBdfTable;
  IsInRange     = FALSE;

  PciIo = NULL;
  Status = gBS->LocateProtocol (
                 &mEfiPciIoProtocolGuid,
                 NULL,
                 (VOID **)&PciIo
                 );

  if (EFI_ERROR (Status) || PciIo == NULL) {
    //
    // Cannot access PCI config space; assume function is not in a populated slot.
    //
    return FALSE;
  }

  for (Index = 0; Index < MAX_PCIE_ROOT_PORTS; Index++) {
    if (((SlotBitmask >> Index) & 1) != 0) {
      //
      // Bit is set: this slot is NOT populated (or is excluded from check).
      //
      continue;
    }

    //
    // Build EFI_PCI_IO_PROTOCOL_PCI_ADDRESS from the root port entry.
    // Encoding:
    //   Bits [7:0]   = Register base (RootPortEntry->RegisterOffset)
    //   Bits [10:8]  = Function     = RootPortEntry->DevFunc & 0x07
    //   Bits [15:11] = Device       = (RootPortEntry->DevFunc >> 3) & 0x1F
    //   Bits [23:16] = Bus          = RootPortEntry->Bus
    //   Bit  28      = 1 (extended config space)
    //
    PciAddr = (RootPortEntry[Index].RegisterOffset & 0xFF) |
              ((RootPortEntry[Index].DevFunc & 0x07) << 8) |
              (((RootPortEntry[Index].DevFunc >> 3) & 0x1F) << 11) |
              ((RootPortEntry[Index].Bus) << 16) |
              BIT28;

    //
    // Read PCI Express Device Capabilities function range.
    // Offset 0x19 relative to the capability base:
    //   - Lower byte = First Function Number of the device
    // Offset 0x1A relative to the capability base:
    //   - Lower byte = Function range / capability indicator
    //
    // These reads identify which function numbers the downstream
    // device (behind this root port) occupies.
    //
    PciIo->Pci.Read (
            PciIo,
            EfiPciIoWidthUint8,
            PciAddr | 0x19,
            1,
            &CapFuncMin
            );

    PciIo->Pci.Read (
            PciIo,
            EfiPciIoWidthUint8,
            PciAddr | 0x1A,
            1,
            &CapFuncMax
            );

    //
    // Check if the given function number falls within the range.
    //
    if (FuncNum >= CapFuncMin && FuncNum <= CapFuncMax) {
      IsInRange = TRUE;
    }
  }

  return IsInRange;
}

/**
 * Returns the board info structure pointer.
 *
 * LightningRidge EXEC B2 has no additional board info beyond what's
 * contained in the PCIe slot config tables. Returns a pointer to
 * an empty zeroed structure.
 *
 * @param[out] BoardInfo   Set to point to the (empty) board info structure
 * @return EFI_SUCCESS
 */
EFI_STATUS
EFIAPI
GetBoardInfo (
  OUT VOID   **BoardInfo
  )
{
  *BoardInfo = (VOID *)&mEmptyBoardInfo;
  return EFI_SUCCESS;
}

/**
 * Returns the first PCIe slot configuration table and its count.
 *
 * The mSlotConfigTable1 table contains 6 entries describing
 * PCIe slot-to-BDF mappings for the LightningRidge EXEC B2 board.
 *
 * @param[out] SlotConfig   Set to point to the first slot config table
 * @param[out] EntryCount   Set to 6
 * @return EFI_SUCCESS
 */
EFI_STATUS
EFIAPI
GetSlotConfig1 (
  OUT VOID   **SlotConfig,
  OUT UINTN  *EntryCount
  )
{
  *SlotConfig = (VOID *)&mSlotConfigTable1;
  *EntryCount = MAX_SLOT_CONFIG1_ENTRIES;  // 6
  return EFI_SUCCESS;
}

/**
 * Returns the second PCIe slot configuration table and its count.
 *
 * The mSlotConfigTable2 table contains 10 entries describing
 * additional PCIe slot-to-BDF mappings for the LightningRidge
 * EXEC B2 board.
 *
 * @param[out] SlotConfig   Set to point to the second slot config table
 * @param[out] EntryCount   Set to 10
 * @return EFI_SUCCESS
 */
EFI_STATUS
EFIAPI
GetSlotConfig2 (
  OUT VOID   **SlotConfig,
  OUT UINTN  *EntryCount
  )
{
  *SlotConfig = (VOID *)&mSlotConfigTable2;
  *EntryCount = MAX_SLOT_CONFIG2_ENTRIES;  // 10
  return EFI_SUCCESS;
}

/**
 * Debug callback invoked when UBA sets/overrides a PCIe slot number.
 *
 * LightningRidge EXEC B2 does not override PCIe slot numbers.
 * The slot number output is written as 0 (use hardware default).
 * Prints a debug message indicating this callback was invoked.
 *
 * @param[out] SlotNumber   Set to 0 (no override)
 * @return EFI_SUCCESS
 */
EFI_STATUS
EFIAPI
SetPcieSlotNumber (
  OUT UINT8  *SlotNumber
  )
{
  *SlotNumber = 0;
  DebugPrint (0x80000000, "[UBA]:SetPcieSlotNumber callback - %d\n", *SlotNumber);
  return EFI_SUCCESS;
}

//=============================================================================
// Driver Entry Point
//=============================================================================

/**
 * UEFI Driver Entry Point.
 *
 * Initializes UEFI globals (ImageHandle, SystemTable, BootServices,
 * RuntimeServices), locates the HOB list, then registers the
 * LightningRidge EXEC B2 board configuration with the UBA Config Protocol.
 *
 * The registration is done via:
 *   1. LocateProtocol(gUbaConfigProtocolGuid, NULL, &UbaConfig)
 *   2. UbaConfig->RegisterBoardConfig(This, gOpromUpdateBoardGuid,
 *        &BoardConfigData, sizeof(PBDS_REGISTRATION))
 *
 * where BoardConfigData is the PBDS structure with:
 *   - Board GUID: OPROM_UPDATE_BOARD_GUID (371bd79c-...)
 *   - Signature:  "PBDS"
 *   - Version:    1
 *   - Callbacks:  IsFunctionInPopulatedSlot,
 *                 GetBoardInfo,
 *                 GetSlotConfig1,
 *                 GetSlotConfig2
 *
 * @param[in] ImageHandle   UEFI image handle
 * @param[in] SystemTable   UEFI system table
 *
 * @return EFI_SUCCESS       Board config registered
 * @return EFI_UNSUPPORTED   UBA Config Protocol not found
 * @return EFI_NOT_FOUND     UBA Config Protocol function not available
 */
EFI_STATUS
EFIAPI
_ModuleEntryPoint (
  IN EFI_IMAGE_HANDLE   ImageHandle,
  IN EFI_SYSTEM_TABLE   *SystemTable
  )
{
  EFI_STATUS   Status;
  VOID         *UbaConfigProtocol;
  PBDS_REGISTRATION *Registration;

  //
  // --- BEGIN: UefiBootServicesTableLib initialization ---
  //
  // Cache ImageHandle: This is required for driver unload and protocol operations.
  //
  gImageHandle = ImageHandle;
  if (gImageHandle == NULL) {
    ReportAssert (
      "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      51,
      "gImageHandle != ((void *) 0)"
      );
  }

  //
  // Cache SystemTable.
  //
  gSystemTable = SystemTable;
  if (gSystemTable == NULL) {
    ReportAssert (
      "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      57,
      "gST != ((void *) 0)"
      );
  }

  //
  // Cache BootServices from SystemTable.
  //
  gBootServices = SystemTable->BootServices;
  if (gBootServices == NULL) {
    ReportAssert (
      "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      63,
      "gBS != ((void *) 0)"
      );
  }

  //
  // --- BEGIN: UefiRuntimeServicesTableLib initialization ---
  //
  gRuntimeServices = SystemTable->RuntimeServices;
  if (gRuntimeServices == NULL) {
    ReportAssert (
      "e:\\hs\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c",
      47,
      "gRT != ((void *) 0)"
      );
  }

  //
  // Locate and cache the HOB list from SystemTable configuration table.
  //
  GetHobList ();

  //
  // Register board configuration with UBA Config Protocol.
  // First, log registration attempt.
  //
  DebugPrint (
    0x80000000,
    "UBA:OpromUpdate-TypeLightningRidgeEXECB2\n"
    );

  //
  // Locate the UBA Config Protocol.
  // The protocol GUID is e03e0d46-5263-4845-b0a4-58d57b3177e2.
  //
  Registration = (PBDS_REGISTRATION *)&mBoardRegistration;
  UbaConfigProtocol = NULL;

  Status = gBS->LocateProtocol (
                 &mUbaConfigProtocolGuid,
                 NULL,
                 &UbaConfigProtocol
                 );

  if (!EFI_ERROR (Status) && UbaConfigProtocol != NULL) {
    //
    // The UBA Config Protocol interface provides:
    //   +0:  Unknown (version/query?)
    //   +8:  Unknown
    //   +16: RegisterBoardConfig(This, BoardGuid, ConfigData, ConfigSize)
    //   ... potentially more functions
    //
    // Register the board:
    //   Guid  = OPROM_UPDATE_BOARD_GUID (371bd79c-...)
    //   Data  = PBDS_BOARD_CONFIG structure with callbacks
    //   Size  = sizeof(PBDS_REGISTRATION) (48 bytes)
    //
    // Function at protocol+16 (index 2) takes:
    //   (ProtocolInterface, BoardGuid, ConfigData, ConfigSize)
    //
    Status = ((EFI_STATUS (EFIAPI *)(VOID *, EFI_GUID *, VOID *, UINTN))(
               ((UINT8 *)UbaConfigProtocol + 16)))(
               UbaConfigProtocol,
               &Registration->BoardGuid,
               (UINT8 *)Registration + sizeof (EFI_GUID),  // Skip GUID, point to PBDS data
               sizeof (PBDS_BOARD_CONFIG)                   // 32 bytes: sig + ver + 4 funcs
               );
  }

  return Status;
}