/**
* @file StaticSkuDataDxeNeonCityFPGA.c
*
* @brief Static SKU Data DXE driver for NeonCity FPGA platform.
*
* This driver installs three configuration tables into the ACPI
* configuration table system:
* 1. UMPT (Ubox/Memory topology) -- 24 bytes at 0x4090
* 2. PIRQ (PCI IRQ routing) -- 16 bytes at 0x40B8
* 3. ACPF (ACPI Platform SKU cfg) -- 16 bytes at 0x9000, referencing
* a 632-entry SKU_CONFIG_ENTRY table at 0x40E0
*
* The SKU data table maps platform device identifiers (like "PSYS",
* "_SB_.CCT0".."_SB_.CCT8", "_SB_.CFH0".."_SB_.CFH8") to ACPI
* namespace path strings. For NVDR (NVMe/Drive) entries, it maps
* function-level registers (FXCD, FXST, FXIN, FXOU, FXBS, FXFH,
* CENA, CFIS) across multiple NVMe controller instances (N000-N350).
* For PCI root bridges, it maps FIX1-FIX8 and MCTL registers
* (PC00-PC23, BR0-BR3, MCP0-MCP7, QRP0-RRP0-SRP0).
*/
#include "StaticSkuDataDxeNeonCityFPGA.h"
/*============================================================================
* GUID Declarations
*============================================================================*/
///
/// Protocol GUID to locate the ACPI configuration interface.
/// {E03E0D46-5263-4845-B0A4-58D57B3177E2}
///
STATIC CONST EFI_GUID mPlatformProtocolGuid = STATIC_SKU_DATA_PROTOCOL_GUID;
///
/// GUID for the HOB list in gST->ConfigurationTable.
/// {7739F24C-93D7-11D4-9A3A-0090273FC14D}
///
STATIC CONST EFI_GUID mHobListGuid = HOB_LIST_GUID;
///
/// GUID key for the UMPT (Ubox Platform Topology) ACPI table.
/// {0FF8A1CF-A0AB-4AC0-BFC9-34A78F68DD8A}
///
STATIC CONST EFI_GUID mUmptTableGuid = UMPT_TABLE_GUID;
///
/// GUID key for the PIRQ (PCI IRQ Routing) ACPI table.
/// {4C1F48A5-C976-4D90-9F03-8E9B1C327FCF}
///
STATIC CONST EFI_GUID mPirqTableGuid = PIRQ_TABLE_GUID;
///
/// GUID key for the ACPF (ACPI Platform SKU data) ACPI table.
/// {81129EF8-391D-4F63-AE99-58517EC077E3}
///
STATIC CONST EFI_GUID mAcpfTableGuid = ACPF_TABLE_GUID;
/*============================================================================
* Global Variables (stored in .data section, 0xF520-0xF550)
*============================================================================*/
///
/// @brief Cached ImageHandle from entry point.
///
EFI_HANDLE gImageHandle = NULL;
///
/// @brief Cached SystemTable pointer from entry point.
///
EFI_SYSTEM_TABLE *gSystemTable = NULL;
///
/// @brief Cached BootServices pointer (SystemTable->BootServices).
///
EFI_BOOT_SERVICES *gBootServices = NULL;
///
/// @brief Cached RuntimeServices pointer (SystemTable->RuntimeServices).
///
EFI_RUNTIME_SERVICES *gRuntimeServices = NULL;
///
/// @brief Cached platform protocol interface (lazy init at 0x4FC).
///
VOID *gPlatformProtocol = NULL;
///
/// @brief Cached HOB list pointer (lazy init at 0x608).
///
VOID *gHobList = NULL;
/*============================================================================
* Static Data: SKU Variable Headers (in .data section)
*============================================================================*/
///
/// @brief UMPT configuration header at 0x4090 (24 bytes).
///
/// Format: "UMPT" + Ver=1 + Ptr=0x9040 + NextPtr=0x9020 + GUID suffix.
///
STATIC CONST UMPT_VAR_BLOCK mUmptHeader = {
{ SIGNATURE_32('U','M','P','T'), 1, (UINT64)0x9040 },
(UINT64)0x9020,
(UINT64)0x0000000000000000 // Placeholder; actual GUID bytes follow
};
///
/// @brief PIRQ configuration header at 0x40B8 (16 bytes).
///
/// Format: "PIRQ" + Ver=1 + Ptr=0x90B8.
///
STATIC CONST SKU_VAR_HEADER mPirqHeader = {
SIGNATURE_32('P','I','R','Q'), 1, (UINT64)0x90B8
};
///
/// @brief ACPF configuration header at 0x9000 (16 bytes).
///
/// Format: "ACPF" + Ver=1 + Ptr=0x40E0 (to the SKU_CONFIG_ENTRY table).
///
STATIC CONST SKU_VAR_HEADER mAcpfHeader = {
SIGNATURE_32('A','C','P','F'), 1, (UINT64)0x40E0
};
///
/// @brief SKU data identifier at 0x4060 (first 16 bytes of .data).
///
/// GUID: {36232936-0E76-31C8-A13A-3AF2FC1C3932}
///
STATIC CONST EFI_GUID mSkuDataIdentifier = SKU_DATA_IDENTIFIER_GUID;
/*============================================================================
* Entry Point
*============================================================================*/
/**
* @brief UEFI DXE driver entry point.
*
* Implements the standard UEFI driver entry point pattern:
* 1. Caches ImageHandle, SystemTable, BootServices, RuntimeServices
* with NULL-check assertions.
* 2. Locates the HOB list via GetHobList().
* 3. Locates the platform-specific ACPI configuration protocol.
* 4. Calls the protocol's InstallConfigurationTable three times to
* register UMPT, PIRQ, and ACPF table entries.
*
* @param[in] ImageHandle The firmware-allocated handle for this driver.
* @param[in] SystemTable Pointer to the UEFI system table.
* @return EFI_SUCCESS The driver initialized successfully.
* @return Other Error from LocateProtocol or InstallConfigurationTable.
*/
EFI_STATUS
EFIAPI
StaticSkuDataDxeEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
VOID *ProtocolInterface; // v4 in decompilation
// 1. Cache global pointers with NULL-check assertions
gImageHandle = ImageHandle;
PlatformAssert (__FILE__, __LINE__, "gImageHandle != ((void *) 0)");
gSystemTable = SystemTable;
PlatformAssert (__FILE__, __LINE__, "gST != ((void *) 0)");
gBootServices = SystemTable->BootServices;
PlatformAssert (__FILE__, __LINE__, "gBS != ((void *) 0)");
gRuntimeServices = SystemTable->RuntimeServices;
PlatformAssert (__FILE__, __LINE__, "gRT != ((void *) 0)");
// 2. Locate the HOB list (for DXE services)
GetHobList (ImageHandle);
// 3. Print platform banner
PlatformDebugPrint (0x80000000, "UBA:OpromUpdate-TypeLightningRidgeEXECB1\n");
// 4. Locate the platform-specific ACPI configuration protocol
// Protocol GUID: {E03E0D46-5263-4845-B0A4-58D57B3177E2}
// v4+0x10 = InstallConfigurationTable function
ProtocolInterface = NULL;
Status = gBootServices->LocateProtocol (
(EFI_GUID *)&mPlatformProtocolGuid,
NULL,
&ProtocolInterface
);
if (EFI_ERROR (Status)) {
return Status;
}
// 5. Install three ACPI configuration tables
//
// The protocol interface has the following layout:
// +0x00: Reserved/Version
// +0x08: Assert function (used by PlatformAssert)
// +0x10: InstallConfigurationTable(GUID *Key, VOID *Data, UINTN Size)
// Install UMPT table: 24 bytes of UMPT_VAR_BLOCK data
// Key GUID: {0FF8A1CF-A0AB-4AC0-BFC9-34A78F68DD8A}
// Data at: 0x4090 (mUmptHeader)
// Size: 24 bytes
Status = ((EFI_STATUS (EFIAPI *)(VOID *, EFI_GUID *, VOID *, UINTN))
(*((VOID ***)ProtocolInterface))[2]) (
ProtocolInterface,
(EFI_GUID *)&mUmptTableGuid,
(VOID *)&mUmptHeader,
24
);
if (EFI_ERROR (Status)) {
return Status;
}
// Install PIRQ table: 16 bytes of PIRQ header
// Key GUID: {4C1F48A5-C976-4D90-9F03-8E9B1C327FCF}
// Data at: 0x40B8 (mPirqHeader)
// Size: 16 bytes
Status = ((EFI_STATUS (EFIAPI *)(VOID *, EFI_GUID *, VOID *, UINTN))
(*((VOID ***)ProtocolInterface))[2]) (
ProtocolInterface,
(EFI_GUID *)&mPirqTableGuid,
(VOID *)&mPirqHeader,
16
);
if (EFI_ERROR (Status)) {
return Status;
}
// Install ACPF table: 16 bytes of SKU data header
// Key GUID: {81129EF8-391D-4F63-AE99-58517EC077E3}
// Data at: 0x9000 (mAcpfHeader)
// Size: 16 bytes
// The DataPointer field (0x40E0) references the 632-entry
// SKU_CONFIG_ENTRY table.
Status = ((EFI_STATUS (EFIAPI *)(VOID *, EFI_GUID *, VOID *, UINTN))
(*((VOID ***)ProtocolInterface))[2]) (
ProtocolInterface,
(EFI_GUID *)&mAcpfTableGuid,
(VOID *)&mAcpfHeader,
16
);
return Status;
}
/*============================================================================
* HOB List Locator
*============================================================================*/
/**
* @brief Locate and cache the HOB list pointer.
*
* Walks SystemTable->ConfigurationTable[] looking for an entry whose
* VendorGuid matches HOB_LIST_GUID. The associated VendorTable pointer
* is the HOB list. Cached in gHobList on success.
*
* @param[in] ImageHandle Unused; passed as first arg to maintain
* compatibility with the wrapper calling convention.
* @return Pointer to the first HOB, or NULL if not found.
*/
VOID *
GetHobList (
IN EFI_HANDLE ImageHandle
)
{
UINTN Index;
// Guard: return cached value if already initialized
if (gHobList != NULL) {
return gHobList;
}
gHobList = NULL;
// Walk the configuration table
if (gSystemTable->NumberOfTableEntries > 0) {
for (Index = 0; Index < gSystemTable->NumberOfTableEntries; Index++) {
if (IsHobGuidMatch (
(UINT64 *)&mHobListGuid,
(UINT64 *)&gSystemTable->ConfigurationTable[Index].VendorGuid
)) {
// Matched the HOB list GUID; cache the vendor table pointer
gHobList = gSystemTable->ConfigurationTable[Index].VendorTable;
break;
}
}
}
// If not found, trigger debug assertion
if (gHobList == NULL) {
PlatformDebugPrint (0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", 0x800000000000000EULL);
PlatformAssert (__FILE__, __LINE__, "!EFI_ERROR (Status)");
}
return gHobList;
}
/*============================================================================
* GUID Comparison Helpers
*============================================================================*/
/**
* @brief Compare two GUID values using 64-bit halves.
*
* Reads the first 8 bytes of each GUID and checks for equality.
* Uses ReadUnaligned64 for safe access to potentially unaligned pointers.
*
* @param[in] Reference Address of the first GUID (e.g. HOB_LIST_GUID).
* @param[in] Target Address of the second GUID (e.g. configuration table entry).
* @return TRUE if the first 8 bytes match.
* @return FALSE if they differ.
*/
BOOLEAN
IsHobGuidMatch (
IN UINT64 *Reference,
IN UINT64 *Target
)
{
UINT64 RefLow;
UINT64 RefHigh;
UINT64 TgtLow;
UINT64 TgtHigh;
// Read first 64-bit half
RefLow = ReadUnaligned64 (Reference);
TgtLow = ReadUnaligned64 (Target);
// Read second 64-bit half
RefHigh = ReadUnaligned64 ((UINT64 *)((UINT8 *)Reference + 8));
TgtHigh = ReadUnaligned64 ((UINT64 *)((UINT8 *)Target + 8));
return (RefLow == TgtLow) && (RefHigh == TgtHigh);
}
/**
* @brief Unaligned 64-bit read with NULL-check assertion.
*
* Returns *(UINT64 *)Buffer. Asserts if Buffer is NULL.
* Based on BaseLib ReadUnaligned64.
*
* @param[in] Buffer Pointer to read from (may be misaligned).
* @return UINT64 value at Buffer.
*/
UINT64
ReadUnaligned64 (
IN CONST VOID *Buffer
)
{
PlatformAssert (__FILE__, __LINE__, "Buffer != ((void *) 0)");
return *(const UINT64 *)Buffer;
}
/*============================================================================
* Platform Protocol Access
*============================================================================*/
/**
* @brief Lazy-initialized platform protocol interface getter.
*
* On first call:
* 1. Allocates 31 bytes from gBS->AllocatePool (boot services data type).
* 2. Frees the pool immediately. If AllocatePool returned <= 0x10,
* returns NULL (pool probe guard).
* 3. Locates the platform protocol via gBS->LocateProtocol.
* 4. Caches the protocol pointer in gPlatformProtocol.
*
* On subsequent calls, returns the cached pointer directly.
*
* The pool probe (31 bytes) is a heuristic check to verify that the
* boot services pool allocator is functional. If the allocation returned
* an address <= 0x10, the allocator is considered unreliable and
* LocateProtocol is skipped.
*
* @return Pointer to the platform protocol interface, or NULL if:
* - Pool probe failed (returned <= 0x10)
* - LocateProtocol failed
*/
VOID *
GetPlatformProtocol (
VOID
)
{
UINT64 PoolProbe;
UINT64 *ProtocolPtr;
// Return cached value if already initialized
if (gPlatformProtocol != NULL) {
return gPlatformProtocol;
}
// Pool probe: allocate 31 bytes to check allocator health
PoolProbe = (UINT64)gBootServices->AllocatePool (31);
gBootServices->FreePool ((VOID *)PoolProbe);
// If pool allocation returned a suspiciously low address, bail out
if (PoolProbe <= 0x10) {
return NULL;
}
// Locate the platform protocol
gPlatformProtocol = NULL;
gBootServices->LocateProtocol (
(EFI_GUID *)&mPlatformProtocolGuid,
NULL,
&gPlatformProtocol
);
// On failure, clear the cached pointer
ProtocolPtr = (UINT64 *)&gPlatformProtocol;
if ((INT64)gBootServices->LocateProtocol (
(EFI_GUID *)&mPlatformProtocolGuid,
NULL,
&gPlatformProtocol
) < 0) {
*ProtocolPtr = 0;
}
return gPlatformProtocol;
}
/*============================================================================
* Platform Debug / Assert Support
*============================================================================*/
/**
* @brief Platform debug print.
*
* Reads the platform type from RTC CMOS register 0x4B.
* Based on the platform type:
* 1 = Debug via route 0x80000004
* 2+ = Debug via route 0x80000006
* Fallback 0 = hardware strap at 0xFDAF0490 bit 1, ORed with 1
*
* Routes the debug output through the protocol interface if the
* debug route mask matches the DebugLevel parameter.
*
* @param[in] DebugLevel 0x80000000 for error messages.
* @param[in] FormatString printf-style format.
* @param[in] ... Variable arguments.
* @return TRUE if the debug message was dispatched.
*/
BOOLEAN
PlatformDebugPrint (
IN UINT64 DebugLevel,
IN CONST CHAR8 *FormatString,
...
)
{
VOID *Protocol;
UINT8 CmosReg;
UINT8 PlatformType;
UINT64 DebugRoute;
Protocol = GetPlatformProtocol ();
DebugRoute = 0;
if (Protocol != NULL) {
// Read RTC CMOS register 0x4B to determine platform type
CmosReg = IoRead8 (0x70);
IoWrite8 (0x70, (CmosReg & 0x80) | 0x4B); // Select reg 0x4B, preserve NMI mask
PlatformType = IoRead8 (0x71);
if (PlatformType > 3) {
// Platform type is already valid (>3), keep as-is
}
if (PlatformType == 0) {
// Fallback: read hardware strap at 0xFDAF0490 bit 1, OR with 1
PlatformType = (*(volatile UINT8 *)0xFDAF0490 & 2) | 1;
}
// Determine debug route based on platform type (minus 1 for 0-indexed check)
if ((PlatformType - 1) <= 0xFD) {
if (PlatformType == 1) {
DebugRoute = 0x80000004; // Standard debug route
} else {
DebugRoute = 0x80000006; // Alternative debug route
}
}
// If the debug route matches the requested level, dispatch to protocol
if ((DebugRoute & DebugLevel) != 0) {
// Protocol function 1 (offset 0x08) = DebugPrint
((VOID (EFIAPI *)(VOID *, CONST CHAR8 *, VA_LIST))
(*((VOID ***)Protocol))[1]) (
Protocol,
FormatString,
(VA_LIST)&FormatString + sizeof(CONST CHAR8 *)
);
}
}
return (BOOLEAN)(UINTN)Protocol;
}
/**
* @brief Platform assert handler.
*
* Resolves the debug protocol and calls its assert handler
* (function at offset 0x08 = function index 1 in the protocol).
*
* @param[in] FileName Source file name where assertion failed.
* @param[in] LineNumber Line number of the failed assertion.
* @param[in] AssertString Description of the failed assertion expression.
*/
VOID
PlatformAssert (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *AssertString
)
{
VOID *Protocol;
Protocol = GetPlatformProtocol ();
if (Protocol != NULL) {
// Protocol function at offset 0x08 = assert handler
((VOID (EFIAPI *)(CONST CHAR8 *, UINTN, CONST CHAR8 *))
(*((VOID ***)Protocol))[1]) (
FileName,
LineNumber,
AssertString
);
}
}
/**
* @brief RTC CMOS register 0x4B read (inline with platform debug).
*
* Reads port 0x70 to get current RTC index, preserves the NMI mask
* (bit 7), selects register 0x4B, then reads platform type from 0x71.
*
* Port 0x70 = CMOS index port (NMI mask in bit 7)
* Port 0x71 = CMOS data port
*
* RTC CMOS register 0x4B is an OEM-configurable byte used to encode
* the platform type identifier (NeonCity FPGA vs other).
* Values:
* 0 -> Fallback to hardware strap at 0xFDAF0490
* 1 -> Debug via route 0x80000004
* 2,3 -> Debug via route 0x80000006
* >3 -> Unchanged, already valid
*/