/**
 * @file StaticSkuDataDxeNeonCityFPGA.h
 *
 * @brief Header for StaticSkuDataDxeNeonCityFPGA - UEFI DXE driver that
 *        installs platform-specific SKU configuration data (UMPT, PIRQ, ACPF)
 *        into ACPI configuration tables for the NeonCity FPGA platform.
 *
 * This driver is part of the Lenovo UBA (Universal BIOS Architecture).
 * Build path: e:\hs\Build\HR6N0XMLK\DEBUG_VS2015\X64\PurleyRpPkg\Uba\UbaMain\Dxe\TypeNeonCityFPGA\StaticSkuDataDxe\DEBUG\StaticSkuDataDxeNeonCityFPGA.pdb
 *
 * The driver reads the platform type from RTC CMOS register 0x4B,
 * locates a platform-specific ACPI configuration protocol via GUID
 * {E03E0D46-5263-4845-B0A4-58D57B3177E2}, and installs three
 * configuration tables:
 *   - UMPT (Ubox/Memory/Platform topology table)
 *   - PIRQ (PCI IRQ routing table)
 *   - ACPF (ACPI Platform SKU configuration data)
 */

#ifndef STATIC_SKU_DATA_DXE_NEON_CITY_FPGA_H
#define STATIC_SKU_DATA_DXE_NEON_CITY_FPGA_H

#include "../uefi_headers/Uefi.h"

/*============================================================================
 * GUID Definitions
 *============================================================================*/

///
/// Protocol GUID used in gBS->LocateProtocol() to obtain the ACPI
/// configuration interface at offset 0x10.
/// This is a platform-specific protocol (likely Lenovo UBA or custom ACPI
/// table protocol), NOT the standard EFI_ACPI_TABLE_PROTOCOL.
///
#define STATIC_SKU_DATA_PROTOCOL_GUID \
  { 0xE03E0D46, 0x5263, 0x4845, { 0xB0, 0xA4, 0x58, 0xD5, 0x7B, 0x31, 0x77, 0xE2 } }

///
/// GUIDs used as ACPI table keys for InstallConfigurationTable:
///
/// 1. UMPT table  -- installed with 24 bytes of data
///    Key GUID:   {0FF8A1CF-A0AB-4AC0-BFC9-34A78F68DD8A}
///    Data GUID:  (same GUID used for both key and data in this call)
///
#define UMPT_TABLE_GUID \
  { 0x0FF8A1CF, 0xA0AB, 0x4AC0, { 0xBF, 0xC9, 0x34, 0xA7, 0x8F, 0x68, 0xDD, 0x8A } }

///
/// 2. PIRQ table  -- installed with 16 bytes of data
///    Key GUID:   {4C1F48A5-C976-4D90-9F03-8E9B1C327FCF}
///    Data GUID:  PIRQ_VAR_GUID (tag "PIRQ" in the data)
///
#define PIRQ_TABLE_GUID \
  { 0x4C1F48A5, 0xC976, 0x4D90, { 0x9F, 0x03, 0x8E, 0x9B, 0x1C, 0x32, 0x7F, 0xCF } }

///
/// 3. ACPF table  -- installed with 16 bytes of data
///    Key GUID:   {81129EF8-391D-4F63-AE99-58517EC077E3}
///    Data GUID:  ACPF_VAR_GUID (tag "ACPF" in the data)
///
#define ACPF_TABLE_GUID \
  { 0x81129EF8, 0x391D, 0x4F63, { 0xAE, 0x99, 0x58, 0x51, 0x7E, 0xC0, 0x77, 0xE3 } }

///
/// HOB list GUID (gEfiDxeServicesTableGuid is the standard UEFI name,
/// but this is actually the HOB list pointer GUID)
/// {7739F24C-93D7-11D4-9A3A-0090273FC14D}
///
#define HOB_LIST_GUID \
  { 0x7739F24C, 0x93D7, 0x11D4, { 0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } }

///
/// SKU data identifier GUID at the start of the .data section
/// {36232936-0E76-31C8-A13A-3AF2FC1C3932}
///
#define SKU_DATA_IDENTIFIER_GUID \
  { 0x36232936, 0x0E76, 0x31C8, { 0xA1, 0x3A, 0x3A, 0xF2, 0xFC, 0x1C, 0x39, 0x32 } }


/*============================================================================
 * Data Structure Definitions
 *============================================================================*/

///
/// Header for each configuration variable block installed into ACPI tables.
/// Each variable block has a 4-byte ASCII tag, a version field, and
/// a pointer to the actual data.
///
#pragma pack(push, 1)
typedef struct {
  UINT32  Signature;        ///< 4-byte ASCII tag: "UMPT", "PIRQ", or "ACPF"
  UINT32  Version;          ///< Version number (always 1 in this driver)
  UINT64  DataPointer;      ///< Absolute address of the actual configuration data
} SKU_VAR_HEADER;
#pragma pack(pop)

///
/// UMPT header has an extended format (24 bytes total):
/// - 8 bytes SKU_VAR_HEADER (Sig + Ver + DataPtr)
/// - 8 bytes next data pointer (points to PIRQ data at 0x90B8)
/// - 8 bytes: table GUID suffix
///
#pragma pack(push, 1)
typedef struct {
  SKU_VAR_HEADER  Header;       ///< "UMPT", version=1, data_ptr=0x9040
  UINT64          NextPtr;      ///< Pointer to next var block (0x9020 -> PIRQ data region)
  UINT64          TableGUIDLow; ///< Low 8 bytes of PIRQ_TABLE_GUID Data2|Data1
} UMPT_VAR_BLOCK;
#pragma pack(pop)

///
/// UMPT configuration data entry (at 0x9020).
/// Each entry pairs a memory/address value with a count.
///
#pragma pack(push, 1)
typedef struct {
  UINT64  BaseAddress;  ///< Memory base address or resource base
  UINT32  Count;        ///< Count of items or size in bytes
  UINT32  Reserved;     ///< Reserved / padding
} UMPT_DATA_ENTRY;
#pragma pack(pop)

///
/// PIRQ configuration data entry (at 0x90F0+).
/// Describes IOAPIC and GSI routing.
///
#pragma pack(push, 1)
typedef struct {
  UINT64  IoApicId;     ///< IOAPIC identifier
  UINT64  GsiBase;      ///< Global System Interrupt base
  UINT64  OverrideFlags;///< Interrupt source override flags
} PIRQ_DATA_ENTRY;
#pragma pack(pop)

///
/// PIRQ header (at 0x90B8):
/// Each entry contains a pointer + count for data arrays.
///
#pragma pack(push, 1)
typedef struct {
  UINT64  DataPointer;  ///< Pointer to PIRQ entry data
  UINT32  Count;        ///< Number of entries
  UINT32  Reserved;     ///< Reserved
} PIRQ_DATA_HEADER;
#pragma pack(pop)

///
/// Main SKU configuration table entry (at 0x40E0+).
/// There are 632 entries, each 0x20 (32) bytes.
///
#pragma pack(push, 1)
typedef struct {
  UINT64  StringOffset;      ///< Absolute address of the identifying string in .rdata
                              ///< e.g. 0x7BC = "PSYS", 0x7C8 = "_SB_.CCT0"
  UINT32  GroupId;           ///< Group identifier:
                              ///<   0x00005B80 - CCT/CFH/PSYS entries
                              ///<   0x00000008 - NVDR entries
                              ///<   0x00000011 - FIX8/FIXA entries (PCI root bridge resources)
  UINT32  RdataStringOffset; ///< Offset in .rdata section of the ACPI path string
                              ///< e.g. 0x0954 = "_SB_.NVDR.N000.FXBS" (for PSYS root)
                              ///< For CCT/CFH entries, this is a secondary reference
  UINT32  EntryType;         ///< Entry type:
                              ///<   0x0000000C - Group root / namespace root
                              ///<   0x0000000E - Child entry with ACPI path
                              ///<   0x0000000A - NVDR sub-function descriptor
                              ///<   0x00000087/0x88/0x8A - PCI resource entries (FIX8/FIXA)
  UINT32  Reserved;          ///< Reserved field
  CHAR8   Name[8];           ///< 8-byte entry name (e.g. "FIX0", "FIXX\1", "FIXV\2", etc.)
                              ///< Bytes 4-7 encode sub-index and flags
} SKU_CONFIG_ENTRY;
#pragma pack(pop)


/*============================================================================
 * Function Declarations
 *============================================================================*/

/**
 * @brief UEFI DXE driver entry point.
 *
 * Standard UEFI entry point. Called by DxeCore during driver dispatch.
 * Caches ImageHandle, SystemTable, BootServices, RuntimeServices.
 * Locates the HOB list, then queries for a platform-specific ACPI
 * configuration protocol. Installs three configuration tables:
 * UMPT (Ubox topology), PIRQ (PCI IRQ routing), and ACPF (SKU data).
 *
 * @param[in] ImageHandle  The firmware-allocated handle for this driver image.
 * @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
  );

/**
 * @brief Locate and cache the HOB list pointer.
 *
 * Searches SystemTable->ConfigurationTable for the HOB list GUID
 * ({7739F24C-93D7-11D4-9A3A-0090273FC14D}). The HOB list is required
 * for locating DXE services during initialization.
 *
 * @param[in] ImageHandle  Unused in this context (passed from entry point).
 * @return Pointer to the first HOB in the HOB list, or NULL if not found.
 */
VOID *
GetHobList (
  IN EFI_HANDLE  ImageHandle
  );

/**
 * @brief Compare two 64-bit values (used for GUID comparison).
 *
 * Reads a UINT64 from the given address and compares it against
 * a reference value. Used by GetHobList to match GUIDs in the
 * configuration table.
 *
 * @param[in] Reference  Address of reference GUID (e.g. &unk_4080 = HOB_LIST_GUID).
 * @param[in] Target     Address of configuration table entry to compare.
 * @return TRUE  if the two 64-bit values match.
 * @return FALSE if they differ.
 */
BOOLEAN
IsHobGuidMatch (
  IN UINT64  *Reference,
  IN UINT64  *Target
  );

/**
 * @brief Unaligned 64-bit read with NULL-check assertion.
 *
 * Wrapper for BaseLib ReadUnaligned64. Asserts if Buffer is NULL.
 *
 * @param[in] Buffer  Pointer to read from (may be unaligned).
 * @return The 64-bit value at Buffer.
 */
UINT64
ReadUnaligned64 (
  IN CONST VOID  *Buffer
  );

/**
 * @brief Platform-specific debug/output function.
 *
 * Reads the platform type from RTC CMOS register 0x4B. Based on the
 * platform type value, routes debug output through the platform protocol.
 *
 * @param[in] DebugLevel   Debug level / routing selector (0x80000000 for error).
 * @param[in] FormatString printf-style format string.
 * @param[in] ...          Variable arguments for format string.
 * @return TRUE if the message was routed.
 */
BOOLEAN
PlatformDebugPrint (
  IN UINT64       DebugLevel,
  IN CONST CHAR8  *FormatString,
  ...
  );

/**
 * @brief Lazy-initialized platform protocol interface getter.
 *
 * On first call, allocates a test pool buffer of 31 bytes to verify
 * that gBS->AllocatePool is functional (checks for pool <= 0x10 as
 * a guard). Then locates the platform protocol via gBS->LocateProtocol.
 * The result is cached globally.
 *
 * @return Pointer to the platform protocol interface, or NULL on failure.
 */
VOID *
GetPlatformProtocol (
  VOID
  );

/**
 * @brief Assert handler for debug builds.
 *
 * Forwards assertion information to the platform protocol's
 * assert function (function offset 0x08 in the protocol interface).
 *
 * @param[in] FileName     Source file name string.
 * @param[in] LineNumber   Line number in source file.
 * @param[in] AssertString Assertion expression string.
 */
VOID
PlatformAssert (
  IN CONST CHAR8  *FileName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *AssertString
  );


/*============================================================================
 * Global Variable Declarations
 *============================================================================*/

///
/// Cached EFI_HANDLE from the entry point.
///
extern EFI_HANDLE  gImageHandle;

///
/// Cached EFI_SYSTEM_TABLE pointer.
///
extern EFI_SYSTEM_TABLE  *gSystemTable;

///
/// Cached EFI_BOOT_SERVICES pointer (offset 0x60 from SystemTable).
///
extern EFI_BOOT_SERVICES  *gBootServices;

///
/// Cached EFI_RUNTIME_SERVICES pointer (offset 0x58 from SystemTable).
///
extern EFI_RUNTIME_SERVICES  *gRuntimeServices;

///
/// Cached platform protocol interface pointer (lazy initialized).
///
extern VOID  *gPlatformProtocol;

///
/// Cached HOB list pointer (lazy initialized).
///
extern VOID  *gHobList;

/*============================================================================
 * Platform Protocol Interface Layout (Inferred)
 *
 * This protocol is obtained via LocateProtocol with GUID
 * {E03E0D46-5263-4845-B0A4-58D57B3177E2}.
 *
 * Offset 0x00: Reserved / Version
 * Offset 0x08: Assert (function 1) - VOID (*)(CHAR8 *File, UINTN Line, CHAR8 *Msg)
 * Offset 0x10: InstallConfigurationTable (function 2) - EFI_STATUS (*)(GUID *Key, VOID *Data, UINTN Size)
 *============================================================================*/

#endif /* STATIC_SKU_DATA_DXE_NEON_CITY_FPGA_H */