/** @file
FpgaConfigDataDxeNeonCityFPGA -- Implementation of FPGA configuration data
retrieval for the NeonCityFPGA platform.
This driver provides:
1. A GetFpgaConfigData protocol interface that other UBA modules call
to obtain per-socket PXB register configuration for HSSI cards.
2. HOB-based FPGA configuration data extraction (and fallback to UEFI
variable "FpgaSocketConfig").
3. Debug output via the DebugLib protocol interface with CMOS-based
debug level control.
Build path:
e:\hs\PurleyRpPkg\Uba\UbaMain\Dxe\TypeNeonCityFPGA\FpgaConfigDataDxe\
Source file:
e:\hs\PurleyRpPkg\Uba\UbaMain\Dxe\TypeNeonCityFPGA\FpgaConfigDataDxe\
FpgaConfigDataDxe.c
**/
#include "FpgaConfigDataDxeNeonCityFPGA.h"
// ===========================================================================
// GUID Definitions
// ===========================================================================
EFI_GUID gFpgaConfigProtocolGuid = FPGA_CONFIG_PROTOCOL_GUID;
EFI_GUID gEfiHobListGuid = EFI_HOB_LIST_GUID;
EFI_GUID gEfiGenericVariableGuid = EFI_GENERIC_VARIABLE_GUID;
EFI_GUID gHobSentinelGuid = HOB_SENTINEL_GUID;
EFI_GUID gFpgaSocketConfigVendorGuid = FPGA_SOCKET_CONFIG_VENDOR_GUID;
// ===========================================================================
// HSSI Card Configuration Table (0x3ED0, 2 entries x 24 bytes = 48 bytes)
// ===========================================================================
//
// This table maps (socket, card_type) pairs to PXB config data and callback
// pointers. The entries at 0x3ED0:
//
// Entry 0: Socket=0, CardType=0x04, PxbConfig=Ptr(0x14C0), ConfigData=0x448
// Entry 1: Socket=0, CardType=0x06, PxbConfig=Ptr(0x3F00), ConfigData=0x448
//
// The PxbConfig entries at 0x14C0 and 0x3F00 are arrays of PXB register
// configuration tuples. Each tuple is 8 bytes:
// [4 bytes: register_offset] [2 bytes: value] [2 bytes: mask]
//
HSSI_CARD_CONFIG_ENTRY mHssiCardConfigTable[MAX_HSSI_CONFIG_ENTRIES] = {
{ 0, 0x04, { 0, 0, 0, 0, 0, 0 }, (VOID *)0x14C0, (VOID *)GetFpgaConfigData },
{ 0, 0x06, { 0, 0, 0, 0, 0, 0 }, (VOID *)0x3F00, (VOID *)GetFpgaConfigData }
};
// ===========================================================================
// Global Variables (.data / .bss section, 0x6920-0x6986)
// ===========================================================================
//
// Standard UEFI globals (populated by _ModuleEntryPoint).
//
EFI_SYSTEM_TABLE *gST = NULL; // 0x6920
EFI_BOOT_SERVICES *gBS = NULL; // 0x6928
EFI_HANDLE gImageHandle = NULL; // 0x6930
EFI_RUNTIME_SERVICES *gRT = NULL; // 0x6938
//
// Cached protocol/state pointers.
//
VOID *mDebugProtocol = NULL; // 0x6940 -- cached DebugLib protocol
VOID *mHobList = NULL; // 0x6948 -- cached HOB list pointer
UINT8 mCmosDebugLevel = 0; // 0x6950 -- cached CMOS debug level byte
//
// FPGA configuration data (0x6960, 38 bytes).
//
FPGA_CONFIG_DATA mFpgaConfigData = { 0 };
// ===========================================================================
// Helper: Zero Memory (sub_370, 0x370-0x38F)
// ===========================================================================
/**
Zeroes a memory buffer. Handles both 8-byte aligned and trailing bytes.
@param[in] Buffer Pointer to buffer to zero.
@param[in] Size Size of buffer in bytes.
@return Buffer.
**/
VOID *
EFIAPI
ZeroMem(
IN VOID *Buffer,
IN UINTN Size
)
{
//
// Zero aligned 8-byte chunks.
//
ZeroMem(Buffer, Size & ~7);
//
// Zero remaining bytes (0-7).
//
ZeroMem((UINT8 *)Buffer + (Size & ~7), Size & 7);
return Buffer;
}
// ===========================================================================
// Assert Handler (sub_830, 0x830-0x86D)
// ===========================================================================
/**
ASSERT handler -- calls DebugLib protocol assertion function.
Resolves the DebugLib protocol (if not cached) and calls its assertion
handler at interface offset +0x08.
@param[in] FileName Source file name.
@param[in] LineNumber Line number.
@param[in] Description Assertion description.
**/
VOID
EFIAPI
DebugAssert(
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
)
{
VOID *DebugProtocol;
DebugProtocol = GetDebugProtocol();
if (DebugProtocol != NULL) {
//
// Call DebugLib protocol's Assert at offset +0x08.
//
((DEBUG_ASSERT_FUNC)((UINTN *)DebugProtocol)[1])(
FileName,
LineNumber,
Description
);
}
}
// ===========================================================================
// CMOS Debug Level Reader (sub_7A8 inner logic, inline)
// ===========================================================================
/**
Reads the debug output level from CMOS register 0x4B.
The CMOS register is accessed through legacy RTC ports 0x70 (index) and
0x71 (data). Bit 7 of port 0x70 is preserved (NMI disable bit).
If the CMOS value is 0, falls back to MMIO at 0xFDAF0490, reading bit 1
and setting bit 0.
@return Debug level (1-4), or 0 if no debug protocol is available.
**/
UINT8
EFIAPI
GetCmosDebugLevel(
VOID
)
{
UINT8 DebugLevel;
//
// Read CMOS register 0x4B.
// Preserve NMI disable bit (bit 7) on port 0x70.
//
__outbyte(0x70, (__inbyte(0x70) & 0x80) | 0x4B);
DebugLevel = __inbyte(0x71);
//
// If CMOS level is 0, fall back to MMIO register at 0xFDAF0490.
//
if (DebugLevel == 0) {
DebugLevel = (*(volatile UINT8 *)0xFDAF0490 & 2) | 1;
}
return DebugLevel;
}
// ===========================================================================
// Debug Print (sub_7A8, 0x7A8-0x82F)
// ===========================================================================
/**
Debug print with level filtering.
Compares the ErrorLevel against the CMOS debug level to determine whether
to actually print. Calls the DebugLib protocol's DebugPrint function at
interface offset +0x00.
The CMOS debug level mapping:
1 -> ErrorLevel >= DEBUG_ERROR (0x80000000) [errors only]
2 -> ErrorLevel >= 0x80000040 [errors + info]
3 -> ErrorLevel >= 0x80000008 [warnings + more]
4 -> All [verbose]
@param[in] ErrorLevel DEBUG_* error level mask.
@param[in] Format Format string.
@param[in] ... Variable arguments.
**/
VOID
EFIAPI
DebugPrint(
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
VOID *DebugProtocol;
UINT8 DebugLevel;
UINTN AllowedLevel;
VA_LIST Args;
DebugProtocol = GetDebugProtocol();
if (DebugProtocol == NULL) {
return;
}
DebugLevel = GetCmosDebugLevel();
//
// Map CMOS debug level to allowed error level mask.
//
if (DebugLevel <= 3) {
//
// Level 0-3: allow only up to a threshold.
// Level 0 -> no output (AllowedLevel stays 0).
//
if (DebugLevel == 0) {
AllowedLevel = 0;
} else if (DebugLevel == 1) {
AllowedLevel = DEBUG_ERROR; // 0x80000000
} else if (DebugLevel == 2) {
AllowedLevel = (UINTN)0x80000040; // DEBUG_ERROR | DEBUG_INFO
} else {
AllowedLevel = (UINTN)0x80000008;
}
} else {
//
// Level 4 or above: allow all.
//
AllowedLevel = (UINTN)-1;
}
if ((AllowedLevel & ErrorLevel) != 0) {
VA_START(Args, Format);
//
// Call DebugLib protocol's DebugPrint at offset +0x00.
//
((DEBUG_PRINT_FUNC)((UINTN *)DebugProtocol)[0])(
ErrorLevel,
Format,
Args
);
VA_END(Args);
}
}
// ===========================================================================
// GetDebugProtocol (sub_728, 0x728-0x7A6)
// ===========================================================================
/**
Lazily resolves the DebugLib protocol via gBS->LocateProtocol().
On first call, allocates and immediately frees a 0-byte pool as a UEFI
environment sanity check. If the pointer returned by AllocatePool is
> 0x10 (a valid UEFI pool allocation), proceeds to locate the protocol.
Otherwise returns NULL (environment is not ready).
Caches the result in mDebugProtocol.
@return Pointer to the DebugLib protocol interface, or NULL if unavailable.
**/
VOID *
EFIAPI
GetDebugProtocol(
VOID
)
{
VOID *TestBuffer;
VOID *Protocol;
if (mDebugProtocol != NULL) {
return mDebugProtocol;
}
//
// Allocate and immediately free a 0-byte pool as a canary to verify
// that UEFI boot services are functional.
//
TestBuffer = AllocatePool(EfiBootServicesData, 0);
FreePool(TestBuffer);
//
// On a functional UEFI, AllocatePool(0) returns a non-NULL pointer with
// a valid address (> 0x10). If TestBuffer <= 0x10, boot services are not
// operational.
//
if ((UINTN)TestBuffer <= 0x10) {
return NULL;
}
//
// Locate the DebugLib protocol.
//
Protocol = NULL;
gBS->LocateProtocol(&gFpgaConfigProtocolGuid, NULL, &Protocol);
mDebugProtocol = Protocol;
return Protocol;
}
// ===========================================================================
// GUID Comparison (sub_BA4, 0xBA4-0xC0A)
// ===========================================================================
/**
Compares two GUIDs by comparing their two 8-byte halves.
Uses ReadUnaligned64 to avoid potential alignment faults.
@param[in] Guid1 Pointer to first GUID.
@param[in] Guid2 Pointer to second GUID.
@return TRUE if the GUIDs are identical.
**/
BOOLEAN
EFIAPI
CompareGuid(
IN EFI_GUID *Guid1,
IN EFI_GUID *Guid2
)
{
if (Guid1 == NULL || Guid2 == NULL) {
return FALSE;
}
return (ReadUnaligned64((UINT64 *)Guid1) == ReadUnaligned64((UINT64 *)Guid2)) &&
(ReadUnaligned64((UINT64 *)((UINTN)Guid1 + 8)) ==
ReadUnaligned64((UINT64 *)((UINTN)Guid2 + 8)));
}
// ===========================================================================
// ReadUnaligned64 (sub_C0C, 0xC0C-0xC3A)
// ===========================================================================
/**
Reads a UINT64 from an optionally unaligned pointer.
Asserts if Buffer is NULL.
@param[in] Buffer Pointer to read from.
@return The UINT64 value.
**/
UINT64
EFIAPI
ReadUnaligned64(
IN CONST UINT64 *Buffer
)
{
if (Buffer == NULL) {
DebugAssert(
"e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
192,
"Buffer != ((void *) 0)"
);
}
return *Buffer;
}
// ===========================================================================
// Allocate Pool (sub_C3C, 0xC3C-0xC6A)
// ===========================================================================
/**
Allocates pool memory of EfiBootServicesData type.
@param[in] PoolType EFI memory pool type.
@param[in] Size Number of bytes.
@return Pointer to allocated buffer, or NULL on failure.
**/
VOID *
EFIAPI
AllocatePool(
IN EFI_MEMORY_TYPE PoolType,
IN UINTN Size
)
{
VOID *Buffer = NULL;
if (gBS->AllocatePool(PoolType, Size, &Buffer) != EFI_SUCCESS) {
return NULL;
}
return Buffer;
}
// ===========================================================================
// Free Pool (sub_C6C, 0xC6C-0xCAE)
// ===========================================================================
/**
Frees pool memory. Asserts on failure.
@param[in] Buffer Pointer to buffer to free.
**/
VOID
EFIAPI
FreePool(
IN VOID *Buffer
)
{
EFI_STATUS Status;
Status = gBS->FreePool(Buffer);
if (EFI_ERROR(Status)) {
DebugPrint(DEBUG_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
DebugAssert(
"e:\\hs\\MdePkg\\Library\\UefiMemoryAllocationLib\\MemoryAllocationLib.c",
819,
"!EFI_ERROR (Status)"
);
}
}
// ===========================================================================
// HOB List Locator (sub_870, 0x870-0x94C)
// ===========================================================================
/**
Locates the HOB (Hand-Off Block) list from the system configuration table.
Scans SystemTable->ConfigurationTable[] for the EFI HOB list GUID
(7739F24C-93D7-11D4-9A3A-0090273FC14D). Each configuration table entry
is 24 bytes: 16-byte GUID + 8-byte pointer.
Caches the result in mHobList.
@return Pointer to the HOB list, or NULL if not found.
**/
VOID *
EFIAPI
GetHobList(
VOID
)
{
UINTN Index;
VOID *HobList;
if (mHobList != NULL) {
return mHobList;
}
mHobList = NULL;
HobList = NULL;
if (gST->NumberOfTableEntries > 0) {
for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
if (CompareGuid(
&gEfiHobListGuid,
(EFI_GUID *)((UINTN)gST->ConfigurationTable + (Index * sizeof(EFI_CONFIGURATION_TABLE)))
)) {
//
// Found the HOB list -- extract the pointer at offset +0x10 within
// the configuration table entry (after the 16-byte GUID).
//
HobList = *(VOID **)((UINTN)gST->ConfigurationTable +
(Index * sizeof(EFI_CONFIGURATION_TABLE)) +
OFFSET_OF(EFI_CONFIGURATION_TABLE, VendorTable));
mHobList = HobList;
break;
}
}
}
if (mHobList == NULL) {
DebugPrint(DEBUG_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", EFI_NOT_FOUND);
DebugAssert(
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
54,
"!EFI_ERROR (Status)"
);
DebugAssert(
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
55,
"mHobList != ((void *) 0)"
);
}
return mHobList;
}
// ===========================================================================
// HOB Walk Sub-function (sub_950, 0x950-0x99C)
// ===========================================================================
/**
Walks the HOB list to find a HOB with the given type.
HOBs are linked list entries where each HOB starts with:
+0x00: UINT16 HobType
+0x02: UINT16 HobLength (total size of this HOB including header)
@param[in] HobStart Pointer to the start of the HOB list.
@return Pointer to the first HOB of type 4 (EFI_HOB_TYPE_GUID_EXT),
or NULL if the end-of-list marker (0xFFFF) is reached.
**/
STATIC
VOID *
EFIAPI
FindGuidHob(
IN VOID *HobStart
)
{
UINT16 *Hob;
if (HobStart == NULL) {
DebugAssert(
"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
108,
"HobStart != ((void *) 0)"
);
}
Hob = (UINT16 *)HobStart;
while (TRUE) {
if (*Hob == 0xFFFF) {
//
// End-of-HOB-list marker.
//
return NULL;
}
if (*Hob == 4) {
//
// EFI_HOB_TYPE_GUID_EXT (type 4) -- this is a GUID-extension HOB.
//
break;
}
//
// Advance to next HOB: HobLength is at offset +0x02.
//
Hob = (UINT16 *)((UINTN)Hob + Hob[1]);
}
return Hob;
}
// ===========================================================================
// Get FPGA Config HOB (sub_9A0, 0x9A0-0xBA2)
// ===========================================================================
/**
Locates or creates the FPGA configuration HOB.
Walks the HOB list looking for a GUID-extension HOB whose GUID matches
the paired sequence (gFpgaConfigProtocolGuid + gHobSentinelGuid).
If found, returns a pointer to the HOB payload (starts at +0x18 from
the HOB header).
If not found, creates a new FPGA configuration HOB of size 38 bytes,
populates it from the "FpgaSocketConfig" UEFI variable (if available),
and marks it as initialized.
@param[out] Buffer Receives pointer to the FPGA configuration data.
@retval EFI_SUCCESS Successfully located or created the HOB.
@retval EFI_NOT_FOUND HOB not found and could not be created.
**/
EFI_STATUS
EFIAPI
GetFpgaConfigHob(
OUT VOID **Buffer
)
{
VOID *HobList;
VOID *GuidHob;
FPGA_CONFIG_DATA *ConfigData;
VOID *NewHob;
UINTN VariableSize;
FPGA_CONFIG_DATA *VarData;
VOID *VarBuffer;
UINTN Index;
UINT8 *ConfigBytes;
UINT8 *VarBytes;
HobList = GetHobList();
//
// Walk HOBs looking for a GUID-extension HOB that matches the FPGA
// config pattern (dual-GUID check: gFpgaConfigProtocolGuid +
// gHobSentinelGuid).
//
GuidHob = FindGuidHob(HobList);
while (GuidHob != NULL) {
//
// GUID-extension HOB layout:
// +0x00: UINT16 HobType (4)
// +0x02: UINT16 HobLength
// +0x04: UINT32 Reserved
// +0x08: EFI_GUID Name (16 bytes)
// +0x18: Data payload starts here
//
if (CompareGuid(
&gFpgaConfigProtocolGuid,
(EFI_GUID *)((UINTN)GuidHob + 8)
)) {
//
// Found the FPGA config HOB. Return pointer to payload.
//
*Buffer = (VOID *)((UINTN)GuidHob + 24);
return EFI_SUCCESS;
}
//
// Continue walking.
//
GuidHob = FindGuidHob((VOID *)((UINTN)GuidHob + *(UINT16 *)((UINTN)GuidHob + 2)));
}
//
// HOB not found -- create one.
//
DebugPrint(
DEBUG_INFO,
"FPGA Configuration Get HOB-> HOB is not found, create it!\n"
);
NewHob = AllocatePool(EfiBootServicesData, FPGA_CONFIG_HOB_SIZE);
if (NewHob == NULL) {
DebugPrint(
DEBUG_INFO,
"FPGA Configuration Get HOB-> HOB IS NULL, could not create!\n"
);
return EFI_NOT_FOUND;
}
//
// Initialize new HOB with ZeroMem.
//
ZeroMem(NewHob, FPGA_CONFIG_HOB_SIZE);
ConfigData = (FPGA_CONFIG_DATA *)NewHob;
//
// Set default values in the new HOB.
//
ConfigData->Initialized = 0;
ConfigData->Reserved1 = 0;
ConfigData->FpgaSktIoApicId = 0;
ConfigData->FpgaSktActive = 0;
ConfigData->SktIioApicId0 = 0;
ConfigData->ActiveIioStackMask = 0;
ConfigData->CpuNum = 0;
//
// Initialize HSSI card IDs to 0xFF (unknown/uninitialized).
//
for (Index = 0; Index < MAX_SOCKET_COUNT; Index++) {
ConfigData->HssiCardId_0 = 0xFF;
ConfigData->HssiCardSubId_0 = 0x0B; // Default sub-ID for unknown card
ConfigData->HssiCardId_1 = 0xFF;
ConfigData->HssiCardSubId_1 = 0x0B;
ConfigData->HssiCardId_2 = 0xFF;
ConfigData->HssiCardSubId_2 = 0x0B;
ConfigData->HssiCardId_3 = 0xFF;
ConfigData->HssiCardSubId_3 = 0x0B;
}
//
// Set initial bifurcation and APIC values.
//
// +0x05 = -256 (0xFF00) -- ActiveIioStackMask = 0xFF00
// +0x25 = 0 -- IioApicIdOverride = 0
//
ConfigData->ActiveIioStackMask = 0xFF;
ConfigData->IioApicIdOverride = 0;
DebugPrint(
DEBUG_INFO,
"FPGA Configuration Get HOB-> create it worked, init it!\n"
);
//
// Try to load saved configuration from UEFI variable "FpgaSocketConfig".
//
VariableSize = sizeof(FPGA_CONFIG_DATA);
VarBuffer = AllocatePool(EfiBootServicesData, VariableSize);
if (VarBuffer != NULL) {
//
// Read the UEFI variable.
//
if (gRT->GetVariable(
L"FpgaSocketConfig",
&gFpgaSocketConfigVendorGuid,
NULL,
&VariableSize,
VarBuffer
) == EFI_SUCCESS)
{
VarData = (FPGA_CONFIG_DATA *)VarBuffer;
DebugPrint(
DEBUG_INFO,
"FPGA Configuration Get HOB-> Vaiable found use it!\n"
);
//
// Copy fields from the variable into the HOB.
// +0x06 (CpuNum) gets copied directly.
// +0x1F (FpgaSktIoApicId2) gets copied directly.
// +0x20 (IioApicId0) gets copied directly.
// +0x25 (IioApicIdOverride) gets copied directly.
//
ConfigData->CpuNum = VarData->CpuNum;
ConfigData->FpgaSktIoApicId2 = VarData->FpgaSktIoApicId2;
ConfigData->IioApicId0 = VarData->IioApicId0;
ConfigData->IioApicIdOverride = VarData->IioApicIdOverride;
//
// Copy HSSI card data per socket.
// For each socket i:
// HssiCardId[i] = VarData.HssiCardId[i] (or -1 if 0)
// HssiCardSubId = VarData.HssiCardSubId[i]
// Bifurcation = VarData.Bifurcation[i]
//
for (Index = 0; Index < MAX_SOCKET_COUNT; Index++) {
UINT8 *DstId;
UINT8 *SrcId;
UINT8 SrcVal;
DstId = &ConfigBytes[Index * 4 + 2]; // offset depends on layout
SrcId = &VarBytes[Index * 4 + 2];
SrcVal = VarBytes[Index * 4 + 14]; // source bifurcation
if (SrcVal != 0) {
if (SrcVal == 0xFF) {
ConfigBytes[Index * 4 + 7] = 0xFF;
} else {
ConfigBytes[Index * 4 + 7] = SrcVal - 1;
}
}
ConfigBytes[Index * 4 + 0] = VarBytes[Index * 4 + 10];
ConfigBytes[Index * 4 + 10] = VarBytes[Index * 4 + 8];
}
}
FreePool(VarBuffer);
}
ConfigData->Initialized = 1;
//
// Return the newly created HOB data pointer.
//
*Buffer = NewHob;
return EFI_SUCCESS;
}
// ===========================================================================
// FPGA Configuration Data Entry (sub_51C, 0x51C-0x725)
// ===========================================================================
/**
Main FPGA configuration data entry function.
Called from _ModuleEntryPoint after HOB list is resolved. Performs:
1. Debug print of module name.
2. Get FPGA configuration data HOB via GetFpgaConfigHob.
3. Extract per-field configuration data from the HOB payload.
4. Check for active FPGA sockets and HSSI cards.
5. Install the FPGA_CONFIG_PROTOCOL via gBS->InstallProtocolInterface.
@param[in] ImageHandle Driver image handle.
@param[in] Buffer HOB data pointer (unused; HOB is re-queried).
@return EFI_SUCCESS on success, or error code from protocol installation.
**/
EFI_STATUS
EFIAPI
FpgaConfigDataEntry(
IN EFI_HANDLE ImageHandle,
IN VOID *Buffer
)
{
UINT8 *Data;
EFI_STATUS Status;
UINT8 SocketIndex;
UINT8 HssiCardType;
VOID *ConfigBuffer;
EFI_HANDLE NewHandle;
UINTN Index;
FPGA_CONFIG_PROTOCOL *ProtocolInterface;
//
// Log module identification string.
//
DebugPrint(DEBUG_INFO, "FpgaConfigData-TypeNeonCityFPGA\n");
//
// Get FPGA configuration data from HOB.
//
Status = GetFpgaConfigHob(&ConfigBuffer);
if (EFI_ERROR(Status)) {
DebugPrint(
DEBUG_INFO,
"FpgaConfigurationGetValues-> HOB error, return EFI_NOT_FOUND!\n"
);
DebugPrint(DEBUG_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
DebugAssert(
"e:\\hs\\PurleyRpPkg\\Uba\\UbaMain\\Dxe\\TypeNeonCityFPGA\\FpgaConfigDataDxe\\FpgaConfigDataDxe.c",
137,
"!EFI_ERROR (Status)"
);
return Status;
}
//
// Extract configuration fields from the HOB data.
//
Data = (UINT8 *)ConfigBuffer;
//
// +0x02: FpgaSktIoApicId
// +0x03: FpgaSktActive (bitmask)
// +0x04: SktIioApicId0
// +0x05: ActiveIioStackMask
// +0x06: CpuNum
// +0x00: byte_6960[0] (raw copy)
// +0x01: byte_6960[1]
// +0x1F: FpgaSktIoApicId2
// +0x20: IioApicId0
// +0x25: IioApicIdOverride
//
mFpgaConfigData.FpgaSktIoApicId = Data[2];
mFpgaConfigData.FpgaSktActive = Data[3];
mFpgaConfigData.SktIioApicId0 = Data[4];
mFpgaConfigData.ActiveIioStackMask = Data[5];
mFpgaConfigData.CpuNum = Data[6];
//
// Copy the raw first two bytes.
//
*(UINT8 *)&mFpgaConfigData = *Data; // offset +0x00
*(UINT8 *)&mFpgaConfigData + 1 = Data[1]; // offset +0x01
mFpgaConfigData.FpgaSktIoApicId2 = Data[31];
mFpgaConfigData.IioApicId0 = Data[32];
mFpgaConfigData.IioApicIdOverride = Data[37];
//
// Copy HSSI card data and bifurcation from HOB offset +0x0B to +0x1F.
//
for (Index = 0; Index < 4; Index++) {
((UINT8 *)&mFpgaConfigData)[Index + 7] = Data[Index + 14];
((UINT8 *)&mFpgaConfigData)[Index + 15] = Data[Index + 22];
((UINT8 *)&mFpgaConfigData)[Index + 19] = Data[Index + 26];
((UINT8 *)&mFpgaConfigData)[Index + 23] = Data[Index + 30];
((UINT8 *)&mFpgaConfigData)[Index + 27] = Data[Index + 34];
((UINT8 *)&mFpgaConfigData)[Index + 11] = Data[Index + 18];
((UINT8 *)&mFpgaConfigData)[Index + 33] = Data[Index + 40];
}
//
// Log active socket mask.
//
DebugPrint(
DEBUG_INFO,
"FpgaConfigDataEntry - FpgaSktActive = 0x%X.\n",
mFpgaConfigData.FpgaSktActive
);
//
// Check if any FPGA sockets are active.
//
if (mFpgaConfigData.FpgaSktActive == 0) {
DebugPrint(DEBUG_INFO, "FpgaConfigDataEntry() no FPGA activated.\n");
return EFI_SUCCESS;
}
//
// Check for HSSI cards on each socket.
//
for (SocketIndex = 0; SocketIndex < MAX_SOCKET_COUNT; SocketIndex++) {
HssiCardType = ((UINT8 *)&mFpgaConfigData)[SocketIndex + 11];
DebugPrint(
DEBUG_INFO,
"FpgaHssiCardID[%X] = 0x%X.\n",
SocketIndex,
HssiCardType
);
//
// 0 = no card, 7 = reserved type. If we find a real card, continue.
//
if (HssiCardType != 0 && HssiCardType != 7) {
break;
}
}
//
// If no HSSI card found on any socket, log and return.
//
if (SocketIndex >= MAX_SOCKET_COUNT) {
DebugPrint(
DEBUG_INFO,
"FpgaConfigDataEntry() no HSSI card found.\n"
);
return EFI_SUCCESS;
}
//
// Install the FPGA Configuration protocol.
// Protocol GUID at 0x1460, interface at off_14B0 which points to GetFpgaConfigData.
//
NewHandle = ImageHandle;
Status = gBS->InstallProtocolInterface(
&NewHandle,
&gFpgaConfigProtocolGuid,
EFI_NATIVE_INTERFACE,
&gFpgaConfigProtocolGuid // note: the actual callback is at off_14B0
);
if (EFI_ERROR(Status)) {
DebugPrint(DEBUG_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
DebugAssert(
"e:\\hs\\PurleyRpPkg\\Uba\\UbaMain\\Dxe\\TypeNeonCityFPGA\\FpgaConfigDataDxe\\FpgaConfigDataDxe.c",
166,
"!EFI_ERROR (Status)"
);
}
return Status;
}
// ===========================================================================
// GetFpgaConfigData Protocol Callback (sub_448, 0x448-0x51B)
// ===========================================================================
/**
Queries FPGA configuration data for a given socket and HSSI card type.
This function is the FPGA_CONFIG_PROTOCOL.GetFpgaConfigData callback.
It is invoked by other UBA modules to retrieve platform-specific PXB
configuration for a given (Socket, CardType) pair.
Lookup algorithm:
1. Validate parameters (NULL pointer check).
2. Check if the requested socket is active in FpgaSktActive bitmask.
3. Validate the HSSI card type (reject types 0-3 and 5).
4. Linear search mHssiCardConfigTable (2 entries) for matching
(Socket, CardType).
5. If found, return PxbConfig and ConfigDataPtr; else EFI_NOT_FOUND.
@param[in] Socket Socket index (0-based).
@param[in] HssiCardType HSSI card type identifier.
@param[out] PxbConfig Pointer to receive PXB config data.
@param[out] ConfigDataPtr Pointer to receive config data callback.
@retval EFI_SUCCESS Lookup succeeded.
@retval EFI_INVALID_PARAMETER NULL pointer parameter.
@retval EFI_NOT_FOUND No matching entry in the table.
@retval EFI_UNSUPPORTED Invalid HSSI card type.
**/
EFI_STATUS
EFIAPI
GetFpgaConfigData(
IN UINT8 Socket,
IN UINT8 HssiCardType,
OUT VOID **PxbConfig,
OUT VOID **ConfigDataPtr
)
{
UINTN Index;
UINTN EntryOffset;
//
// NULL pointer validation.
//
if (PxbConfig == NULL || ConfigDataPtr == NULL) {
return EFI_INVALID_PARAMETER;
}
*PxbConfig = NULL;
*ConfigDataPtr = NULL;
//
// Check if the requested socket is active.
// FpgaSktActive bitmask: bit 0 = socket 0, bit 1 = socket 1, etc.
//
if ((mFpgaConfigData.FpgaSktActive & (1 << Socket)) == 0) {
return EFI_INVALID_PARAMETER;
}
//
// Validate HSSI card type.
// Supported types: 4, 6 (other types up to 5 and type 5 itself are invalid).
//
if ((HssiCardType <= 3) || (HssiCardType == 5)) {
DebugPrint(
DEBUG_ERROR,
"Unsupported HSSI Card: = %X.\n",
HssiCardType
);
return EFI_UNSUPPORTED;
}
//
// Linear search the HSSI card config table.
// mHssiCardConfigTable has 2 entries of sizeof(HSSI_CARD_CONFIG_ENTRY) = 24 bytes.
//
EntryOffset = 0;
while (EntryOffset < (MAX_HSSI_CONFIG_ENTRIES * sizeof(HSSI_CARD_CONFIG_ENTRY))) {
if (mHssiCardConfigTable[Index].Socket == Socket &&
mHssiCardConfigTable[Index].CardType == HssiCardType) {
//
// Match found -- return the PXB config and data pointer.
//
*PxbConfig = mHssiCardConfigTable[Index].PxbConfig;
*ConfigDataPtr = mHssiCardConfigTable[Index].ConfigDataPtr;
return EFI_SUCCESS;
}
Index++;
EntryOffset += sizeof(HSSI_CARD_CONFIG_ENTRY);
}
//
// No matching entry found.
//
return EFI_NOT_FOUND;
}
// ===========================================================================
// Module Entry Point (_ModuleEntryPoint, 0x390-0x447)
// ===========================================================================
/**
UEFI module entry point. Called by the DXE dispatcher.
Initializes the standard UEFI global variables (gImageHandle, gST, gBS,
gRT) with assertions for NULL safety. Then resolves the HOB list and
calls FpgaConfigDataEntry.
@param[in] ImageHandle Handle for this driver image.
@param[in] SystemTable Pointer to the UEFI system table.
@return EFI_STATUS from FpgaConfigDataEntry.
**/
EFI_STATUS
EFIAPI
_ModuleEntryPoint(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
//
// Initialize global image handle.
//
gImageHandle = (EFI_HANDLE)ImageHandle;
if (gImageHandle == NULL) {
DebugAssert(
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
51,
"gImageHandle != ((void *) 0)"
);
}
//
// Initialize global system table pointer.
//
gST = SystemTable;
if (gST == NULL) {
DebugAssert(
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
57,
"gST != ((void *) 0)"
);
}
//
// Initialize global boot services pointer.
//
gBS = SystemTable->BootServices;
if (gBS == NULL) {
DebugAssert(
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
63,
"gBS != ((void *) 0)"
);
}
//
// Initialize global runtime services pointer.
//
gRT = SystemTable->RuntimeServices;
if (gRT == NULL) {
DebugAssert(
"e:\\hs\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c",
47,
"gRT != ((void *) 0)"
);
}
//
// Resolve HOB list and perform FPGA configuration setup.
//
GetHobList();
return FpgaConfigDataEntry(ImageHandle, NULL);
}