Newer
Older
AMI-Aptio-BIOS-Reversed / OpromUpdateDxeNeonCityEPECB / OpromUpdateDxeNeonCityEPECB.c
@Ajax Dong Ajax Dong 2 days ago 20 KB Init
/** @file
  OpromUpdateDxeNeonCityEPECB - Option ROM Update DXE Driver for NeonCity EP EC B

  This DXE driver implements the UBA (Universal BIOS Adapter) OpromUpdate
  protocol for the NeonCity EP EC B platform. It provides:

  - PCIe slot number validation against platform-specific slot ranges using the
    DXE Services Protocol to read PCIe Slot Capabilities registers.
  - Platform-specific PCIe slot configuration data tables (default, platform,
    and slot number mappings).
  - PCIe slot number assignment (fixed to slot 2 for this platform).
  - UBA backchannel debug logging with platform type detection via CMOS/RTC.

  The driver entry point locates the UBA OpromUpdate config protocol and
  registers its platform-specific configuration data and callbacks.

  Copyright (c) 2024, Inspur Corporation. All rights reserved.
  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include "OpromUpdateDxeNeonCityEPECB.h"

//
// Global UEFI table pointers (initialized at entry point)
//
EFI_HANDLE             gImageHandle       = NULL;
EFI_SYSTEM_TABLE      *gSystemTable       = NULL;
EFI_BOOT_SERVICES     *gBootServices      = NULL;
EFI_RUNTIME_SERVICES  *gRuntimeServices   = NULL;

//
// Cached UBA protocol interface pointer (for debug print and assert)
//
STATIC VOID  *mUbaProtocol = NULL;

//
// Cached HOB list pointer
//
STATIC VOID  *mHobList = NULL;

//
// GUID definitions (located in .data section at runtime)
//
STATIC CONST EFI_GUID  mDxeServicesProtocolGuid =
  { 0x2F707EBB, 0x4A1A, 0x11D4, { 0x9A, 0x38, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } };

STATIC CONST EFI_GUID  mUbaProtocolGuid =
  { 0x36232936, 0x0E76, 0x31C8, { 0xA1, 0x3A, 0x3A, 0xF2, 0xFC, 0x1C, 0x39, 0x32 } };

STATIC CONST EFI_GUID  mUbaConfigProtocolGuid =
  { 0xE03E0D46, 0x5263, 0x4845, { 0xB0, 0xA4, 0x58, 0xD5, 0x7B, 0x31, 0x77, 0xE2 } };

STATIC CONST EFI_GUID  mHobListGuid =
  { 0x7739F24C, 0x93D7, 0x11D4, { 0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } };

//
// OPRM (Option ROM Policy) Table
//
// 8 entries, each spanning 3 bytes across a 4-byte stride.
// The table encodes the PCI bus:device:function range for each of the 8 slots.
// Entries are at offsets 0xEF1, 0xEF5, 0xEF9, 0xEFD, 0xF01, 0xF05, 0xF09, 0xF0D.
// At runtime the data is populated by the platform initialization code.
//
// Byte layout per entry (bytes v4-1, v4, v4+1):
//   byte[0] = Bus number (or upper byte of BDF encoding)
//   byte[1] = Device number
//   byte[2] = Function number (or lower byte of BDF encoding)
//
// Combined key: ((Bus << 8) | (Device << 16) | (Function << 24)) & 0xFFFFFF00
//
STATIC UINT8  mOprmTable[OPRM_TABLE_ENTRY_COUNT * OPRM_TABLE_STRIDE];

//
// Default slot configuration table (all 0xFFFF = empty)
//
STATIC UINT8  mDefaultSlotConfig[64] = { 0 };

//
// NeonCity EP EC B slot configuration table
// Format: array of 6 { DeviceId, SubVendorId, Revision, ... } entries
//
#pragma pack(1)
typedef struct {
  UINT32  SlotInfo;
  UINT32  VendorDeviceId;
  UINT16  SubSystemId;
  UINT8   Revision;
  UINT8   ProgInterface;
  UINT8   SubClass;
  UINT8   BaseClass;
  UINT8   Reserved0[4];
  UINT8   EepromOffset;
  UINT8   Reserved1[3];
} NEONCITY_SLOT_CONFIG_ENTRY;

typedef struct {
  UINT8   EntryCount;
  UINT8   Reserved[3];
  NEONCITY_SLOT_CONFIG_ENTRY  Entries[6];
} NEONCITY_SLOT_CONFIG_TABLE;
#pragma pack()

STATIC CONST NEONCITY_SLOT_CONFIG_ENTRY  mNeonCitySlotConfig[6] = {
  // Placeholder entries matching the .rdata structure at 0xD40
  { 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0} },
  { 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0} },
  { 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0} },
  { 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0} },
  { 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0} },
  { 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0} },
};

//
// PciBdfSlot number table (10 entries for NeonCity EP EC B)
//
#pragma pack(1)
typedef struct {
  UINT16  SlotFlags;        // Flags/attributes for this slot
  UINT16  DeviceId;         // PCI Device ID
  UINT16  VendorId;         // PCI Vendor ID
  UINT32  Reserved;
  UINT32  SlotCapabilities; // PCIe Slot Capabilities register value
} PCIE_BDF_SLOT_ENTRY;
#pragma pack()

STATIC CONST PCIE_BDF_SLOT_ENTRY  mPcieBdfSlotTable[10] = {
  // Data at 0xE40 - platform-specific PCIe BDF slot mappings
  // These entries define the PCIe slot numbering for the platform
  { 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0 },
};

/**
  Safely reads a UINT64 from memory, asserting if the pointer is NULL.

  @param[in] Buffer  Pointer to the UINT64 value to read.

  @return The UINT64 value at the specified address.
**/
UINT64
ReadUnaligned64 (
  IN CONST UINT64  *Buffer
  )
{
  if (Buffer == NULL) {
    UbaAssert (
      "e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
      0xC0,
      "Buffer != ((void *) 0)"
      );
  }

  return *Buffer;
}

/**
  Compares two GUIDs by comparing their first and last QWORD components.

  This avoids pulling in the full CompareGuid library routine.

  @param[in] GuidPtr    Pointer to the reference GUID.
  @param[in] HobEntry   Pointer to the GUID in the HOB entry.

  @retval TRUE   Both QWORD components match.
  @retval FALSE  The GUIDs do not match.
**/
BOOLEAN
CompareGuidQword (
  IN EFI_GUID  *GuidPtr,
  IN VOID      *HobEntry
  )
{
  UINT64  GuidFirst;
  UINT64  GuidLast;
  UINT64  EntryFirst;
  UINT64  EntryLast;

  GuidFirst = ReadUnaligned64 ((UINT64 *)GuidPtr);
  GuidLast  = ReadUnaligned64 ((UINT64 *)((UINTN)GuidPtr + sizeof (UINT64)));
  EntryFirst = ReadUnaligned64 ((UINT64 *)HobEntry);
  EntryLast  = ReadUnaligned64 ((UINT64 *)((UINTN)HobEntry + sizeof (UINT64)));

  return (BOOLEAN)(GuidFirst == EntryFirst && GuidLast == EntryLast);
}

/**
  Retrieves the HOB list pointer from the UEFI SystemTable.

  Scans the SystemTable configuration table entries to find the HOB list
  GUID match, then caches and returns the HOB list pointer.

  @param[in] ImageHandle  The EFI image handle (currently unused).

  @return Pointer to the HOB list, or NULL if not found.
**/
VOID *
GetHobList (
  IN EFI_HANDLE  ImageHandle
  )
{
  UINTN   Index;
  UINTN   EntryCount;
  VOID    *ConfigTable;
  VOID    *HobListResult;

  if (mHobList != NULL) {
    return mHobList;
  }

  mHobList = NULL;
  HobListResult = NULL;

  //
  // Scan system configuration table for EFI_HOB_LIST_GUID entry
  // gSystemTable->ConfigurationTable is an array of {EFI_GUID, VOID*} entries
  //
  if (gSystemTable->NumberOfTableEntries > 0) {
    for (Index = 0; Index < gSystemTable->NumberOfTableEntries; Index++) {
      ConfigTable = (VOID *)((UINTN)gSystemTable->ConfigurationTable + (Index * 24));
      if (CompareGuidQword (&mHobListGuid, ConfigTable)) {
        HobListResult = *(VOID **)((UINTN)ConfigTable + 16);
        mHobList = HobListResult;
        return HobListResult;
      }
    }
  }

  //
  // HOB list not found - trigger assertion (matching original behavior)
  //
  UbaDebugPrint (
    UBA_DEBUG_ERROR,
    "\nASSERT_EFI_ERROR (Status = %r)\n",
    0x800000000000000EULL
    );
  UbaAssert (
    "e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
    54,
    "!EFI_ERROR (Status)"
    );

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

  return mHobList;
}

/**
  Locates and returns the UBA backchannel protocol interface pointer.

  Uses the DXE Services Table to locate the UBA protocol. First checks
  the HOB size via GetBootMode (index 3), and if HOB size <= 0x10,
  locates the protocol via the DXE Services Table's LocateProtocol
  (function at vtable index 40 = offset 320).

  @return Pointer to the UBA protocol interface, or NULL if not found.
**/
VOID *
GetUbaProtocol (
  VOID
  )
{
  UINT64               HobSize;
  EFI_DXE_SERVICES     *DxeServices;
  EFI_STATUS           Status;

  if (mUbaProtocol != NULL) {
    return mUbaProtocol;
  }

  //
  // Get HOB size via DXE Services GetBootMode (function at vtable+24 = index 3)
  // BootServices[24] = CalculateE820CompatibleSize or similar size-retrieval
  //
  HobSize = gBootServices->CalculateE820CompatibleSize (31);
  gBootServices->FreePool ((VOID *)(UINTN)HobSize);

  if (HobSize <= 0x10) {
    //
    // Locate UBA protocol via DXE Services Table
    // gBootServices->LocateProtocol is at offset 320 (index 40) in BootServices vtable
    //
    Status = gBootServices->LocateProtocol (
                              &mUbaProtocolGuid,
                              NULL,
                              &mUbaProtocol
                              );
    if (EFI_ERROR (Status)) {
      mUbaProtocol = NULL;
    }
  }

  return mUbaProtocol;
}

/**
  Debug print via UBA backchannel protocol.

  Reads the platform type from CMOS/RTC register 0x4B to determine
  the debug filter level. If the platform matches NeonCity EP and
  the error level matches the filter, calls the UBA debug print function.

  @param[in] ErrorLevel  Debug severity level.
  @param[in] Format      Format string.
  @param[in] ...         Variable arguments.

  @retval TRUE   The message was printed.
  @retval FALSE  The UBA backchannel was not available.
**/
BOOLEAN
UbaDebugPrint (
  IN UINTN       ErrorLevel,
  IN CONST CHAR8 *Format,
  ...
  )
{
  VA_LIST              Args;
  VOID                 *UbaProtocol;
  EFI_STATUS           (EFIAPI *DebugPrintFunc)(UINTN, CONST CHAR8 *, VA_LIST);
  UINT8                RtcReg;
  UINT8                PlatformType;
  UINTN                FilterLevel;
  BOOLEAN              Result;

  UbaProtocol = GetUbaProtocol ();
  FilterLevel = 0;
  DebugPrintFunc = NULL;
  Result = FALSE;

  if (UbaProtocol != NULL) {
    //
    // Detect platform type from CMOS/RTC register
    //
    RtcReg        = IoRead8 (RTC_ADDRESS_PORT);
    IoWrite8 (RTC_ADDRESS_PORT, (RtcReg & 0x80) | RTC_INDEX_PLATFORM_TYPE);
    PlatformType  = IoRead8 (RTC_DATA_PORT);

    //
    // Validate platform type
    //
    if (PlatformType > PLATFORM_TYPE_MAX) {
      if (PlatformType == 0) {
        //
        // Fallback: read platform type from MMIO register
        //
        PlatformType = (MmioRead32 (PLATFORM_TYPE_MMIO_REG) & 0x2) | 0x1;
      }
    }

    //
    // Set filter level based on platform type
    //
    FilterLevel = UBA_DEBUG_ERROR;
    if (PlatformType == PLATFORM_TYPE_NEONCITY_EP) {
      FilterLevel = UBA_DEBUG_INFO;
    }

    //
    // Call UBA debug print function if severity matches filter
    // Debug print function is at vtable offset 1 (index 1, offset 8)
    //
    if ((FilterLevel & ErrorLevel) != 0) {
      DebugPrintFunc = (EFI_STATUS (EFIAPI *)(UINTN, CONST CHAR8 *, VA_LIST))
                        *((UINT64 *)UbaProtocol + 1);
      VA_START (Args, Format);
      DebugPrintFunc (ErrorLevel, Format, Args);
      VA_END (Args);
      Result = TRUE;
    }
  }

  return Result;
}

/**
  Assert handler via UBA backchannel protocol.

  @param[in] FileName      Source file name where the assertion occurred.
  @param[in] LineNumber    Line number of the assertion.
  @param[in] AssertString  The assertion expression string.
**/
VOID
UbaAssert (
  IN CONST CHAR8  *FileName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *AssertString
  )
{
  VOID     *UbaProtocol;
  EFI_STATUS (EFIAPI *AssertFunc)(CONST CHAR8 *, UINTN, CONST CHAR8 *);

  UbaProtocol = GetUbaProtocol ();
  if (UbaProtocol != NULL) {
    //
    // Assert function is at vtable offset 2 (index 2, offset 16)
    //
    AssertFunc = (EFI_STATUS (EFIAPI *)(CONST CHAR8 *, UINTN, CONST CHAR8 *))
                  *((UINT64 *)UbaProtocol + 2);
    AssertFunc (FileName, LineNumber, AssertString);
  }
}

/**
  Validates a PCI function address against the slot bitmask.

  For each bit set in SlotBitmask (bits 0-7), reads the slot BDF range
  from the OPRM table and queries the DXE Services protocol to determine
  whether the given PCI address falls within the slot's valid range.

  The DXE Services protocol function at vtable index 7 (offset 56) is
  called to read configuration space bytes at the computed BDF address.

  @param[in] PciAddress   PCI bus:device:function address to validate.
  @param[in] SlotBitmask  Bitmask of slot positions to check (bits 0-7).

  @retval TRUE   The address falls within an enabled slot's range.
  @retval FALSE  The address is not within any enabled slot's range.
**/
BOOLEAN
IsPcieSlotNumberValid (
  IN UINT64   PciAddress,
  IN UINT32   SlotBitmask
  )
{
  UINT32       Bitmask;
  UINT8        *SlotBase;
  UINT8        *OprmEntry;
  BOOLEAN      Result;
  UINTN        PortIndex;
  UINT64       Bus;
  UINT64       Device;
  UINT64       Function;
  EFI_STATUS   Status;
  VOID         *DxeServices;
  UINT64       BdfSlotKey;
  UINT8        SlotRangeLow;
  UINT8        SlotRangeHigh;

  Bitmask    = SlotBitmask;
  SlotBase   = (UINT8 *)(UINTN)mOprmTable - 1;  // Adjust for v4-1 offset
  Result     = FALSE;

  for (PortIndex = 0; PortIndex < OPRM_TABLE_ENTRY_COUNT; PortIndex++) {
    if (((Bitmask >> PortIndex) & 1) == 0) {
      continue;
    }

    //
    // Each OPRM entry is 3 bytes at 4-byte stride
    // OprmEntry points to entry base = mOprmTable + (PortIndex * 4)
    //
    OprmEntry = (UINT8 *)(UINTN)mOprmTable + (PortIndex * 4);

    //
    // Decode BDF from 3 bytes at offset v4-1, v4, v4+1
    // Combined into a slot key: ((byte[-1] << 8) | (byte[0] << 16) | (byte[1] << 24)) & 0xFFFFFF00
    //
    Bus      = OprmEntry[-1];
    Device   = OprmEntry[0];
    Function = OprmEntry[1];

    //
    // Build the BDF slot key: ((Bus) | (Device << 8) | (Function << 16)) << 8
    // Then OR with 0x19 (Slot Capabilities Register low byte offset) and 0x1A (high byte)
    //
    BdfSlotKey = (Bus | (Device << 8) | (Function << 16)) << 8;
    Result     = FALSE;

    //
    // Locate DXE Services Protocol
    // (GUID = EFI_DXE_SERVICES_TABLE_GUID)
    //
    Status = gBootServices->LocateProtocol (
                              &mDxeServicesProtocolGuid,
                              NULL,
                              &DxeServices
                              );
    if (EFI_ERROR (Status)) {
      continue;
    }

    //
    // Read slot range low byte via DXE Services function at vtable+56 (index 7)
    // BdfSlotKey | 0x19 = PCIe Slot Capabilities register low byte
    //
    Status = ((EFI_DXE_SERVICES *)DxeServices)->GetFunctionTableEntry (
                                                  DxeServices,
                                                  0,
                                                  BdfSlotKey | 0x19,
                                                  1,
                                                  &SlotRangeLow
                                                  );
    if (EFI_ERROR (Status)) {
      continue;
    }

    //
    // Read slot range high byte via DXE Services function at vtable+56 (index 7)
    // BdfSlotKey | 0x1A = PCIe Slot Capabilities register high byte
    //
    Status = ((EFI_DXE_SERVICES *)DxeServices)->GetFunctionTableEntry (
                                                  DxeServices,
                                                  0,
                                                  BdfSlotKey | 0x1A,
                                                  1,
                                                  &SlotRangeHigh
                                                  );
    if (EFI_ERROR (Status)) {
      continue;
    }

    //
    // Check if PciAddress falls within this slot's valid range
    //
    if (PciAddress >= SlotRangeLow && PciAddress <= SlotRangeHigh) {
      Result = TRUE;
    }
  }

  return Result;
}

/**
  Returns the default (empty) slot configuration table.

  @param[out] ConfigTable  Pointer to receive the table address.

  @retval EFI_SUCCESS  The table pointer was returned.
**/
EFI_STATUS
GetDefaultSlotConfig (
  OUT VOID  **ConfigTable
  )
{
  *ConfigTable = (VOID *)mDefaultSlotConfig;
  return EFI_SUCCESS;
}

/**
  Returns the NeonCity EP EC B slot configuration table.

  @param[out] ConfigTable  Pointer to receive the table address.
  @param[out] EntryCount   Pointer to receive the number of entries (6).

  @retval EFI_SUCCESS  The table pointer and count were returned.
**/
EFI_STATUS
GetNeonCitySlotConfig (
  OUT VOID    **ConfigTable,
  OUT UINTN   *EntryCount
  )
{
  *ConfigTable = (VOID *)mNeonCitySlotConfig;
  *EntryCount  = 6;
  return EFI_SUCCESS;
}

/**
  Returns the PCIe BDF slot number table for NeonCity EP EC B.

  @param[out] SlotTable    Pointer to receive the table address.
  @param[out] EntryCount   Pointer to receive the number of entries (10).

  @retval EFI_SUCCESS  The table pointer and count were returned.
**/
EFI_STATUS
GetPcieSlotNumberTable (
  OUT VOID    **SlotTable,
  OUT UINTN   *EntryCount
  )
{
  *SlotTable  = (VOID *)mPcieBdfSlotTable;
  *EntryCount = 10;
  return EFI_SUCCESS;
}

/**
  Set PCIe slot number callback.

  Assigns slot number 2 and emits a debug trace.

  @param[out] SlotNumber  Pointer to receive the assigned slot number.

  @retval EFI_SUCCESS  The slot number was set successfully.
**/
EFI_STATUS
SetPcieSlotNumber (
  OUT UINT8  *SlotNumber
  )
{
  *SlotNumber = 2;

  UbaDebugPrint (
    UBA_DEBUG_INFO,
    "[UBA]:SetPcieSlotNumber callback - %d\n",
    *SlotNumber
    );

  return EFI_SUCCESS;
}

/**
  Entry point for the OpromUpdate DXE driver.

  Initializes global UEFI table pointers, retrieves the HOB list, and
  registers the platform's OpromUpdate configuration with the UBA
  framework.

  The registration provides:
  - A GUID identifying the platform
  - A data table containing function pointers for config callbacks
  - The data size (48 bytes)

  @param[in] ImageHandle  The firmware allocated handle for the EFI image.
  @param[in] SystemTable  A pointer to the EFI System Table.

  @retval EFI_SUCCESS           Protocol installed successfully.
  @retval EFI_NOT_FOUND         UBA protocol not found.
  @retval Others                Error from gBS->InstallProtocolInterface.
**/
EFI_STATUS
EFIAPI
OpromUpdateEntryPoint (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS  Status;
  VOID        *UbaConfigProtocol;
  //
  // UBA configuration data structure (48 bytes total)
  // Contains GUID + version + callback function pointers
  //
  typedef struct {
    EFI_GUID  ConfigGuid;           // Platform config GUID (16 bytes)
    UINT32    Version;              // Configuration data version
    UINT8     Padding[4];           // Alignment padding
    //
    // Callback function pointers (the "PSET" table at 0xEC0 in .data)
    // Index 0: GetDefaultSlotConfig
    // Index 1: GetNeonCitySlotConfig
    // Index 2: GetPcieSlotNumberTable
    // Index 3: SetPcieSlotNumber
    // Index 4,5: Reserved (set to 0)
    //
    UINT64    Callbacks[6];         // 6 * 8 = 48 bytes
  } UBA_OPROM_CONFIG_DATA;

  UBA_OPROM_CONFIG_DATA  ConfigData;

  //
  // Initialize global UEFI table pointers to match UEFI standard library behavior
  //
  gImageHandle = ImageHandle;
  if (ImageHandle == NULL) {
    UbaAssert (
      "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      51,
      "gImageHandle != ((void *) 0)"
      );
  }

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

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

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

  //
  // Initialize HOB list (cached for later use)
  //
  GetHobList (ImageHandle);

  //
  // Log driver entry
  //
  UbaDebugPrint (
    UBA_DEBUG_INFO,
    "UBA:OpromUpdate-TypeNeonCityEPECB\n"
    );

  //
  // Locate the UBA OpromUpdate config protocol
  //
  Status = gBootServices->LocateProtocol (
                            &mUbaConfigProtocolGuid,
                            NULL,
                            &UbaConfigProtocol
                            );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Build configuration data structure
  //
  CopyMem (&ConfigData.ConfigGuid, &mUbaProtocolGuid, sizeof (EFI_GUID));
  ConfigData.Version = 1;
  ZeroMem (ConfigData.Padding, sizeof (ConfigData.Padding));
  ConfigData.Callbacks[0] = (UINT64)(UINTN)IsPcieSlotNumberValid;
  ConfigData.Callbacks[1] = (UINT64)(UINTN)GetDefaultSlotConfig;
  ConfigData.Callbacks[2] = (UINT64)(UINTN)GetNeonCitySlotConfig;
  ConfigData.Callbacks[3] = (UINT64)(UINTN)GetPcieSlotNumberTable;
  ConfigData.Callbacks[4] = (UINT64)(UINTN)SetPcieSlotNumber;
  ConfigData.Callbacks[5] = 0;

  //
  // Register configuration with UBA framework
  // Call function at vtable index 2 (offset 16) in UbaConfigProtocol
  //
  return ((EFI_STATUS (EFIAPI *)(VOID *, VOID *, VOID *, UINTN))UbaConfigProtocol)(
           UbaConfigProtocol,
           &ConfigData,
           &ConfigData.Callbacks,
           sizeof (UBA_OPROM_CONFIG_DATA)
           );
}