/** @file
IioCfgUpdateDxeLightningRidgeEXECB4.c
IIO Configuration Update DXE driver for the LightningRidge EX EC B4 platform.
This DXE driver registers platform-specific IIO (Integrated I/O) configuration
data with the UBA (Universal BIOS Architecture) framework for the LightningRidge
EX EC B4 platform.
The driver flow:
1. Initialize gImageHandle, gST, gBS, gRT global pointers (standard DXE entry)
2. Locate the IIO configuration HOB via the HOB list in SystemTable
3. Print debug banner "UBA:IioCfgUpdate-TypeLightningRidgeEXECB4"
4. Locate the UBA IIO configuration protocol
5. Dispatch the IIO config platform data header (48 bytes) to four
GUID-registered protocol instances (one per IIO stack)
The IIO configuration data header uses signature "PIIO" and describes:
- Bifurcation mapping (60 entries) starting at offset 0x3C from header
- PCIe slot configuration count: 1292
- SMBUS configuration count: 3120
- Reserved value: 252
Copyright (C) 2024-2026, Insyde Software Corp. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/DxeHobLib.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/IoLib.h>
#include "IioCfgUpdateDxeLightningRidgeEXECB4.h"
//
// ---------------------------------------------------------------------------
// Global data: IIO configuration platform data header
// ---------------------------------------------------------------------------
//
// This 48-byte structure is the Platform IIO config descriptor dispatched to
// each UBA protocol instance. The bifurcation mapping table follows at the
// byte offset indicated by BifurMapEntryCount acting as the offset (0x3C).
//
STATIC CONST IIO_CFG_PLATFORM_DATA_HEADER mIioCfgPlatformData = {
.Signature = SIGNATURE_32 ('P', 'I', 'I', 'O'), // 0x4F494950
.Revision = 1,
.TotalDataSize = 0xD60, // 3424 bytes total config
.Reserved0 = 0,
.BifurMapEntryCount = 60, // 60 bifurcation entries (offset 0x3C)
.Reserved1 = 0,
.SlotConfigCount = 0x50C, // 1292 slot config entries
.Reserved2 = 0,
.SmbusConfigCount = 0xC30, // 3120 SMBUS config entries
.Reserved3 = 0,
.Reserved4 = 0xFC, // 252 reserved
.Reserved5 = 0
};
//
// ---------------------------------------------------------------------------
// Static variables
// ---------------------------------------------------------------------------
STATIC VOID *mIioCfgProtocol = NULL; ///< Cached UBA IIO config protocol
STATIC VOID *mIioCfgHobList = NULL; ///< Cached IIO config HOB list
//
// ---------------------------------------------------------------------------
// GUID definitions used by this driver
// ---------------------------------------------------------------------------
STATIC CONST EFI_GUID mUbaIioCfgProtocolGuid = UBA_IIO_CFG_PROTOCOL_GUID;
STATIC CONST EFI_GUID mUbaIioCfgUpdateGuid = UBA_IIO_CFG_UPDATE_PROTOCOL_GUID;
STATIC CONST EFI_GUID mUbaIioCfgProtocolGuid2 = UBA_IIO_CFG_PROTOCOL_GUID_2;
STATIC CONST EFI_GUID mUbaIioCfgProtocolGuid3 = UBA_IIO_CFG_PROTOCOL_GUID_3;
STATIC CONST EFI_GUID mUbaIioCfgProtocolGuid4 = UBA_IIO_CFG_PROTOCOL_GUID_4;
//
// The HOB list is identified by gEfiHobListGuid, but the specific HOB
// entry this driver looks for matches the GUID at 0xC18.
//
STATIC CONST EFI_GUID mIioCfgHobTargetGuid = IIO_CFG_HOB_GUID;
STATIC CONST EFI_GUID mEfiHobListGuid = HOB_LIST_GUID;
//
// ---------------------------------------------------------------------------
// Debug protocol lookup (cached)
// ---------------------------------------------------------------------------
/**
Locate and cache the UBA IIO configuration protocol.
Attempts to locate the protocol identified by mUbaIioCfgProtocolGuid
(GUID: 6FE6C559-4F35-4111-98E1-332A251512F3). The result is cached
in mIioCfgProtocol for subsequent calls.
@return Pointer to the UBA IIO config protocol interface, or NULL on failure.
**/
STATIC
VOID *
GetUbaConfigProtocol (
VOID
)
{
EFI_STATUS Status;
if (mIioCfgProtocol != NULL) {
return mIioCfgProtocol;
}
Status = gBS->LocateProtocol (
(EFI_GUID *)&mUbaIioCfgProtocolGuid,
NULL,
&mIioCfgProtocol
);
if (EFI_ERROR (Status)) {
mIioCfgProtocol = NULL;
}
return mIioCfgProtocol;
}
//
// ---------------------------------------------------------------------------
// CMOS debug output
// ---------------------------------------------------------------------------
/**
Debug print function utilizing CMOS ports 0x70/0x71 for platform debug
output routing.
The debug level is determined by:
1. Reading CMOS index 0x4B (port 0x70, 0x71)
2. If value > 3 and value != 0, it is used as-is
3. If value == 0, reading MMIO register 0xFEDAF0490 bit 1
4. The effective debug level is (CmosValue - 1)
@param[in] ErrorLevel Debug error level (e.g., 0x80000000 for error).
@param[in] Format Format string.
@param[in] ... Variable argument list.
**/
STATIC
VOID
EFIAPI
DebugLogPrint (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
UINT8 CmosValue;
UINT8 DebugLevel;
VOID *UbaProtocol;
VA_LIST VaList;
VA_START (VaList, Format);
//
// Access CMOS debug routing register
//
IoWrite8 (0x70, (IoRead8 (0x70) & 0x80) | 0x4B);
CmosValue = IoRead8 (0x71);
if (CmosValue > 3) {
//
// If value == 0, check MMIO-based debug enable
//
if (CmosValue == 0) {
CmosValue = (MmioRead8 (0xFEDAF0490) & 2) | 1;
}
}
DebugLevel = CmosValue - 1;
if (DebugLevel <= 0xFD) {
DebugLevel = 4;
}
//
// Route to UBA protocol debug output if available
//
UbaProtocol = GetUbaConfigProtocol ();
if (UbaProtocol != NULL) {
//
// Protocol interface at offset +8 is the DebugPrint function
//
((EFI_STATUS (EFIAPI *)(VOID *, UINTN, CONST CHAR8 *, VA_LIST))
((UINT64 *)UbaProtocol)[1]) (UbaProtocol, ErrorLevel, Format, VaList);
}
VA_END (VaList);
}
//
// ---------------------------------------------------------------------------
// ASSERT handler
// ---------------------------------------------------------------------------
/**
Assertion failure handler. Displays the failed assertion via the UBA
debug protocol.
@param[in] FileName Source file name where the assertion occurred.
@param[in] LineNumber Line number of the assertion.
@param[in] Description Assertion expression text.
**/
STATIC
VOID
EFIAPI
DebugAssertHandler (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
)
{
VOID *UbaProtocol;
UbaProtocol = GetUbaConfigProtocol ();
if (UbaProtocol != NULL) {
//
// Protocol interface at offset +8 is the DebugPrint function,
// but here we call it in ASSERT mode (no VA_LIST needed)
//
((EFI_STATUS (EFIAPI *)(CONST CHAR8 *, UINTN, CONST CHAR8 *))
((UINT64 *)UbaProtocol)[1]) (FileName, LineNumber, Description);
}
}
//
// ---------------------------------------------------------------------------
// Unaligned memory access
// ---------------------------------------------------------------------------
/**
Reads a 64-bit value from an unaligned memory address.
ASSERTs if Buffer is NULL.
@param[in] Buffer Pointer to the unaligned 64-bit value.
@return The 64-bit value at Buffer.
**/
STATIC
UINT64
ReadUnaligned64 (
IN CONST VOID *Buffer
)
{
ASSERT (Buffer != NULL);
return *(UINT64 *)Buffer;
}
//
// ---------------------------------------------------------------------------
// GUID comparison (as two UINT64 values)
// ---------------------------------------------------------------------------
/**
Compares two GUIDs by treating them as two UINT64 values each.
@param[in] Guid1 Pointer to first GUID.
@param[in] Guid2 Pointer to second GUID.
@return TRUE if the GUIDs match, FALSE otherwise.
**/
STATIC
BOOLEAN
CompareGuid (
IN EFI_GUID *Guid1,
IN EFI_GUID *Guid2
)
{
if (ReadUnaligned64 (Guid1) == ReadUnaligned64 (Guid2) &&
ReadUnaligned64 ((UINT8 *)Guid1 + 8) == ReadUnaligned64 ((UINT8 *)Guid2 + 8)) {
return TRUE;
}
return FALSE;
}
//
// ---------------------------------------------------------------------------
// HOB list retrieval
// ---------------------------------------------------------------------------
/**
Retrieves the IIO configuration HOB from the UEFI System Table HOB list.
Walks the HOB array (SystemTable + 0x68 holds count, + 0x70 holds pointer).
Each HOB entry is 24 bytes:
[0:8] GUID first QWORD
[8:16] GUID second QWORD
[16:24] Data pointer
Searches for a HOB whose GUID matches mIioCfgHobTargetGuid.
@return Pointer to the IIO config HOB data, or NULL if not found.
**/
STATIC
VOID *
GetIioConfigHobList (
VOID
)
{
UINTN HobCount;
UINTN Index;
VOID *HobArray;
UINT64 TargetGuid0;
UINT64 TargetGuid1;
//
// Return cached result
//
if (mIioCfgHobList != NULL) {
return mIioCfgHobList;
}
mIioCfgHobList = NULL;
//
// SystemTable HOB fields:
// +0x68 = Number of HOBs
// +0x70 = Pointer to HOB array
//
HobCount = *(UINTN *)((UINT8 *)gST + 0x68);
if (HobCount != 0) {
HobArray = *(VOID **)((UINT8 *)gST + 0x70);
TargetGuid0 = ReadUnaligned64 (&mIioCfgHobTargetGuid);
TargetGuid1 = ReadUnaligned64 ((UINT8 *)&mIioCfgHobTargetGuid + 8);
//
// Linear scan through HOB array (each entry 24 bytes)
//
for (Index = 0; Index < HobCount; Index++) {
//
// Compare GUID at HOB entry offset 0
//
if (ReadUnaligned64 ((UINT8 *)HobArray + Index * 24) == TargetGuid0 &&
ReadUnaligned64 ((UINT8 *)HobArray + Index * 24 + 8) == TargetGuid1) {
//
// Found -- data pointer at HOB entry offset 0x10
//
mIioCfgHobList = *(VOID **)((UINT8 *)HobArray + Index * 24 + 0x10);
return mIioCfgHobList;
}
}
}
//
// HOB not found -- trigger assertion
//
DebugLogPrint (0x80000000, L"\nASSERT_EFI_ERROR (Status = %r)\n");
DebugAssertHandler (
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
0x36,
"!EFI_ERROR (Status)"
);
if (mIioCfgHobList == NULL) {
DebugAssertHandler (
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
0x37,
"mHobList != ((void *) 0)"
);
}
return mIioCfgHobList;
}
//
// ---------------------------------------------------------------------------
// IIO configuration platform data registration
// ---------------------------------------------------------------------------
/**
Register the IIO configuration platform data with UBA protocol instances.
Locates the UBA IIO configuration protocol (GUID E03E0D46-5263-4845-B0A4-58D57B3177E2),
then calls the protocol's SetData function (at offset +0x10) for each of the
four IIO stack GUIDs:
1. UBA_IIO_CFG_PROTOCOL_GUID (6FE6C559-...)
2. UBA_IIO_CFG_UPDATE_PROTOCOL_GUID (0F722F2A-...)
3. UBA_IIO_CFG_PROTOCOL_GUID_3 (EBD11A00-...)
4. UBA_IIO_CFG_PROTOCOL_GUID_4 (82D03B12-...)
Each call passes the same 48-byte IIO_CFG_PLATFORM_DATA_HEADER, which the
protocol uses to register per-stack bifurcation and slot config data.
@return EFI_SUCCESS if all registrations succeed, or the first error status.
**/
EFI_STATUS
RegisterIioConfigPlatformData (
VOID
)
{
EFI_STATUS Status;
VOID *UbaProtocol;
//
// Locate the UBA IIO configuration protocol
//
Status = gBS->LocateProtocol (
(EFI_GUID *)&mUbaIioCfgProtocolGuid2, // E03E0D46-...
NULL,
&UbaProtocol
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Register config data for each IIO stack GUID
// Protocol function at offset +0x10 = SetPlatformData(This, RegisterGuid, DataBuffer, DataSize)
//
Status = ((EFI_STATUS (EFIAPI *)(
VOID *, // This
EFI_GUID *, // Register GUID
VOID *, // Data buffer
UINTN // Data size
))((UINT64 *)UbaProtocol)[2])(
UbaProtocol,
(EFI_GUID *)&mUbaIioCfgProtocolGuid, // 6FE6C559-...
(VOID *)&mIioCfgPlatformData,
sizeof (mIioCfgPlatformData) // 48 bytes
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Second stack registration
//
Status = ((EFI_STATUS (EFIAPI *)(
VOID *,
EFI_GUID *,
VOID *,
UINTN
))((UINT64 *)UbaProtocol)[2])(
UbaProtocol,
(EFI_GUID *)&mUbaIioCfgUpdateGuid, // 0F722F2A-...
(VOID *)&mIioCfgPlatformData,
sizeof (mIioCfgPlatformData)
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Third stack registration
//
Status = ((EFI_STATUS (EFIAPI *)(
VOID *,
EFI_GUID *,
VOID *,
UINTN
))((UINT64 *)UbaProtocol)[2])(
UbaProtocol,
(EFI_GUID *)&mUbaIioCfgProtocolGuid3, // EBD11A00-...
(VOID *)&mIioCfgPlatformData,
sizeof (mIioCfgPlatformData)
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Fourth stack registration
//
Status = ((EFI_STATUS (EFIAPI *)(
VOID *,
EFI_GUID *,
VOID *,
UINTN
))((UINT64 *)UbaProtocol)[2])(
UbaProtocol,
(EFI_GUID *)&mUbaIioCfgProtocolGuid4, // 82D03B12-...
(VOID *)&mIioCfgPlatformData,
sizeof (mIioCfgPlatformData)
);
return Status;
}
//
// ---------------------------------------------------------------------------
// Driver entry point
// ---------------------------------------------------------------------------
/**
Main entry point for the IioCfgUpdateDxeLightningRidgeEXECB4 driver.
Initializes the UEFI global service pointers (gImageHandle, gST, gBS, gRT),
retrieves the IIO configuration HOB, prints a debug banner, then dispatches
the IIO configuration platform data to the UBA protocol.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS Driver initialized and IIO config registered.
@retval EFI_UNSUPPORTED UBA protocol not found.
@retval other Error from RegisterIioConfigPlatformData.
**/
EFI_STATUS
EFIAPI
_ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
//
// Initialize global UEFI service pointer cache
//
gImageHandle = ImageHandle;
ASSERT (ImageHandle != NULL);
gST = SystemTable;
ASSERT (SystemTable != NULL);
gBS = SystemTable->BootServices;
ASSERT (gBS != NULL);
gRT = SystemTable->RuntimeServices;
ASSERT (gRT != NULL);
//
// Retrieve the IIO configuration HOB list (locates HOBs in SystemTable)
//
GetIioConfigHobList ();
//
// Print platform identification string
//
DebugLogPrint (0x80000000, "UBA:IioCfgUpdate-TypeLightningRidgeEXECB4\n");
//
// Register IIO configuration platform data
//
return RegisterIioConfigPlatformData ();
}