/**
 * @file OpromUpdateDxeLightningRidgeEXECB3.h
 *
 * @brief Header for OpromUpdateDxeLightningRidgeEXECB3 UEFI DXE driver.
 *
 * This module is a UBA (Unified Board Architecture) board-type DXE driver
 * for the LightningRidge EXEC B3 platform (index 31 of 427 PE files in the
 * HR650X BIOS). It registers PCIe Option ROM (OpROM) update configuration
 * tables via the UBA framework, providing callback functions that the
 * platform uses to determine which PCIe slots and devices should receive
 * OpROM updates.
 *
 * == UBA Registration Pattern ==
 * 1. _ModuleEntryPoint caches UEFI globals (gImageHandle, gST, gBS, gRT)
 * 2. GetHobList() resolves the HOB list via SystemTable->ConfigurationTable
 * 3. DebugPrint() emits the platform banner using the UBA DebugLib protocol
 * 4. gBS->LocateProtocol() resolves the UBA_CONFIG_PROTOCOL by GUID
 *    {E03E0D46-5263-4845-B0A4-58D57B3177E2}
 * 5. The protocol's RegisterConfig function (vtable offset 0x10) is called
 *    with an OPROM_UPDATE_CONFIG structure (PBDS) containing 5 callbacks
 *
 * Source paths reference "e:\hs\MdePkg\Library\" (internal build server).
 * PDB: OpromUpdateDxeLightningRidgeEXECB3.pdb
 * SHA256: d58f84d1adb92017d59b450e242cac64939aadc6e24a35da7573064e7b531022
 */

#ifndef __OPROM_UPDATE_DXE_LIGHTNING_RIDGE_EXECB3_H__
#define __OPROM_UPDATE_DXE_LIGHTNING_RIDGE_EXECB3_H__

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

/*==============================================================================
 * GUID Definitions (stored in .rdata section at compile-time addresses)
 *============================================================================*/

/**
 * EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID
 *   {2F707EBB-4A1A-11D4-9A38-0090273FC14D}
 *
 * Standard UEFI protocol for PCI Root Bridge IO operations (config space access).
 * Stored at image address 0xCE0.
 * Used by IsPcieSlotConfigured() to read PCI config space registers.
 *
 * In the original binary, this GUID is at offset 0xCE0 (16 bytes).
 * Sub_48C calls gBS->LocateProtocol() with this GUID inside its loop.
 */
#define EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID \
  { 0x2F707EBB, 0x4A1A, 0x11D4, \
    { 0x9A, 0x38, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } }

/**
 * UBA_DEBUG_LIB_PROTOCOL_GUID
 *   {36232936-0E76-31C8-A13A-3AF2FC1C3932}
 *
 * UBA DebugLib protocol GUID. Used for debug output and assertions.
 * Resolved lazily via gBS->LocateProtocol() by GetDebugLibProtocol().
 *
 * Protocol interface layout (vtable):
 *   - Offset 0x00: DebugPrint function pointer
 *   - Offset 0x08: DebugAssert function pointer
 *
 * Stored at image address 0xCF0.
 * The result is cached in gOpromProtocol (image addr 0xF50).
 */
#define UBA_DEBUG_LIB_PROTOCOL_GUID \
  { 0x36232936, 0x0E76, 0x31C8, \
    { 0xA1, 0x3A, 0x3A, 0xF2, 0xFC, 0x1C, 0x39, 0x32 } }

/**
 * UBA_CONFIG_PROTOCOL_GUID
 *   {E03E0D46-5263-4845-B0A4-58D57B3177E2}
 *
 * UBA board-type configuration protocol GUID for LightningRidge EXEC B3.
 * This protocol is registered by the platform-specific UBA board driver
 * and provides a RegisterConfig function at vtable offset 0x10 (function
 * index 2). The entry point calls this function to register the OpROM
 * update configuration (PBDS structure and config GUID).
 *
 * Stored at image address 0xD00.
 *
 * Protocol interface layout (vtable):
 *   - Offset 0x00: Reserved / QueryInterface?
 *   - Offset 0x08: Reserved / Unknown function
 *   - Offset 0x10: RegisterConfig(configGuid, configData, dataSize)
 */
#define UBA_CONFIG_PROTOCOL_GUID \
  { 0xE03E0D46, 0x5263, 0x4845, \
    { 0xB0, 0xA4, 0x58, 0xD5, 0x7B, 0x31, 0x77, 0xE2 } }

/**
 * EFI_HOB_LIST_GUID
 *   {7739F24C-93D7-11D4-9A3A-0090273FC14D}
 *
 * Standard UEFI HOB (Hand-Off Block) list GUID.
 * GetHobList() walks the SystemTable->ConfigurationTable[] searching for
 * this GUID to locate the HOB list pointer.
 *
 * Stored as two 8-byte halves at image addresses 0xD10 and 0xD18.
 * The comparison in IsHobListGuid() reads these as unaligned 64-bit values.
 */
#define EFI_HOB_LIST_GUID \
  { 0x7739F24C, 0x93D7, 0x11D4, \
    { 0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } }

/**
 * OPROM_UPDATE_CONFIG_DATA_GUID
 *   {371BD79C-DE79-4C5F-AA2B-BC9EBEFA988F}
 *
 * Configuration data identifier GUID for the OpROM update config structure.
 * Passed to the UBA_CONFIG_PROTOCOL.RegisterConfig() call as the
 * ConfigGuid parameter identifying the type of configuration being registered.
 * Stored at image address 0xEF0.
 */
#define OPROM_UPDATE_CONFIG_DATA_GUID \
  { 0x371BD79C, 0xDE79, 0x4C5F, \
    { 0xAA, 0x2B, 0xBC, 0x9E, 0xBE, 0xFA, 0x98, 0x8F } }

/*==============================================================================
 * Type Definitions
 *============================================================================*/

/**
 * OPROM_UPDATE_CONFIG - PBDS protocol interface structure (48 bytes total)
 *
 * This structure is registered with the UBA_CONFIG_PROTOCOL.RegisterConfig().
 * It contains the signature/version header and five callback function pointers.
 * The callbacks are resolved to absolute function addresses at runtime via
 * relocation (the .reloc section has entries for this structure).
 *
 * Layout at image address 0xF00:
 *   Offset  Size  Field                 Description
 *   ------  ----  -------------------   ----------------------------
 *   0x00    4     'PBDS'                 Signature (0x53444250)
 *   0x04    4     Version                Structure version (always 1)
 *   0x08    8     IsPcieSlotConfigured   Ptr to IsPcieSlotConfigured()
 *   0x10    8     OpromGetConfigA        Ptr to OpromGetConfigA()
 *   0x18    8     OpromGetConfigB        Ptr to OpromGetConfigB()
 *   0x20    8     OpromGetConfigC        Ptr to OpromGetConfigC()
 *   0x28    8     OpromSetSlotNumber     Ptr to OpromSetSlotNumber()
 *   ------  ----  -----
 *   Total   48 bytes (0x30)
 */
typedef struct {
  UINT32  Signature;             ///< 'PBDS' = 0x53444250
  UINT32  Version;               ///< Structure version (must be 1)
  UINT64  IsPcieSlotConfigured;  ///< Function pointer: IsPcieSlotConfigured()
  UINT64  OpromGetConfigA;       ///< Function pointer: OpromGetConfigA()
  UINT64  OpromGetConfigB;       ///< Function pointer: OpromGetConfigB()
  UINT64  OpromGetConfigC;       ///< Function pointer: OpromGetConfigC()
  UINT64  OpromSetSlotNumber;    ///< Function pointer: OpromSetSlotNumber()
} OPROM_UPDATE_CONFIG;

/**
 * UBA_DEBUG_LIB_PROTOCOL - Debug output protocol interface
 *
 * Resolved by GetDebugLibProtocol() via gBS->LocateProtocol() with
 * UBA_DEBUG_LIB_PROTOCOL_GUID. Cached in gOpromProtocol.
 *
 * The protocol provides two functions at its vtable base:
 *   - Offset 0x00: DebugPrint - debug output with format string and VA_LIST
 *   - Offset 0x08: DebugAssert - assertion failure handler
 */
typedef struct {
  UINT64  DebugPrint;   ///< Function pointer: DebugPrint(ErrorLevel, Format, VaList)
  UINT64  DebugAssert;  ///< Function pointer: DebugAssert(FileName, LineNumber, Desc)
} UBA_DEBUG_LIB_PROTOCOL;

/**
 * UBA_CONFIG_PROTOCOL - Board-type configuration protocol
 *
 * Located via gBS->LocateProtocol() using UBA_CONFIG_PROTOCOL_GUID.
 * Provides a RegisterConfig function at vtable offset 0x10 that accepts
 * a configuration type GUID, data structure pointer, and data size.
 *
 * Vtable layout:
 *   [0] @+0x00: Unknown (QueryInterface?)
 *   [1] @+0x08: Unknown
 *   [2] @+0x10: RegisterConfig(Protocol*, ConfigGuid*, ConfigData*, DataSize)
 */
typedef struct {
  UINT64  Unknown0;       ///< Reserved / QueryInterface?
  UINT64  Unknown1;       ///< Reserved / Unknown function
  UINT64  RegisterConfig; ///< RegisterConfig(ConfigGuid, ConfigData, DataSize)
} UBA_CONFIG_PROTOCOL;

/**
 * PCIE_SLOT_RANGE - PCIe slot BDF descriptor (4 bytes)
 *
 * Describes a single PCIe slot's Bus/Device/Function range for slot
 * validation. Each entry is 4 bytes but only the first 3 bytes are used
 * by IsPcieSlotConfigured().
 *
 * The function reads these with a byte-level stride of 4 bytes and
 * accesses them at offsets [-1, 0, +1] relative to a pointer that starts
 * at image address 0xED1, advancing by 4 each iteration.
 *
 * Stored at image address 0xED0 (8 entries).
 */
typedef struct {
  UINT8   Bus;       ///< PCI Bus number (byte at offset -1)
  UINT8   Device;    ///< PCI Device number (byte at offset 0)
  UINT8   Function;  ///< PCI Function number (byte at offset +1)
  UINT8   Reserved;  ///< Not used (byte at offset +3, stride padding)
} PCIE_SLOT_RANGE;

/*==============================================================================
 * Global Variable Declarations
 *
 * These globals are at fixed addresses in the .data segment:
 *   gST             at 0xF30  EFI System Table
 *   gBS             at 0xF38  EFI Boot Services
 *   gImageHandle    at 0xF40  EFI Image Handle
 *   gRT             at 0xF48  EFI Runtime Services
 *   gOpromProtocol  at 0xF50  UBA DebugLib protocol cache (lazy init)
 *   gHobList        at 0xF58  HOB list pointer cache (lazy init)
 *============================================================================*/
extern EFI_SYSTEM_TABLE           *gST;
extern EFI_BOOT_SERVICES          *gBS;
extern EFI_HANDLE                  gImageHandle;
extern EFI_RUNTIME_SERVICES       *gRT;
extern UBA_DEBUG_LIB_PROTOCOL     *gOpromProtocol;
extern VOID                       *gHobList;

/*==============================================================================
 * Function Prototypes
 *
 * All functions are module-internal (STATIC in the .c file, or called via
 * function pointers registered with the UBA framework). There is no public
 * API exposed by this driver beyond _ModuleEntryPoint.
 *============================================================================*/

/**
 * _ModuleEntryPoint - UEFI DXE driver entry point.
 *
 * Called by the DXE Dispatcher. Performs the following initialization:
 * 1. Caches ImageHandle, SystemTable, BootServices, RuntimeServices globals
 * 2. Resolves the HOB list via GetHobList()
 * 3. Emits platform banner "UBA:OpromUpdate-TypeLightningRidgeEXECB3"
 * 4. Locates UBA_CONFIG_PROTOCOL by GUID {E03E0D46-5263-4845-B0A4-58D57B3177E2}
 * 5. Calls RegisterConfig(vtable[2]) with:
 *    - Config GUID: {371BD79C-DE79-4C5F-AA2B-BC9EBEFA988F}
 *    - Config data: PBDS structure (48 bytes)
 *    - Data size: 48
 *
 * @param[in] ImageHandle   Handle for this driver image.
 * @param[in] SystemTable   Pointer to the UEFI system table.
 *
 * @return EFI_SUCCESS      Configuration registered successfully.
 * @return Other             LocateProtocol or RegisterConfig failure.
 */
EFI_STATUS
EFIAPI
_ModuleEntryPoint (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  );

/**
 * IsPcieSlotConfigured - Check if a PCIe BDF is in a configured slot range.
 *
 * UBA framework callback (registered via PBDS at offset +0x08).
 * Iterates 8 PCIE_SLOT_RANGE entries at 0xED0. For each slot where the
 * corresponding bit in SlotMask is clear (slot not yet configured):
 *   1. Opens EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL via gBS->LocateProtocol()
 *   2. Reads PCI config register 0x19 (Secondary Bus Number / BIST)
 *   3. Reads PCI config register 0x1A (Subordinate Bus Number / Header Type)
 *   4. Checks if PcieBdfAddr falls within [reg_0x19, reg_0x1A]
 *
 * The BDF address for each slot is computed from the 3-byte descriptor:
 *   combined = (Bus | ((Device | (Function << 8)) << 8)) << 8
 * Then ORed with 0x19 or 0x1A as the config space register offset.
 *
 * @param[in] PcieBdfAddr  PCIe BDF address to test (bus:device:function).
 * @param[in] SlotMask     Bitmask of slots (bits 0-7). Clear bit means
 *                          the slot should be checked for presence.
 *
 * @return TRUE   The BDF is within a configured slot range.
 * @return FALSE  The BDF is not within any configured slot range.
 */
BOOLEAN
IsPcieSlotConfigured (
  IN UINT64   PcieBdfAddr,
  IN UINT32   SlotMask
  );

/**
 * OpromGetConfigA - Get pointer to Config Table A (primary PCIe topology).
 *
 * UBA framework callback (registered via PBDS at offset +0x10).
 * Returns a pointer to the zero-initialized primary configuration table
 * at image address 0xD20. On the LightningRidge EXEC B3 platform, this
 * table is unused (all zeros) - it acts as a terminator/sentinel.
 *
 * @param[out] ConfigTable  Receives pointer to the configuration table.
 *
 * @return EFI_SUCCESS  Always.
 */
EFI_STATUS
OpromGetConfigA (
  OUT VOID  **ConfigTable
  );

/**
 * OpromGetConfigB - Get pointer to Config Table B and entry count.
 *
 * UBA framework callback (registered via PBDS at offset +0x18).
 * Returns pointer to the 6-entry configuration table at image address
 * 0xD60, describing PCIe root port topology for OpROM updates.
 *
 * The table entries encode bus/device/function ranges, vendor/device IDs,
 * and slot information. See the .c file for the raw data layout.
 *
 * @param[out] ConfigTable  Receives pointer to the configuration table.
 * @param[out] EntryCount   Receives the number of entries (6).
 *
 * @return EFI_SUCCESS  Always.
 */
EFI_STATUS
OpromGetConfigB (
  OUT VOID    **ConfigTable,
  OUT UINTN   *EntryCount
  );

/**
 * OpromGetConfigC - Get pointer to Config Table C and entry count.
 *
 * UBA framework callback (registered via PBDS at offset +0x20).
 * Returns pointer to the 10-entry configuration table at image address
 * 0xE60, describing extended PCIe device topology for OpROM updates.
 *
 * The entries include Intel I350 Gigabit Ethernet and 82599ES 10GbE
 * device configurations. See the .c file for the raw data layout.
 *
 * @param[out] ConfigTable  Receives pointer to the configuration table.
 * @param[out] EntryCount   Receives the number of entries (10).
 *
 * @return EFI_SUCCESS  Always.
 */
EFI_STATUS
OpromGetConfigC (
  OUT VOID    **ConfigTable,
  OUT UINTN   *EntryCount
  );

/**
 * OpromSetSlotNumber - Set PCIe slot number callback.
 *
 * UBA framework callback (registered via PBDS at offset +0x28).
 * Always sets slot number to 0 on this platform and logs:
 *   "[UBA]:SetPcieSlotNumber callback - %d\n"
 * with %d=0, indicating slot enumeration starts from slot 0.
 *
 * @param[out] SlotNumber  Receives the slot number (always 0).
 *
 * @return EFI_SUCCESS  Always.
 */
EFI_STATUS
OpromSetSlotNumber (
  OUT UINT8  *SlotNumber
  );

/**
 * GetDebugLibProtocol - Resolve and cache the UBA DebugLib protocol.
 *
 * Called lazily on first use from DebugPrint() or DebugAssert().
 * Performs a UEFI pool allocation of type 31 to check minimum pool size
 * (must be > 0x10 bytes), then calls gBS->LocateProtocol() with
 * UBA_DEBUG_LIB_PROTOCOL_GUID {36232936-0E76-31C8-A13A-3AF2FC1C3932}.
 *
 * The result is cached in gOpromProtocol (image addr 0xF50), so
 * subsequent calls return immediately.
 *
 * @return Pointer to UBA_DEBUG_LIB_PROTOCOL, or NULL if:
 *         - Pool allocation fails (< 0x10 bytes available)
 *         - LocateProtocol fails
 */
UBA_DEBUG_LIB_PROTOCOL *
GetDebugLibProtocol (
  VOID
  );

/**
 * DebugPrint - Platform-aware debug output.
 *
 * Reads CMOS register 0x4B via port 0x70/0x71 to determine platform type:
 *   Type 1 = LightningRidge -> debug mask = 0x80000004
 *   Type 2/3 = other        -> debug mask = 0x80000006
 * Falls back to MMIO read at 0xFDAF0490 bit | 1 when CMOS returns 0.
 *
 * The output is only emitted when (ErrorLevel & DebugMask) != 0.
 * If the DebugLib protocol is not yet resolved, GetDebugLibProtocol()
 * is called to initialize it.
 *
 * @param[in] ErrorLevel  Debug message severity level mask.
 * @param[in] Format      Printf-compatible format string.
 * @param[in] ...         Variable arguments for format string.
 *
 * @return Non-zero if output succeeded, 0 if suppressed or protocol missing.
 */
UINTN
EFIAPI
DebugPrint (
  IN UINTN       ErrorLevel,
  IN CONST CHAR8 *Format,
  ...
  );

/**
 * DebugAssert - ASSERT failure handler.
 *
 * Calls the DebugLib protocol's assertion handler at protocol offset 0x08.
 * This is the runtime ASSERT() macro implementation for this module.
 * If the protocol is not yet resolved, GetDebugLibProtocol() is called.
 *
 * @param[in] FileName     Source file name string.
 * @param[in] LineNumber   Line number of the assertion.
 * @param[in] Description  Assertion description string.
 */
VOID
DebugAssert (
  IN CONST CHAR8  *FileName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *Description
  );

/**
 * GetHobList - Locate the HOB (Hand-Off Block) list.
 *
 * Walks gST->ConfigurationTable[] entries looking for the entry whose
 * VendorGuid matches EFI_HOB_LIST_GUID
 * ({7739F24C-93D7-11D4-9A3A-0090273FC14D}). The associated VendorTable
 * pointer is the HOB list. Result is cached in gHobList (image addr 0xF58).
 *
 * If the GUID is not found in any ConfigTable entry, triggers ASSERT
 * with status 0x800000000000000E (EFI_NOT_FOUND).
 * If the resolved pointer is NULL, another ASSERT is triggered.
 *
 * Source file paths (from ASSERT strings):
 *   e:\hs\MdePkg\Library\DxeHobLib\HobLib.c  (lines 54-55)
 *
 * @return Pointer to the HOB list, or NULL on failure.
 */
VOID *
GetHobList (
  VOID
  );

/**
 * IsHobListGuid - Compare a GUID against EFI_HOB_LIST_GUID.
 *
 * Compares two GUIDs by splitting each into two 64-bit halves using
 * ReadUnaligned64(). The reference EFI_HOB_LIST_GUID halves are stored
 * at image addresses 0xD10 (first 8 bytes) and 0xD18 (second 8 bytes).
 *
 * @param[in] Guid  Pointer to the GUID to compare.
 *
 * @return TRUE  The GUID matches EFI_HOB_LIST_GUID.
 * @return FALSE The GUID does not match.
 */
BOOLEAN
IsHobListGuid (
  IN EFI_GUID  *Guid
  );

/**
 * ReadUnaligned64 - Read a 64-bit value from an unaligned pointer.
 *
 * Direct 8-byte read with NULL pointer assertion check via DebugAssert().
 * Source: e:\hs\MdePkg\Library\BaseLib\Unaligned.c, line 192.
 *
 * @param[in] Buffer  Pointer to read from (must not be NULL).
 *
 * @return The 64-bit value at the address.
 */
UINT64
ReadUnaligned64 (
  IN CONST VOID  *Buffer
  );

#endif /* __OPROM_UPDATE_DXE_LIGHTNING_RIDGE_EXECB3_H__ */