/** @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);
}