Newer
Older
AMI-Aptio-BIOS-Reversed / OpromUpdateDxeCLX64L / OpromUpdateDxeCLX64L.c
@Ajax Dong Ajax Dong 2 days ago 22 KB Init
/** @file
  OpromUpdateDxeCLX64L - UEFI Driver for Option ROM Update Policy on CLX64L Platform

  This module implements platform-specific Option ROM (OpROM) update policy
  for the CLX64L (Cascade Lake Xeon 64L) server platform using the UBA
  (Universal BIOS Architecture) framework.

  The driver provides:
    1. PCIe slot number assignment - maps physical BDF to logical slot numbers
       for CLX64L-specific slot topology.
    2. Bus scan limits - restricts PCI bus enumeration ranges per device,
       ensuring correct resource allocation on the CLX64L platform.
    3. ACPI support integration - registers with ACPI support protocol via UBA.

  Functional Overview:
    - ModuleEntryPoint initializes UEFI boot/runtime services globals and the
      HOB (Hand-Off Block) list, then installs the UBA OpromUpdate protocol
      configuration for the CLX64L platform.
    - SetPcieSlotNumber() checks a given bus/device/function against the
      CLX64L slot mapping table and validates a caller-supplied value against
      the slot's valid range.
    - GetBusScanLimit/GetBusScanLimit2 return platform-specific tables of
      PCI devices whose bus scan range should be limited.
    - SetPcieSlotCallback() is invoked when a slot number update occurs,
      logging the event via UBA debug output.

  Build Dependencies:
    - MdePkg
    - UefiBootServicesTableLib
    - UefiRuntimeServicesTableLib
    - DxeHobLib
    - BaseLib

  Copyright (C) 2025 Insyde Software Corporation. All rights reserved.
  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include "OpromUpdateDxeCLX64L.h"

//
// ---------------------------------------------------------------------------
// Global data
// ---------------------------------------------------------------------------
//

EFI_HANDLE              gImageHandle     = NULL;
EFI_SYSTEM_TABLE        *gSystemTable    = NULL;
EFI_BOOT_SERVICES       *gBootServices   = NULL;
EFI_RUNTIME_SERVICES    *gRuntimeServices = NULL;
VOID                    *mHobList        = NULL;

//
// GUIDs used by this driver:
//   gEfiPciRootBridgeIoProtocolGuid  - protocol for PCI root bridge I/O
//   gEfiHobListGuid                  - HOB list identifier
//   gEfiVariableArchProtocolGuid     - variable architecture protocol
//   gEfiAcpiSupportProtocolGuid      - ACPI support protocol
//
// These are referenced via the UBA configuration tables below.
//
EFI_GUID  gEfiPciRootBridgeIoProtocolGuid  = {0x2F707EBB, 0x4A1A, 0x11D4, {0x9A, 0x38, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D}};
EFI_GUID  gEfiHobListGuid                  = {0x36232936, 0x0E76, 0x31C8, {0xA1, 0x3A, 0x3A, 0xF2, 0xFC, 0x1C, 0x39, 0x32}};
EFI_GUID  gEfiVariableArchProtocolGuid     = {0xE03E0D46, 0x5263, 0x4845, {0xB0, 0xA4, 0x58, 0xD5, 0x7B, 0x31, 0x77, 0xE2}};
EFI_GUID  gEfiAcpiSupportProtocolGuid      = {0x7739F24C, 0x93D7, 0x11D4, {0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D}};

//
// ---------------------------------------------------------------------------
// Bus Scan Limit Tables
//
// These tables define the PCIe devices on the CLX64L platform whose secondary
// bus range is constrained for PCI enumeration. Each entry identifies a device
// by Segment/Bus/Device/Function and VendorId/DeviceId, and specifies the
// allowed primary and secondary bus limits.
// ---------------------------------------------------------------------------
//

//
// Table 1: Primary bus scan limits (6 entries).
// Covers on-board PCIe devices for CLX64L.
//
UBA_OPROM_BUS_SCAN_LIMIT_ENTRY  mBusScanLimitTable[] = {
  //
  // Entry 0: 8086:1528 (Intel I350 PCIe Controller) at Bus 1, Dev 2, Func 0
  //           Rev 0x02, BaseClass 0x02 (Network Controller)
  //           Bus scan range: primary up to 0x2D, secondary up to 0x2C
  //           Slot 0x01, BDF range [0, 0xFF] x [0x2E, 0x2F]
  //
  { 0x0001, 0x00000001, 0x00000000, 0x00000002, 0x8086, 0x1528, 0x02, 0x00, 0x00, 0x02,
    0x00000001, 0x2D, 0x2C, 0x00000001, 0x00000001, 0x00, 0x2E, 0xFFFF },

  //
  // Entry 1: 8086:1521 (Intel I350 PCIe Controller) at Bus 1, Dev 1, Func 0
  //           Rev 0x02, BaseClass 0x02 (Network Controller)
  //           Bus scan range: primary up to 0x2D, secondary up to 0x2C
  //           Slot 0x01, BDF range [0, 0xFF] x [0x2E, 0x2F]
  //
  { 0x0001, 0x00010000, 0x00000000, 0x00000001, 0x8086, 0x1521, 0x02, 0x01, 0x00, 0x02,
    0x00000001, 0x2D, 0x2C, 0x00000001, 0x00000001, 0x00, 0x2E, 0xFFFF },

  //
  // Entry 2: 8086:10FB (Intel X550/X557 10GbE Controller) at wildcard BDF
  //           Rev 0x02, BaseClass 0x02 (Network Controller)
  //           Broad wildcard bus range
  //
  { 0x0002, 0x00000000, 0x00000000, 0x00000002, 0x8086, 0x10FB, 0x02, 0x05, 0xFFFFFFFF, 0x02,
    0xFFFFFFFF, 0xFF, 0xFF, 0xFFFFFFFF, 0x00000002, 0x00, 0x2E, 0xFFFF },

  //
  // Entry 3: 8086:1521 at Dev 4, Func 4 (second instance)
  //           Bus scan range: primary up to 0x2D, secondary up to 0x2C
  //           Slot 0x04, BDF range [0, 0xFF] x [0x2E, 0x2F]
  //
  { 0x0002, 0x00000000, 0x00000000, 0x00000004, 0x8086, 0x1521, 0x04, 0x04, 0xFFFFFFFF, 0x02,
    0xFFFFFFFF, 0xFF, 0xFF, 0xFFFFFFFF, 0x00000002, 0x00, 0x2E, 0xFFFF },

  //
  // Entry 4: 8086:1528 at Dev 2, Func 9 (third instance)
  //           Bus scan range wildcard
  //
  { 0x0002, 0x00000000, 0x00000000, 0x00000002, 0x8086, 0x1528, 0x02, 0x09, 0xFFFFFFFF, 0x02,
    0xFFFFFFFF, 0xFF, 0xFF, 0xFFFFFFFF, 0x00000002, 0x00, 0x2E, 0xFFFF },

  //
  // Entry 5: Additional device at Bus 2, Dev 16, Func 3
  //           Vendor 0x15B3 (Mellanox), Device 0x1003
  //           BaseClass 0x02 (Network Controller)
  //           Bus scan range: secondary up to 0x06
  //
  { 0x0001, 0x00010000, 0x00000000, 0x00000002, 0x15B3, 0x1003, 0x03, 0x10, 0x01, 0x02,
    0x00000006, 0xFF, 0xFF, 0xFFFFFFFF, 0x00000001, 0x00, 0x2E, 0xFFFF },
};

UINT32  mBusScanLimitTableCount = sizeof (mBusScanLimitTable) / sizeof (mBusScanLimitTable[0]);

//
// Table 2: Secondary bus scan limits (not populated for CLX64L).
//
UBA_OPROM_BUS_SCAN_LIMIT_ENTRY  mBusScanLimitTable2[10] = { 0 };
UINT32  mBusScanLimitTable2Count = 10;

//
// ---------------------------------------------------------------------------
// PCIe Slot Mapping Table (CLX64L)
//
// Maps physical PCIe Root Port (Bus/Device/Function) to logical slot numbers.
// 8 entries correspond to the 8 PCIe root ports on the CLX64L platform.
// ---------------------------------------------------------------------------
//
// NOTE: These entries are indexed by slot bit position. Entry[i] defines the
// BDF for slot bit i. The slot number in byte 3 is 0 for all entries since
// slot numbering is derived from the bit position (not an explicit number).
//
UBA_OPROM_SLOT_MAPPING  mSlotMappingTable[] = {
  { 0x00, 0x03, 0x00, 0x00 },   // Slot 0: Bus 0, Dev 3,  Func 0
  { 0x00, 0x01, 0x80, 0x00 },   // Slot 1: Bus 80h, Dev 1, Func 0 (PCH)
  { 0x00, 0x02, 0x80, 0x00 },   // Slot 2: Bus 80h, Dev 2, Func 0 (PCH)
  { 0x02, 0x03, 0x80, 0x00 },   // Slot 3: Bus 80h, Dev 3, Func 2 (PCH)
  { 0x00, 0x02, 0x00, 0x00 },   // Slot 4: Bus 0,  Dev 2, Func 0
  { 0x00, 0x01, 0x00, 0x00 },   // Slot 5: Bus 0,  Dev 1, Func 0
  { 0x05, 0x1C, 0x00, 0x00 },   // Slot 6: Bus 0,  Dev 1Ch, Func 5
  { 0x00, 0x03, 0x80, 0x00 },   // Slot 7: Bus 80h, Dev 3, Func 0 (PCH)
};

UINT32  mSlotMappingTableCount = sizeof (mSlotMappingTable) / sizeof (mSlotMappingTable[0]);

//
// UBA protocol instance. Registered with the UBA framework during
/// ModuleEntryPoint to provide CLX64L-specific OpROM update callbacks.
//
UBA_OPROM_UPDATE_PROTOCOL  mUbaOpromUpdateProtocol = {
  SetPcieSlotNumber,
  (EFI_GUID **)GetPcieSlotNumber,
  (VOID *)mBusScanLimitTable,
  (VOID *)mBusScanLimitTable2,
  SetPcieSlotCallback,
  0
};

//
// ---------------------------------------------------------------------------
// UBA Debug Print
//
// Writes a debug message through the UBA protocol's debug channel.
//
// @param[in]  DebugLevel  Debug level mask (typically 0x80000000 for UBA).
// @param[in]  Format      Print format string.
// @param[in]  ...         Variable arguments for format string.
// ---------------------------------------------------------------------------
//
VOID
UbaDebugPrint (
  IN UINT64  DebugLevel,
  IN CHAR8   *Format,
  ...
  )
{
  VA_LIST             Marker;
  UBA_OPROM_UPDATE_PROTOCOL  *Protocol;
  UINT64              CmosValue;
  UINT8               PlatformType;

  Protocol = GetUbaProtocol ();
  if (Protocol == NULL) {
    return;
  }

  //
  // Read CMOS register 0x70 to check platform type
  // CMOS 0x4B bit 7 = reserved, bits [1:0] = platform type
  // Type 0 = unknown, Type 1 = CLX platform, Type 2-3 = other
  //
  CmosValue = IoRead8 (0x70);
  IoWrite8 (0x70, (CmosValue & 0x80) | 0x4B);
  PlatformType = IoRead8 (0x71);

  if (PlatformType > 3) {
    if (PlatformType == 0) {
      PlatformType = (MmioRead8 (0xFDAF0490) & 2) | 1;
    }
  }

  if ((PlatformType - 1) <= 0xFD) {
    //
    // Platform type is valid (not -1/0xFF)
    //
    if (DebugLevel & 0x80000000) {
      if (PlatformType == 1) {
        //
        // CLX platform: write through debug function
        //
        VA_START (Marker, Format);
        // Output through registered UBA debug function (offset 0 in protocol)
        Protocol->SetPcieSlotCallback ((UINT8)DebugLevel);
        VA_END (Marker);
      }
    }
  }
}

//
// ---------------------------------------------------------------------------
// SetPcieSlotNumber
//
// Determines whether a given Bus/Device/Function is within the valid slot
// range for the specified slot bitmask on CLX64L.
//
// For each slot bit set in SlotMask, this function retrieves the PCI root
// bridge protocol, reads the bridge's bus number range (via
// SetAttributes with PCI attributes 0x19 and 0x1A), and checks whether
// BusDeviceFunction falls within that range.
//
// @param[in]  BusDeviceFunction  Encoded bus/device/function value to check.
// @param[in]  SlotMask           Bitmask of PCIe slots to check.
//
// @retval TRUE   BusDeviceFunction is valid for one of the enabled slots.
// @retval FALSE  BusDeviceFunction is not valid for any enabled slot.
//
// ---------------------------------------------------------------------------
//
BOOLEAN
EFIAPI
SetPcieSlotNumber (
  IN UINT64   BusDeviceFunction,
  IN UINT32   SlotMask
  )
{
  UINT32                   Index;
  UINT8                    *SlotEntry;
  EFI_STATUS               Status;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *RootBridgeIo;
  UINT64                   RootBridgeHandle;
  UINT8                    MinBus;
  UINT8                    MaxBus;
  BOOLEAN                  InRange;

  InRange = FALSE;
  SlotEntry = (UINT8 *)&mSlotMappingTable;
  DEBUG_CODE_BEGIN ();

  for (Index = 0; Index < mSlotMappingTableCount; Index++) {
    if ((SlotMask & (1 << Index)) == 0) {
      //
      // This slot is not enabled in the bitmask; skip it.
      //
      SlotEntry += sizeof (UBA_OPROM_SLOT_MAPPING);
      continue;
    }

    //
    // Locate the PCI Root Bridge I/O protocol for this root port.
    //
    Status = gBootServices->LocateProtocol (
                              &gEfiPciRootBridgeIoProtocolGuid,
                              NULL,
                              (VOID **)&RootBridgeHandle
                              );
    if (EFI_ERROR (Status)) {
      SlotEntry += sizeof (UBA_OPROM_SLOT_MAPPING);
      continue;
    }
    RootBridgeIo = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *)RootBridgeHandle;

    //
    // Build the PCI address from slot mapping entry:
    //   SlotEntry[-1] = Function
    //   SlotEntry[0]  = Device
    //   SlotEntry[1]  = Bus
    // These are packed into the "DeviceFunction" field used
    // for PCI root bridge operations.
    //
    {
      UINT8   Function;
      UINT8   Device;
      UINT8   Bus;

      Function = SlotEntry[-1];
      Device   = SlotEntry[0];
      Bus      = SlotEntry[1];

      //
      // Get bus number range for this root port.
      // Attribute 0x19 = Get primary bus number
      // Attribute 0x1A = Get secondary bus number (subordinate)
      //
      RootBridgeIo->SetAttributes (
                     RootBridgeIo,
                     0,
                     ((Bus << 16) | (Device << 11) | (Function << 8)) | 0x19,
                     1,
                     &MinBus
                     );
      RootBridgeIo->SetAttributes (
                     RootBridgeIo,
                     0,
                     ((Bus << 16) | (Device << 11) | (Function << 8)) | 0x1A,
                     1,
                     &MaxBus
                     );

      if (BusDeviceFunction >= MinBus) {
        InRange = (BOOLEAN)(BusDeviceFunction <= MaxBus);
      }
    }

    SlotEntry += sizeof (UBA_OPROM_SLOT_MAPPING);
  }

  DEBUG_CODE_END ();
  return InRange;
}

//
// ---------------------------------------------------------------------------
// GetPcieSlotNumber
//
// Returns a pointer to gEfiAcpiSupportProtocolGuid, which identifies the
// ACPI support protocol used for slot number querying.
//
// @param[out]  Guid  Pointer to receive the protocol GUID.
//
// @retval EFI_SUCCESS
//
// ---------------------------------------------------------------------------
//
UINTN
EFIAPI
GetPcieSlotNumber (
  IN EFI_GUID  **Guid
  )
{
  *Guid = &gEfiAcpiSupportProtocolGuid;
  return 0;
}

//
// ---------------------------------------------------------------------------
// GetBusScanLimit
//
// Returns the primary bus scan limit table for CLX64L.
// The table defines which PCIe devices on this platform have restricted
// bus ranges for enumeration.
//
// @param[out]  Table  Pointer to the bus scan limit entry table.
// @param[out]  Count  Number of entries in the table.
//
// @retval EFI_SUCCESS
//
// ---------------------------------------------------------------------------
//
UINTN
EFIAPI
GetBusScanLimit (
  IN VOID     **Table,
  IN UINT32   *Count
  )
{
  *Table = mBusScanLimitTable;
  *Count = mBusScanLimitTableCount;
  return 0;
}

//
// ---------------------------------------------------------------------------
// GetBusScanLimit2
//
// Returns the secondary bus scan limit table for CLX64L.
// This table is reserved and currently contains zero-initialized entries.
//
// @param[out]  Table  Pointer to the bus scan limit entry table.
// @param[out]  Count  Number of entries in the table.
//
// @retval EFI_SUCCESS
//
// ---------------------------------------------------------------------------
//
UINTN
EFIAPI
GetBusScanLimit2 (
  IN VOID     **Table,
  IN UINT32   *Count
  )
{
  *Table = mBusScanLimitTable2;
  *Count = mBusScanLimitTable2Count;
  return 0;
}

//
// ---------------------------------------------------------------------------
// SetPcieSlotCallback
//
// Called when a PCIe slot number assignment callback occurs.
// This function sets the slot value to 2 and logs the event.
//
// @param[in]  SlotNumber  The slot number being assigned.
//
// @retval EFI_SUCCESS
//
// ---------------------------------------------------------------------------
//
EFI_STATUS
EFIAPI
SetPcieSlotCallback (
  IN UINT8    SlotNumber
  )
{
  *((volatile UINT8 *)SlotNumber) = 2;
  UbaDebugPrint (UBA_DEBUG_LEVEL, "[UBA]:SetPcieSlotNumber callback - %d\n");
  return 0;
}

//
// ---------------------------------------------------------------------------
// GetUbaProtocol
//
// Retrieves the UBA protocol instance. On first call, searches the HOB list
// for the gEfiVariableArchProtocolGuid HOB and records the HOB data pointer.
//
// @return  Pointer to the UBA protocol structure, or NULL if not found.
//
// ---------------------------------------------------------------------------
//
EFI_HANDLE
GetUbaProtocol (
  VOID
  )
{
  EFI_HANDLE  Handle;

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

  //
  // Search the HOB list for the Variable Arch protocol HOB.
  // The HOB list is obtained from SystemTable->HobList.
  //
  Handle = NULL;
  mHobList = NULL;

  if (gSystemTable != NULL && gSystemTable->NumberOfTableEntries > 0) {
    UINTN   Index;
    UINTN   *HobList;

    HobList = (UINTN *)gSystemTable->ConfigurationTable;
    for (Index = 0; Index < gSystemTable->NumberOfTableEntries; Index++) {
      if (CompareGuid (
            (EFI_GUID *)HobList,
            &gEfiVariableArchProtocolGuid
            )) {
        Handle = (EFI_HANDLE)((UINT8 *)HobList + sizeof (EFI_GUID));
        mHobList = (VOID *)Handle;
        break;
      }
      HobList += 3;   // ConfigurationTable entries are 24 bytes each
    }

    if (Handle == NULL) {
      DEBUG ((DEBUG_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", EFI_INVALID_PARAMETER));
      ASSERT_EFI_ERROR (FALSE);
    }
  }

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

  return (EFI_HANDLE)mHobList;
}

//
// ---------------------------------------------------------------------------
// ReadUnaligned64
//
// Reads a 64-bit value from an unaligned address, with NULL pointer assertion.
//
// @param[in]  Buffer  Pointer to the unaligned 64-bit value.
//
// @return  The 64-bit value at Buffer.
//
// ---------------------------------------------------------------------------
//
UINT64
ReadUnaligned64 (
  IN CONST VOID  *Buffer
  )
{
  if (Buffer == NULL) {
    ASSERT (Buffer != NULL);
  }
  return *(const UINT64 *)Buffer;
}

//
// ---------------------------------------------------------------------------
// IsGuidMatch
//
// Compares two GUID values as a pair of 64-bit quantities.
//
// @param[in]  Guid1  First GUID to compare.
// @param[in]  Guid2  Second GUID to compare.
//
// @retval TRUE   GUIDs are equal.
// @retval FALSE  GUIDs are not equal.
//
// ---------------------------------------------------------------------------
//
BOOLEAN
IsGuidMatch (
  IN CONST EFI_GUID  *Guid1,
  IN CONST EFI_GUID  *Guid2
  )
{
  return (BOOLEAN)(
    ReadUnaligned64 (Guid1) == ReadUnaligned64 (Guid2) &&
    ReadUnaligned64 ((UINT8 *)Guid1 + 8) == ReadUnaligned64 ((UINT8 *)Guid2 + 8)
    );
}

//
// ---------------------------------------------------------------------------
// GetHobList
//
// Retrieves the HOB (Hand-Off Block) list pointer by searching the system
// configuration table for the gEfiHobListGuid entry.
//
// On first call, scans the configuration table, validates the retrieved HOB
// pointer, and caches it in the module global mHobList.
//
// @return  Pointer to the HOB list, or NULL if not found.
//
// ---------------------------------------------------------------------------
//
VOID *
GetHobList (
  VOID
  )
{
  EFI_STATUS  Status;
  VOID        *HobList;
  UINT64      EfiMemoryBase;
  UINTN       HobLength;

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

  //
  // The HOB list physical address is stored in the first configuration table
  // entry if the table reports at least 16 entries (EfiMemoryMap).
  //
  if (gBootServices == NULL) {
    return NULL;
  }

  Status = gBootServices->LocateProtocol (
                            &gEfiHobListGuid,
                            NULL,
                            (VOID **)&EfiMemoryBase
                            );
  if (EFI_ERROR (Status)) {
    return NULL;
  }

  if (EfiMemoryBase <= 0x10) {
    //
    // Memory base must be > 16 to be valid (below 16 is ISA/memory reserved).
    //
    Status = gBootServices->LocateProtocol (
                              &gEfiVariableArchProtocolGuid,
                              NULL,
                              &HobList
                              );
    if (EFI_ERROR (Status)) {
      HobList = NULL;
    }
    mHobList = HobList;
  } else {
    mHobList = NULL;
  }

  return mHobList;
}

//
// ---------------------------------------------------------------------------
// ModuleEntryPoint (also UefiMain)
//
// UEFI driver entry point for OpromUpdateDxeCLX64L.
//
// Initializes global service pointers (ImageHandle, SystemTable, BootServices,
// RuntimeServices), retrieves the HOB list, registers the CLX64L-specific
// UBA OpromUpdate configuration with the UBA framework.
//
// The UBA configuration includes:
//   - PCIe slot mapping table for CLX64L
//   - Bus scan limit tables for CLX64L-specific devices
//   - Slot assignment callback functions
//
// @param[in]  ImageHandle     The firmware allocated handle for the UEFI image.
// @param[in]  SystemTable     A pointer to the EFI System Table.
//
// @retval EFI_SUCCESS           The driver initialized successfully.
// @retval EFI_INVALID_PARAMETER A required protocol could not be located.
//
// ---------------------------------------------------------------------------
//
EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS                   Status;
  UBA_OPROM_UPDATE_PROTOCOL    *ConfigTable;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *RootBridgeIo;

  //
  // Save UEFI global pointers for library functions.
  //
  gImageHandle = ImageHandle;
  if (ImageHandle == NULL) {
    DEBUG ((
      DEBUG_ERROR,
      "%a(%d): %a\n",
      "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      51,
      "gImageHandle != ((void *) 0)"
      ));
    ASSERT (ImageHandle != NULL);
  }

  gSystemTable = SystemTable;
  if (SystemTable == NULL) {
    DEBUG ((
      DEBUG_ERROR,
      "%a(%d): %a\n",
      "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      57,
      "gST != ((void *) 0)"
      ));
    ASSERT (SystemTable != NULL);
  }

  gBootServices = SystemTable->BootServices;
  if (gBootServices == NULL) {
    DEBUG ((
      DEBUG_ERROR,
      "%a(%d): %a\n",
      "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      63,
      "gBS != ((void *) 0)"
      ));
    ASSERT (gBootServices != NULL);
  }

  gRuntimeServices = SystemTable->RuntimeServices;
  if (gRuntimeServices == NULL) {
    DEBUG ((
      DEBUG_ERROR,
      "%a(%d): %a\n",
      "e:\\hs\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c",
      47,
      "gRT != ((void *) 0)"
      ));
    ASSERT (gRuntimeServices != NULL);
  }

  //
  // Initialize the HOB list.
  //
  GetHobList ();

  //
  // Log the UBA OpromUpdate registration for CLX64L.
  //
  UbaDebugPrint (UBA_DEBUG_LEVEL, "UBA:OpromUpdate-TypeClx64L\n");

  //
  // Locate the PCI Root Bridge I/O protocol and install the UBA
  // OpromUpdate configuration table.
  //
  ConfigTable = &mUbaOpromUpdateProtocol;
  Status = gBootServices->LocateProtocol (
                            &gEfiPciRootBridgeIoProtocolGuid,
                            NULL,
                            (VOID **)&RootBridgeIo
                            );
  if (!EFI_ERROR (Status)) {
    //
    // Register the UBA configuration with the root bridge driver.
    // The configuration includes the slot mapping table, bus scan limits,
    // and callback functions.
    //
    Status = RootBridgeIo->SetAttributes (
                             RootBridgeIo,
                             0,
                             (UINT64)-1,   // Use default configuration
                             48,           // Size of UBA configuration structure
                             ConfigTable
                             );
  }

  return Status;
}