/** @file
IioCfgUpdateDxeLightningRidgeEXECB3 -- IIO Configuration Update DXE Driver
for the LightningRidge EX EC B3 platform.
This UEFI DXE driver configures Integrated IO (IIO) PCIe bus topology for
the LightningRidge EX EC B3 platform. It operates as a UBA (Universal BIOS
Architecture) board-type driver, registering IIO configuration data tables
via the UBA protocol's AddConfig interface.
== Architecture ==
1. ModuleEntryPoint caches UEFI globals (gImageHandle, gST, gBS, gRT)
2. GetHobList() resolves the HOB list via SystemTable->ConfigurationTable
3. IioCfgUpdateEntryPoint() emits the platform banner and locates the
UBA IIO configuration protocol
4. Four IIO PCIe topology configuration tables are registered, each keyed
by a distinct GUID and described by a "PIIO" header (48 bytes):
Table 1: {0x36232936-0E76-31C8-A13A-3AF2FC1C3932}
Table 2: {0x0F722F2A-650F-448A-ABB7-04EECD75BB30}
Table 3: {0xE03E0D46-5263-4845-B0A4-58D57B3177E2}
Table 4: {0xEBD11A00-8C5C-4F71-BB9E-5394032B01F4}
== Binary Info ==
File: IioCfgUpdateDxeLightningRidgeEXECB3.efi
Index: 30 of 427 PE files in HR650X BIOS
Size: 3776 bytes (0xEC0)
SHA256: 5698c437729140af878cef496aaeeaaa2e1222aca5686eec31ff9c9d6dd47d4d
MD5: f38f5e2647ef28abb5bc010b20b0fe2d
Arch: X64
PDB: IioCfgUpdateDxeLightningRidgeEXECB3.pdb
Copyright (c) 2023-2026, Dell Inc. and/or its affiliates. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "IioCfgUpdateDxeLightningRidgeEXECB3.h"
/*==============================================================================
* GUID Definitions (stored in .rdata / .data at fixed image offsets)
*============================================================================*/
///
/// UBA IIO Configuration Protocol GUID
/// Image offset: 0xBC0 (16 bytes)
///
STATIC CONST EFI_GUID mUbaIioCfgProtocolGuid = UBA_IIO_CFG_PROTOCOL_GUID;
///
/// IIO Table 1 GUID
/// Image offset: 0xBD0 (16 bytes)
///
STATIC CONST EFI_GUID mIioCfgTable1Guid = IIO_CFG_TABLE_1_GUID;
///
/// IIO Table 2 GUID
/// Image offset: 0xBE0 (16 bytes)
///
STATIC CONST EFI_GUID mIioCfgTable2Guid = IIO_CFG_TABLE_2_GUID;
///
/// IIO Table 3 GUID
/// Image offset: 0xBF0 (16 bytes)
///
STATIC CONST EFI_GUID mIioCfgTable3Guid = IIO_CFG_TABLE_3_GUID;
///
/// IIO Table 4 GUID
/// Image offset: 0xC00 (16 bytes)
///
STATIC CONST EFI_GUID mIioCfgTable4Guid = IIO_CFG_TABLE_4_GUID;
///
/// EFI HOB List GUID
/// Image offset: 0xC10 (16 bytes)
/// Used by IsHobListGuid() to identify the HOB list in ConfigurationTable[].
///
STATIC CONST EFI_GUID mEfiHobListGuid = EFI_HOB_LIST_GUID;
///
/// UBA Debug Library Protocol GUID
/// Image offset: 0xBD0 (duplicate of IIO Table 1 GUID -- the decompiler
/// references 0xBD0 as the debug lib protocol GUID in sub_510).
///
STATIC CONST EFI_GUID mUbaDebugLibProtocolGuid = UBA_DEBUG_LIB_PROTOCOL_GUID;
/*==============================================================================
* Global Variable Definitions (.data segment)
*============================================================================*/
///
/// gImageHandle -- UEFI image handle for this driver.
/// Image offset: 0xDB0
///
EFI_HANDLE gImageHandle = NULL;
///
/// gST -- UEFI System Table pointer.
/// Image offset: 0xDA0
///
EFI_SYSTEM_TABLE *gST = NULL;
///
/// gBS -- UEFI Boot Services pointer.
/// Image offset: 0xDA8
///
EFI_BOOT_SERVICES *gBS = NULL;
///
/// gRT -- UEFI Runtime Services pointer.
/// Image offset: 0xDB8
///
EFI_RUNTIME_SERVICES *gRT = NULL;
///
/// mUbaDebugProtocol -- Cached UBA debug protocol pointer.
/// Image offset: 0xDC0
/// Resolved lazily by LocateUbaDebugProtocol().
///
VOID *mUbaDebugProtocol = NULL;
///
/// mHobList -- Cached HOB list pointer.
/// Image offset: 0xDC8
/// Resolved lazily by GetHobList().
///
VOID *mHobList = NULL;
/*==============================================================================
* IIO Configuration Table Header (PIIO)
*
* This 48-byte structure at image offset 0xD30 describes the IIO PCIe
* topology configuration data block:
*
* Signature: "PIIO"
* Version: 1
* EntrySize: 0xD60 (3424 bytes per entry)
* EntryCount: 60 (0x3C)
* TableSize: 0x50C (1292 bytes)
* CfgOffset: 0xC30 (3120 bytes from header)
* CfgSize: 0xFC (252 bytes of config data)
*
* The configuration data itself is small (0xFC = 252 bytes) but the entry
* size is large (0xD60) -- this suggests the entries define broad IIO stack
* parameters per PCIe root port with sparse encoding, or the entry size
* includes padding for hardware register layout alignment.
*============================================================================*/
STATIC CONST IIO_CFG_TABLE_HEADER mIioCfgHeader = {
.Signature = { 'P', 'I', 'I', 'O' },
.Version = 1,
.EntrySize = 0xD60,
.EntryCount = 60,
.TableSize = 0x50C,
.CfgOffset = 0xC30,
.CfgSize = 0xFC,
};
/*==============================================================================
* Function Implementations
*============================================================================*/
/**
UEFI DXE driver entry point for IioCfgUpdateDxeLightningRidgeEXECB3.
Called by the DXE Dispatcher after all dependencies are satisfied.
Performs the following initialization sequence:
1. Cache ImageHandle and SystemTable pointers into global variables.
2. Validate non-NULL: ImageHandle, SystemTable, BootServices,
RuntimeServices (triggers UBA assert on failure).
3. Resolve the HOB list via GetHobList().
4. Dispatch the IIO configuration update via IioCfgUpdateEntryPoint().
@param[in] ImageHandle Handle for this driver image.
@param[in] SystemTable Pointer to the UEFI system table.
@return EFI_SUCCESS IIO configuration registered successfully.
@return EFI_UNSUPPORTED/... Protocol Locate or AddConfig failure.
**/
EFI_STATUS
EFIAPI
ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// Step 1: Cache UEFI standard pointers globally.
//
gImageHandle = ImageHandle;
gST = SystemTable;
//
// Step 2: Validate non-NULL and cache boot/runtime services.
//
if (ImageHandle == NULL) {
UbaDebugPrint (
0x80000000,
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c"
);
UbaDebugAssert (
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
51,
"gImageHandle != ((void *) 0)"
);
}
gBS = SystemTable->BootServices;
if (SystemTable == NULL) {
UbaDebugPrint (
0x80000000,
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c"
);
UbaDebugAssert (
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
57,
"gST != ((void *) 0)"
);
}
if (gBS == NULL) {
UbaDebugPrint (
0x80000000,
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c"
);
UbaDebugAssert (
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
63,
"gBS != ((void *) 0)"
);
}
gRT = SystemTable->RuntimeServices;
if (gRT == NULL) {
UbaDebugPrint (
0x80000000,
"e:\\hs\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c"
);
UbaDebugAssert (
"e:\\hs\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c",
47,
"gRT != ((void *) 0)"
);
}
//
// Step 3: Resolve the HOB list (cached in mHobList).
//
GetHobList ();
//
// Step 4: Dispatch the IIO configuration update.
//
Status = IioCfgUpdateEntryPoint ();
return Status;
}
/**
Entry point for IIO configuration table registration.
Registers four IIO PCIe topology configuration data tables through the
UBA protocol's AddConfig interface. Each registration provides a table
GUID and the same IIO_CFG_TABLE_HEADER (PIIO struct) with data size 48.
Sequence:
1. Emit the platform identification banner via UbaDebugPrint.
2. Locate the UBA IIO configuration protocol by GUID
{0x6FE6C559-4F35-4111-98E1-332A251512F3} via gBS->LocateProtocol().
3. Call the protocol's AddConfig function (vtable index 2, offset 0x10)
four times, once per table GUID, passing the PIIO header and size 48.
4. Return immediately on first failure.
@return EFI_SUCCESS All four tables registered successfully.
@return EFI_UNSUPPORTED Protocol GUID not found.
@return EFI_INVALID_PARAMETER AddConfig call failed for a table.
**/
EFI_STATUS
IioCfgUpdateEntryPoint (
VOID
)
{
EFI_STATUS Status;
VOID *UbaProtocol; ///< Located UBA protocol interface
//
// Step 1: Initialize output variable and emit platform banner.
//
UbaProtocol = NULL;
UbaDebugPrint (
0x80000000,
"UBA:IioCfgUpdate-TypeLightningRidgeEXECB3\n"
);
//
// Step 2: Locate the UBA IIO configuration protocol.
//
Status = gBS->LocateProtocol (
&mUbaIioCfgProtocolGuid,
NULL,
&UbaProtocol
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Step 3: Register the four IIO PCIe topology configuration tables.
// Each call passes the same PIIO header structure (48 bytes) but keyed
// by a different table GUID.
//
// The AddConfig function is at vtable index 2 (offset 0x10):
// EFI_STATUS (*AddConfig)(
// VOID *This,
// CONST EFI_GUID *ConfigGuid,
// CONST VOID *ConfigData,
// UINTN ConfigDataSize
// );
//
//
// Table 1: Primary IIO topology
//
Status = ((EFI_STATUS (*)(VOID *, CONST EFI_GUID *, CONST VOID *, UINTN))
(*((UINT64 **)UbaProtocol) + 2)) (
UbaProtocol,
&mIioCfgTable1Guid,
&mIioCfgHeader,
sizeof (IIO_CFG_TABLE_HEADER)
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Table 2: Secondary IIO topology
//
Status = ((EFI_STATUS (*)(VOID *, CONST EFI_GUID *, CONST VOID *, UINTN))
(*((UINT64 **)UbaProtocol) + 2)) (
UbaProtocol,
&mIioCfgTable2Guid,
&mIioCfgHeader,
sizeof (IIO_CFG_TABLE_HEADER)
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Table 3: Tertiary IIO topology
//
Status = ((EFI_STATUS (*)(VOID *, CONST EFI_GUID *, CONST VOID *, UINTN))
(*((UINT64 **)UbaProtocol) + 2)) (
UbaProtocol,
&mIioCfgTable3Guid,
&mIioCfgHeader,
sizeof (IIO_CFG_TABLE_HEADER)
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Table 4: Quaternary IIO topology
//
Status = ((EFI_STATUS (*)(VOID *, CONST EFI_GUID *, CONST VOID *, UINTN))
(*((UINT64 **)UbaProtocol) + 2)) (
UbaProtocol,
&mIioCfgTable4Guid,
&mIioCfgHeader,
sizeof (IIO_CFG_TABLE_HEADER)
);
return Status;
}
/**
Locates the UBA debug protocol (lazy init with caching).
On first call, performs a pool size sanity check (allocate 31 bytes, if
only <= 0x10 bytes available, returns NULL) then calls gBS->LocateProtocol()
using the UBA debug protocol GUID. The result is cached in mUbaDebugProtocol.
@return Pointer to the UBA debug protocol interface, or NULL if unavailable.
**/
VOID *
LocateUbaDebugProtocol (
VOID
)
{
UINT64 PoolSize; ///< Pool allocation for size check
//
// Return cached pointer if already resolved.
//
if (mUbaDebugProtocol != NULL) {
return mUbaDebugProtocol;
}
//
// Perform pool size sanity check.
// Allocate and immediately free a 31-byte buffer. If the returned pool
// size is <= 0x10, the system is in a state where protocol resolution
// would also fail, so bail out early.
//
gBS->AllocatePool (EfiBootServicesData, 31, (VOID **)&PoolSize);
gBS->FreePool ((VOID *)PoolSize);
if (PoolSize <= 0x10) {
mUbaDebugProtocol = NULL;
return NULL;
}
//
// Locate the UBA debug protocol.
//
mUbaDebugProtocol = NULL;
gBS->LocateProtocol (
&mUbaDebugLibProtocolGuid,
NULL,
&mUbaDebugProtocol
);
return mUbaDebugProtocol;
}
/**
Platform-aware debug print via the UBA debug protocol.
Reads CMOS register 0x4B (via legacy I/O ports 0x70/0x71) to determine
the board platform type, which selects the debug output mask:
Platform type 1 (LightningRidge):
Debug mask = 0x80000004
Platform type 2 or 3 (other IIO variants):
Debug mask = 0x80000006
If CMOS register 0x4B reads as 0, falls back to MMIO read at physical
address 0xFDAF0490 (GPIO/strapping register), extracting bit 1 ORed
with 1 to derive the platform type.
Debug output is only emitted when (ErrorLevel & DebugMask) != 0.
@param[in] ErrorLevel Debug message severity level mask.
@param[in] Format Printf-compatible format string.
@param[in] ... Variable arguments for format string.
@return Non-zero if debug output was emitted or successfully suppressed.
@return 0 Debug protocol not available.
**/
UINTN
EFIAPI
UbaDebugPrint (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
VA_LIST VaList;
VOID *Protocol;
UINT8 CmosValue;
UINTN PlatformType;
UINTN DebugMask;
//
// Resolve the UBA debug protocol (lazy init).
//
Protocol = LocateUbaDebugProtocol ();
if (Protocol == NULL) {
return 0;
}
//
// Read CMOS register 0x4B to determine the board platform type.
// Access sequence:
// 1. Read CMOS index register (I/O port 0x70) to preserve NMI bit
// 2. Write index with (NMI_disabled | 0x4B) to select register 0x4B
// 3. Read data from CMOS data register (I/O port 0x71)
//
CmosValue = IoRead8 (0x70);
IoWrite8 (0x70, (CmosValue & 0x80) | 0x4B);
PlatformType = IoRead8 (0x71);
//
// Determine platform type from CMOS value.
// If value is > 3 and equals 0, fall back to MMIO strapping register.
//
if (PlatformType > 3) {
if (PlatformType == 0) {
PlatformType = (*(volatile UINT8 *)(UINTN)0xFDAF0490 & 2) | 1;
}
}
//
// Select debug mask based on platform type.
// Type 1 = LightningRidge, others use a broader mask.
//
if (PlatformType == 1) {
DebugMask = 0x80000004;
} else {
DebugMask = 0x80000006;
}
//
// Check if the error level matches the platform debug mask.
//
if ((DebugMask & ErrorLevel) == 0) {
return 4;
}
//
// Call the protocol's DebugPrint function (vtable offset 0x00).
//
VA_START (VaList, Format);
return ((UINTN (*)(UINTN, CONST CHAR8 *, VA_LIST))
(*(UINT64 *)Protocol)) (
ErrorLevel,
Format,
VaList
);
}
/**
ASSERT failure handler via the UBA debug protocol.
Called when an ASSERT() condition evaluates to FALSE. Routes to the
UBA debug protocol's assertion handler at vtable offset 0x08.
@param[in] FileName Full path to the source file containing the assert.
@param[in] LineNumber Line number of the assertion.
@param[in] Description Text description of the failing assertion condition.
**/
VOID
EFIAPI
UbaDebugAssert (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
)
{
VOID *Protocol;
//
// Resolve the UBA debug protocol (lazy init).
//
Protocol = LocateUbaDebugProtocol ();
if (Protocol != NULL) {
//
// Call the protocol's assertion handler (vtable offset 0x08).
//
((VOID (*)(CONST CHAR8 *, UINTN, CONST CHAR8 *))
(*((UINT64 *)Protocol + 1))) (
FileName,
LineNumber,
Description
);
}
}
/**
Retrieves the HOB (Hand-Off Block) list pointer from the UEFI system table.
Scans gST->ConfigurationTable[] for the entry whose VendorGuid matches
EFI_HOB_LIST_GUID ({7739F24C-93D7-11D4-9A3A-0090273FC14D}). The associated
VendorTable pointer is the HOB list. Result is cached in mHobList.
If the GUID is not found in any configuration table entry, or if the
resolved pointer is NULL, triggers UBA debug assertions.
@return Pointer to the HOB list, or NULL if not found.
**/
VOID *
GetHobList (
VOID
)
{
UINTN Index;
EFI_CONFIGURATION_TABLE *ConfigTable;
UINTN TableCount;
//
// Return cached pointer if already resolved.
//
if (mHobList != NULL) {
return mHobList;
}
//
// Initialize cache to NULL before scanning.
//
mHobList = NULL;
TableCount = gST->NumberOfTableEntries;
ConfigTable = gST->ConfigurationTable;
//
// Scan the configuration table array for the HOB list GUID.
//
if (ConfigTable != NULL) {
for (Index = 0; Index < TableCount; Index++) {
if (IsHobListGuid (&ConfigTable[Index].VendorGuid)) {
mHobList = (VOID *)ConfigTable[Index].VendorTable;
break;
}
}
}
//
// If the GUID was not found, trigger a debug assert.
//
if (mHobList == NULL) {
UbaDebugPrint (
0x80000000,
"\nASSERT_EFI_ERROR (Status = %r)\n",
0x800000000000000EULL // EFI_NOT_FOUND
);
UbaDebugAssert (
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
54,
"!EFI_ERROR (Status)"
);
}
//
// If the resolved pointer itself is NULL, trigger another assert.
//
if (mHobList == NULL) {
UbaDebugAssert (
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
55,
"mHobList != ((void *) 0)"
);
}
return mHobList;
}
/**
Compares a GUID against EFI_HOB_LIST_GUID using 64-bit wide comparisons.
Both the input GUID and the reference EFI_HOB_LIST_GUID are split into
two 64-bit halves and compared via ReadUnaligned64().
@param[in] Guid Pointer to the GUID to compare.
@return TRUE The GUID matches EFI_HOB_LIST_GUID.
@return FALSE The GUID does not match.
**/
BOOLEAN
IsHobListGuid (
IN EFI_GUID *Guid
)
{
//
// Compare GUID as two 64-bit halves.
//
return (ReadUnaligned64 (&mEfiHobListGuid) == ReadUnaligned64 (Guid))
&& (ReadUnaligned64 ((UINT8 *)&mEfiHobListGuid + 8)
== ReadUnaligned64 ((UINT8 *)Guid + 8));
}
/**
Reads a 64-bit value from a (possibly unaligned) memory address.
Directly dereferences a 64-bit pointer. Asserts via UbaDebugAssert()
if the pointer is NULL.
@param[in] Buffer Pointer to read from (must not be NULL).
@return The 64-bit value at the Buffer address.
**/
UINT64
ReadUnaligned64 (
IN CONST VOID *Buffer
)
{
//
// Validate buffer pointer is not NULL.
//
if (Buffer == NULL) {
UbaDebugAssert (
"e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
192,
"Buffer != ((void *) 0)"
);
}
//
// Dereference directly.
//
return *(CONST UINT64 *)Buffer;
}