/** @file
  SlotDataUpdateDxeLightningRidgeEXECB2 - Platform Slot Table (PSLT) update driver
  for LightningRidge EXEC B2 platforms.

  This driver is part of the Lenovo UBA (Universal BIOS Architecture) framework.
  It provides platform-specific PCIe slot configuration data for the LightningRidge
  EXEC B2 platform by registering PSLT entries through the UBA protocol.

  Build source path: PurleyRpPkg/Uba/UbaMain/Dxe/TypeLightningRidgeEXECB2/
                     SlotDataUpdateDxe/SlotDataUpdateDxe/
  PDB: SlotDataUpdateDxeLightningRidgeEXECB2.pdb
  Build: VS2015, DEBUG, X64
  Image size: 0xD00 (3328 bytes)
  Entry point: 0x390 (_ModuleEntryPoint)

  Copyright (C) 2026, Lenovo. All rights reserved.
  SPDX-License-Identifier: BSD-2-Clause-Patent
**/

#ifndef SLOT_DATA_UPDATE_DXE_LIGHTNING_RIDGE_EXEC_B2_H
#define SLOT_DATA_UPDATE_DXE_LIGHTNING_RIDGE_EXEC_B2_H

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

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

/**
  UBA Protocol GUID.

  GUID: 36232936-0E76-31C8-A13A-3AF2FC1C3932

  This is the UBA protocol identification GUID for the LightningRidge EXEC B2
  platform. It is located via gBS->LocateProtocol() to obtain the UBA protocol
  interface, which provides three services:
    +0x00: DebugPrint (debug message output)
    +0x08: DebugAssert (assertion handler)
    +0x10: Register (SetData - register config data by GUID)

  This GUID is shared across all LightningRidge EXEC variants (B1, B2, B3, B4).
  The NeonCity FPGA variant uses a different GUID
  (76232936-C80E-A131-3A3A-F2FC1C3932).
**/
#define UBA_PROTOCOL_GUID \
    { 0x36232936, 0x0E76, 0x31C8, \
      { 0xA1, 0x3A, 0x3A, 0xF2, 0xFC, 0x1C, 0x39, 0x32 } }

/** Pointer to UBA_PROTOCOL_GUID as EFI_GUID */
extern EFI_GUID gUbaProtocolGuid;

/**
  UBA Slot Data PSLT Entry 1 GUID.

  GUID: B93613E1-48F0-4B32-B3A8-4FEDFC7C1365

  Used with UbaProtocol->Register (at v4+0x10) to register the first PSLT
  (Platform Slot Table) entry for the EXEC B2 platform. The data is 32 bytes
  sourced from gSlotDataBuffer1 (at 0xBC0).
**/
#define UBA_SLOT_DATA_PSLT1_GUID \
    { 0xB93613E1, 0x48F0, 0x4B32, \
      { 0xB3, 0xA8, 0x4F, 0xED, 0xFC, 0x7C, 0x13, 0x65 } }

extern EFI_GUID gUbaSlotDataPsl1Guid;

/**
  UBA Slot Data PSLT Entry 2 GUID.

  GUID: 226763AE-972C-4E3C-80D1-73B25E8CBBA3

  Used with UbaProtocol->Register (at v4+0x10) to register the second PSLT
  entry for the EXEC B2 platform. The data is 40 bytes sourced from
  gSlotDataBuffer2 (at 0xBE0).
**/
#define UBA_SLOT_CONFIG_GUID \
    { 0x226763AE, 0x972C, 0x4E3C, \
      { 0x80, 0xD1, 0x73, 0xB2, 0x5E, 0x8C, 0xBB, 0xA3 } }

extern EFI_GUID gUbaSlotConfigGuid;

/**
  DXE Services Table GUID (gEfiDxeServicesTableGuid).

  GUID: 7739F24C-93D7-11D4-9A3A-0090273FC14D

  Standard UEFI GUID used to locate the HOB (Hand-Off Block) list from the
  EFI System Table's ConfigurationTable. The driver scans the config table for
  this GUID to find the HOB list pointer, which is used for HOB-based data
  access (GetHobList function at 0x600).
**/
#define DXE_SERVICES_TABLE_GUID \
    { 0x7739F24C, 0x93D7, 0x11D4, \
      { 0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } }

extern EFI_GUID gEfiDxeServicesTableGuid;

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

/**
  PSLT_HEADER - Platform Slot Table Header.

  This structure defines the layout of a PSLT entry that gets registered with
  the UBA protocol. The template instances are stored in the .data section at:

    gSlotDataBuffer1 (0xBC0, 32 bytes): Primary PSLT entry
    gSlotDataBuffer2 (0xBE0, 40 bytes): Secondary PSLT entry (with extended config)

  The PSLT format embeds function pointers:
    - SlotCount offset refers to GetSlotCount (sub_4B0 at 0x4B0, returns 2)
    - SlotDataOffset refers to GetSlotData (sub_4B4 at 0x4B4, identity passthrough)
**/
#pragma pack(push, 1)
typedef struct {
  UINT32    Signature;        ///< "PSLT" (0x544C5350) - Platform Slot Table signature
  UINT32    Version;          ///< Format version (1 for current generation)
  UINT32    TotalDataSize;    ///< Total slot table data size in bytes (0xBB0 = 2992 for B2)
  UINT32    SlotCountFunc;    ///< RVA of GetSlotCount function (0x4B0 for B2)
  UINT32    Reserved;         ///< Reserved / padding (0)
  UINT32    SlotDataFunc;     ///< RVA of GetSlotData function (0x4B4 for B2)
  UINT8     ConfigData[8];    ///< Platform-specific slot configuration flags
} PSLT_HEADER;

/**
  SLOT_CONFIG - Extended slot configuration structure (40 bytes).

  Used for the second Register call (GUID: 226763AE-972C-4E3C-...).
  Extends PSLT_HEADER with an additional function pointer slot for
  platform-specific customization.
**/
typedef struct {
  PSLT_HEADER   Header;       ///< PSLT header (32 bytes)
  UINT64        ExtraConfig;  ///< Extended platform config data (RVA to sub_4B4 at 0x4B4)
} SLOT_CONFIG;
#pragma pack(pop)

/** Check that PSLT_HEADER matches expected size. */
STATIC_ASSERT (sizeof (PSLT_HEADER) == 32, "PSLT_HEADER must be 32 bytes");
STATIC_ASSERT (sizeof (SLOT_CONFIG) == 40, "SLOT_CONFIG must be 40 bytes");

// =============================================================================
// UBA Protocol Interface
// =============================================================================

/**
  UBA protocol interface structure.

  The UBA protocol is located via LocateProtocol (gUbaProtocolGuid) and provides:
    +0x00: DebugPrint (DebugLib print service)
    +0x08: DebugAssert (Assert handler)
    +0x10: Register (SetData - register config by GUID + Data + Size)

  For the EXEC B2 platform (as opposed to EXEC B1 which reads via GetData,
  and NeonCity FPGA which also registers via GetData+SetData), the protocol
  function at +0x10 is used to REGISTER (push) platform slot data into the
  UBA framework, rather than to read (pull) from it.
**/
typedef struct {
  //
  // +0x00: DebugPrint
  //   VOID (*)(UINTN DebugLevel, CONST CHAR8 *Format, VA_LIST Va)
  //
  UINT64    DebugPrint;

  //
  // +0x08: DebugAssert
  //   VOID (*)(UINT64 FileName, UINTN LineNumber, UINT64 Expression)
  //
  UINT64    DebugAssert;

  //
  // +0x10: Register (SetData)
  //   EFI_STATUS (*)(UBA_PROTOCOL *This, EFI_GUID *Guid, VOID *Data, UINTN Size)
  //
  UINT64    RegisterFunc;
} UBA_PROTOCOL;

/**
  Type definition for the UBA protocol Register function.

  @param[in] Uba   Pointer to the UBA protocol interface.
  @param[in] Guid  GUID identifying the configuration data.
  @param[in] Data  Pointer to the configuration data buffer.
  @param[in] Size  Size of the configuration data buffer.

  @return EFI_STATUS from the registration operation.
**/
typedef
EFI_STATUS
(EFIAPI *UBA_REGISTER) (
  IN UBA_PROTOCOL  *Uba,
  IN EFI_GUID      *Guid,
  IN VOID          *Data,
  IN UINTN          Size
  );

/**
  Type definition for UBA DebugPrint function.

  @param[in] DebugLevel  Debug message severity (mask).
  @param[in] Format      Print format string.
  @param[in] Va          Variable argument list.
**/
typedef
VOID
(EFIAPI *UBA_DEBUG_PRINT) (
  IN UINTN        DebugLevel,
  IN CONST CHAR8 *Format,
  IN UINT64       *Va
  );

/**
  Type definition for UBA DebugAssert function.

  @param[in] FileName     Source file name (as UINT64 pointer).
  @param[in] LineNumber   Line number of the assertion.
  @param[in] Description  Assertion expression string (as UINT64 pointer).
**/
typedef
VOID
(EFIAPI *UBA_DEBUG_ASSERT) (
  IN UINT64  FileName,
  IN UINTN   LineNumber,
  IN UINT64  Description
  );

// =============================================================================
// Global Variables (declared in .c)
// =============================================================================

/** Saved ImageHandle from entry point parameter. Initialized at 0xC18. */
extern EFI_HANDLE            gImageHandle;

/** Saved SystemTable pointer from entry point parameter. Initialized at 0xC08. */
extern EFI_SYSTEM_TABLE     *gSystemTable;

/** Saved BootServices pointer (SystemTable->BootServices). Initialized at 0xC10. */
extern EFI_BOOT_SERVICES    *gBootServices;

/** Saved RuntimeServices pointer (SystemTable->RuntimeServices). Initialized at 0xC20. */
extern EFI_RUNTIME_SERVICES *gRuntimeServices;

/** Cached UBA protocol interface pointer (lazy-initialized by UbaGetProtocolInterface). Initialized at 0xC28. */
extern VOID                 *gUbaProtocol;

/** Cached HOB list pointer (initialized by GetHobList from config table). Initialized at 0xC30. */
extern VOID                 *gHobList;

/** Cached platform type from CMOS[0x4B] (read by UbaDebugPrint). Initialized at 0xC38. */
extern UINT8                 gPlatformType;

/**
  Slot data buffer 1 - PSLT entry template (32 bytes at 0xBC0).

  Contains a PSLT entry with:
    - Signature "PSLT"
    - Version 1
    - TotalDataSize 0xBB0 (2992 bytes)
    - SlotCountFunc RVA 0x4B0 (GetSlotCount)
    - SlotDataFunc RVA 0x4B4 (GetSlotData)
    - ConfigData all zeros
    - NumberOfSlots = 1

  Registered with UBA via gUbaSlotDataPsl1Guid.
**/
extern PSLT_HEADER gSlotDataBuffer1;

/**
  Slot data buffer 2 - Extended PSLT entry template (40 bytes at 0xBE0).

  Contains a PSLT_HEADER plus an extra 8 bytes:
    - PSLT header (32 bytes, same format as buffer 1)
    - ExtraConfig: RVA 0x4B4 (extended callback to GetSlotData)

  Registered with UBA via gUbaSlotConfigGuid.
**/
extern SLOT_CONFIG gSlotDataBuffer2;

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

/**
  UEFI DXE driver entry point.

  Called by the DXE Core during driver dispatch. Performs the following:
    1. Caches ImageHandle, SystemTable, BootServices, and RuntimeServices
       globals (with NULL-assert checks via UbaDebugAssert).
    2. Calls GetHobList() to locate the HOB list from configuration table.
    3. Calls UbaDebugPrint to log "UBA:SlotDataUpdate-TypeLightningRidgeEXECB2".
    4. Locates the UBA protocol via gBS->LocateProtocol().
    5. Registers PSLT entry 1 via UbaProtocol->Register(gUbaSlotDataPsl1Guid,
       gSlotDataBuffer1, 32).
    6. Registers PSLT entry 2 via UbaProtocol->Register(gUbaSlotConfigGuid,
       gSlotDataBuffer2, 40).

  @param[in] ImageHandle  The firmware-allocated handle for this driver image.
  @param[in] SystemTable  A pointer to the EFI System Table.

  @return EFI_STATUS  EFI_SUCCESS on success, or error from LocateProtocol/Register.
**/
EFI_STATUS
EFIAPI
_ModuleEntryPoint (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE *SystemTable
  );

/**
  Returns the supported slot count for this platform.

  Always returns 2 for LightningRidge EXEC B2.
  This function is referenced by the UBA framework at RVA 0x4B0.

  @return UINT8  2 (number of PCIe slots for this platform).
**/
UINT8
EFIAPI
GetSlotCount (
  VOID
  );

/**
  Platform slot data identity pass-through.

  Returns its second argument (DefaultData) unchanged. This function is the
  GetSlotData callback at RVA 0x4B4 and allows platform-specific slot data
  customization, though for EXEC B2 no customization is needed beyond the
  template PSLT data registered with the UBA protocol.

  @param[in] Slot          Slot index (unused in B2).
  @param[in] DefaultData   Default slot data to pass through.

  @return VOID*  The unmodified DefaultData pointer.
**/
VOID *
EFIAPI
GetSlotData (
  IN UINTN  Slot,
  IN VOID   *DefaultData
  );

/**
  Lazily resolves and caches the UBA protocol interface.

  Checks the cache at gUbaProtocol first. If not yet resolved, allocates a
  test buffer of 31 bytes (EfiBootServicesData pool type) and frees it to
  verify pool is operational. Then calls gBS->LocateProtocol to find the
  UBA protocol interface by gUbaProtocolGuid.

  The located protocol interface is cached in gUbaProtocol (at 0xC28).

  @return UBA_PROTOCOL*  The cached UBA protocol interface, or NULL if not
                          found or pool allocation fails.
**/
UBA_PROTOCOL *
EFIAPI
UbaGetProtocolInterface (
  VOID
  );

/**
  UBA-aware debug print with CMOS platform-type filtering.

  Reads CMOS register 0x4B via I/O ports 0x70/0x71 to determine the platform
  debug verbosity level:
    - CMOS[0x4B] > 3: Use as-is for routing
    - CMOS[0x4B] == 0: Read hardware strap from 0xFDAF0490 bit 1 | 1
    - CMOS[0x4B] == 1: DebugRoute = 0x80000004 (EFI_D_INFO)
    - CMOS[0x4B] >= 2: DebugRoute = 0x80000006 (EFI_D_VERBOSE)

  If the severity mask from the caller matches the DebugRoute (bitwise AND),
  the message is forwarded to the UBA protocol's DebugPrint function at +0x00.

  @param[in] Severity  Debug message severity mask (e.g., 0x80000000 for ERROR).
  @param[in] Format    Print format string.
  @param[in] ...       Variable arguments for the format string.
**/
VOID
EFIAPI
UbaDebugPrint (
  IN UINT64       Severity,
  IN CONST CHAR8  *Format,
  ...
  );

/**
  UBA-aware ASSERT failure handler.

  Called when a DEBUG condition fails. Locates the UBA protocol and calls
  its DebugAssert function (at +0x08) with the file name, line number, and
  assertion expression.

  @param[in] FileName     Source file name where the assertion failed.
  @param[in] LineNumber   Line number of the failed assertion.
  @param[in] Expression   The assertion expression string.
**/
VOID
EFIAPI
UbaDebugAssert (
  IN CONST CHAR8  *FileName,
  IN UINTN         LineNumber,
  IN CONST CHAR8  *Expression
  );

/**
  Locates and caches the HOB list from the EFI System Table configuration table.

  Scans SystemTable->ConfigurationTable for an entry matching
  gEfiDxeServicesTableGuid ({7739F24C-93D7-11D4-9A3A-0090273FC14D}).
  The GUID comparison uses IsHobGuidMatch for unaligned-safe comparison of
  64-bit halves.

  If the GUID is found, caches the associated pointer in gHobList and returns
  it. If not found, triggers a debug assert via UbaDebugAssert and
  UbaDebugPrint.

  Result is cached in gHobList (at 0xC30) so subsequent calls return immediately.

  @return VOID*  Pointer to the HOB list, or NULL if not found.
**/
VOID *
EFIAPI
GetHobList (
  VOID
  );

/**
  Compares two EFI_GUID values via unaligned 64-bit reads.

  Reads both halves (first 8 bytes and last 8 bytes) of each GUID using
  ReadUnaligned64 and compares them. This avoids unaligned access faults
  on strict-alignment architectures.

  @param[in] Guid1  Pointer to first EFI_GUID.
  @param[in] Guid2  Pointer to second EFI_GUID.

  @return BOOLEAN  TRUE if both halves match, FALSE otherwise.
**/
BOOLEAN
EFIAPI
IsHobGuidMatch (
  IN EFI_GUID  *Guid1,
  IN EFI_GUID  *Guid2
  );

/**
  Reads a UINT64 from a potentially unaligned address with NULL check.

  Asserts via UbaDebugAssert if Buffer is NULL, then performs a 64-bit read
  from the given address. The function does not handle misalignment specially;
  it trusts the target CPU architecture to support unaligned reads.

  @param[in] Buffer  Pointer to the UINT64 to read (must not be NULL).

  @return UINT64  The 64-bit value at Buffer.
**/
UINT64
EFIAPI
ReadUnaligned64 (
  IN CONST UINT64  *Buffer
  );

#endif // SLOT_DATA_UPDATE_DXE_LIGHTNING_RIDGE_EXEC_B2_H