/** @file
  StaticSkuDataDxeLightningRidgeEXECB2.c -- Implementation.

  This UEFI DXE driver publishes three static configuration protocols
  (NUMPT, PIRQ, ACPF) for the LightningRidge EXECB2 platform. It contains
  embedded SKU configuration data in its .data section.

  Build path (inferred):
    e:\hs\Build\...\X64\PurleyRpPkg\Uba\UbaMain\Dxe\TypeLightningRidgeEXECB2\
      StaticSkuDataDxe\DEBUG\StaticSkuDataDxeLightningRidgeEXECB2.pdb

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

#include "StaticSkuDataDxeLightningRidgeEXECB2.h"

//
// Globals -- cached pointers set during ModuleEntryPoint
//

/// Global image handle.
EFI_HANDLE           gImageHandle     = NULL;

/// Global system table pointer.
EFI_SYSTEM_TABLE     *gSystemTable    = NULL;

/// Global boot services pointer (cached from SystemTable->BootServices).
EFI_BOOT_SERVICES    *gBootServices   = NULL;

/// Global runtime services pointer (cached from SystemTable->RuntimeServices).
EFI_RUNTIME_SERVICES *gRuntimeServices = NULL;

/// Cached platform protocol pointer (lazy-init via GetPlatformProtocol).
PLATFORM_PROTOCOL    *gPlatformProtocol = NULL;

/// Cached SKU configuration table pointer (lazy-init via GetSkuConfigTable).
VOID                 *gSkuConfigTable  = NULL;

//
// Platform type variable (CMOS 0x4B result caching, used by PlatformDebugPrint)
//

/// Cached platform type from CMOS register 0x4B.
/// 0 = unknown, 1-3 = valid, >3 may check HW strap at 0xFDAF0490.
UINT8                gPlatformType    = 0;

//
// GUID Definitions (in .rdata/.data section)
//

/// PLATFORM_PROTOCOL_GUID {36232936-0E76-31C8-A13A-3AF2FC1C3932}
STATIC CONST EFI_GUID mPlatformProtocolGuid = PLATFORM_PROTOCOL_GUID;

/// SKU_CONFIG_TABLE_GUID {7739F24C-93D7-11D4-9A3A-0090273FC14D}
STATIC CONST EFI_GUID mSkuConfigTableGuid  = SKU_CONFIG_TABLE_GUID;

/// NUMPT_PROTOCOL_GUID {0FF8A1CF-A0AB-4AC0-BFC9-34A78F68DD8A}
STATIC CONST EFI_GUID mNumptProtocolGuid   = NUMPT_PROTOCOL_GUID;

/// PIRQ_PROTOCOL_GUID {4C1F48A5-C976-4D90-9F03-8E9B1C327FCF}
STATIC CONST EFI_GUID mPirqProtocolGuid    = PIRQ_PROTOCOL_GUID;

/// ACPF_PROTOCOL_GUID {81129EF8-391D-4F63-AE99-58517EC077E3}
STATIC CONST EFI_GUID mAcpfProtocolGuid    = ACPF_PROTOCOL_GUID;

//
// Static Protocol Data (embedded in .data section)
//
// These structures are defined at fixed addresses in the PE .data section.
// The following extern declarations allow the code to reference them.
//

/// @brief  NUMPT protocol interface instance (24 bytes).
///
/// Layout:
///   +0x00: UINT32 Signature = "NUMPT"
///   +0x04: UINT32 Version   = 1
///   +0x08: VOID*  SkuTable    -> gNumptSkuTable
///   +0x10: VOID*  SkuCountTbl -> gNumptSkuCountTable
///
/// Defined at absolute address 0x40B0 (after GUID header).
extern NUMPT_PROTOCOL mNumptProtocolIf;

/// @brief  PIRQ protocol interface instance (16 bytes).
///
/// Layout:
///   +0x00: UINT32 Signature = "PIRQ"
///   +0x04: UINT32 Version   = 1
///   +0x08: VOID*  PirqTable -> gPirqTable
///
/// Defined at absolute address 0x40D8.
extern PIRQ_PROTOCOL  mPirqProtocolIf;

/// @brief  ACPF protocol interface instance (16 bytes).
///
/// Layout:
///   +0x00: UINT32 Signature = "ACPF"
///   +0x04: UINT32 Version   = 1
///   +0x08: UINT32 BoardType = platform board type
///   +0x0C: UINT32 Reserved  = 0
///
/// Defined at absolute address 0x9020.
extern ACPF_PROTOCOL  mAcpfProtocolIf;

//
// Function: PlatformAssert / sub_5C8
//

/**
  ASSERT handler wrapper for UEFI.

  Calls the platform protocol's ASSERT function at protocol offset 0x08.
  This is the standard UEFI ASSERT() implementation used in this binary.

  If the platform protocol has not been initialized yet (gPlatformProtocol
  is NULL), this function is a no-op and returns.

  @param[in] FileName     Source filename of the ASSERT.
  @param[in] LineNumber   Source line number of the ASSERT.
  @param[in] Description  ASSERT condition string.
**/
VOID
EFIAPI
PlatformAssert (
  IN CONST CHAR8 *FileName,
  IN UINTN       LineNumber,
  IN CONST CHAR8 *Description
  )
{
  //
  // gPlatformProtocol is lazy-init via GetPlatformProtocol().
  // If it's NULL, LocateProtocol hasn't succeeded and we skip.
  //
  GetPlatformProtocol ();
  if (gPlatformProtocol != NULL) {
    //
    // Protocol offset +0x08: DebugAssert(FileName, LineNumber, Description)
    //
    gPlatformProtocol->DebugAssert (FileName, LineNumber, Description);
  }
}

//
// Function: GetPlatformProtocol / sub_4C0
//

/**
  Lazy-initializes the platform protocol pointer via gBS->LocateProtocol.

  This function includes a health-check allocation of 31 bytes of pool:
    - If AllocatePool returns an address <= 0x10, the allocator is considered
      unreliable and LocateProtocol is skipped.
    - Otherwise, the pool is freed and LocateProtocol is called.

  The result is cached in gPlatformProtocol.

  @return  Pointer to PLATFORM_PROTOCOL, or NULL if not available.
**/
PLATFORM_PROTOCOL *
GetPlatformProtocol (
  VOID
  )
{
  //
  // Return cached value if already resolved.
  //
  if (gPlatformProtocol == NULL) {
    UINT64  PoolProbe;

    //
    // Health check: allocate 31 bytes as a pool probe.
    //
    PoolProbe = (UINT64)gBootServices->AllocatePool (31);

    //
    // Free the probe allocation immediately.
    //
    gBootServices->FreePool ((VOID *)PoolProbe);

    //
    // If pool returned > 0x10 bytes, allocator is healthy -> LocateProtocol.
    //
    if (PoolProbe <= 0x10) {
      return NULL;
    }

    //
    // Locate the platform protocol by GUID.
    //
    gBootServices->LocateProtocol (
                     &mPlatformProtocolGuid,
                     NULL,
                     (VOID **)&gPlatformProtocol
                     );

    //
    // If LocateProtocol failed, ensure we return NULL.
    //
    if (gPlatformProtocol == NULL) {
      return NULL;
    }
  }

  return gPlatformProtocol;
}

//
// Function: PlatformDebugPrint / sub_540
//

/**
  Platform-aware debug print with ASSERT routing.

  Reads CMOS RTC register 0x4B via I/O ports 0x70/0x71 to determine the
  platform's routing type, then conditionally calls the platform protocol's
  debug print function.

  Platform type determination (from CMOS 0x4B):
    - 0:      Fallback: read hardware strap at 0xFDAF0490, mask bit 1, OR with 1
    - 1:      Routing mask = 0x80000004 (DEBUG_INIT)
    - 2-3:    Routing mask = 0x80000006 (DEBUG_ERROR)
    - >3:     Already valid (preserved as-is)

  NMI is preserved by masking bit 7 of CMOS address port 0x70.

  @param[in] Status        EFI_STATUS or debug level mask.
  @param[in] FormatString  Debug format string.
  @param[in] ...           Additional format arguments.
**/
VOID
EFIAPI
PlatformDebugPrint (
  IN UINTN       Status,
  IN CONST CHAR8 *FormatString,
  ...
  )
{
  PLATFORM_PROTOCOL *Protocol;
  UINTN             RouteMask;
  UINT8             PlatformType;
  UINT8             CmosAddr;

  Protocol = GetPlatformProtocol ();
  if (Protocol == NULL) {
    return;
  }

  //
  // Read CMOS register 0x4B for platform type.
  // Preserve NMI mask (bit 7) in CMOS address register.
  //
  CmosAddr     = __inbyte (0x70);
  __outbyte (0x70, (CmosAddr & 0x80) | 0x4B);
  PlatformType = __inbyte (0x71);

  //
  // Determine routing mask from platform type.
  //
  if (PlatformType > 3) {
    //
    // Value is stale/invalid; treat as unchanged.
    //
    PlatformType = PlatformType;  // No-op: preserve existing
    if (PlatformType == 0) {
      //
      // Fallback: read hardware strap register.
      //
      PlatformType = (*(volatile UINT8 *)0xFDAF0490 & 2) | 1;
    }
  }

  RouteMask = 0;
  if ((PlatformType - 1) <= 0xFD) {
    RouteMask = 0x80000006;  // DEBUG_ERROR
    if (PlatformType == 1) {
      RouteMask = 0x80000004;  // DEBUG_INIT
    }
  }

  //
  // Call protocol's DebugPrint only if the status mask matches.
  //
  if ((RouteMask & Status) != 0) {
    Protocol->DebugAssert (Status, FormatString, NULL);
  }
}

//
// Function: ReadUnaligned64 / sub_750
//

/**
  Reads a possibly-unaligned UINT64 from memory.

  Asserts if Buffer is NULL.

  @param[in] Buffer  Pointer to the value to read (may be unaligned).

  @return The 64-bit value at the given memory address.
**/
UINT64
EFIAPI
ReadUnaligned64 (
  IN CONST VOID  *Buffer
  )
{
  if (Buffer == NULL) {
    PlatformAssert (
      "e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
      192,
      "Buffer != ((void *) 0)"
      );
  }

  return *(volatile UINT64 *)Buffer;
}

//
// Function: IsSkuConfigTableGuid / sub_6E0
//

/**
  Checks whether the given GUID matches mSkuConfigTableGuid.

  Compares the GUID as two UINT64 halves to avoid full memcmp.

  @param[in] Context      Ignored (passed from GetSkuConfigTable).
  @param[in] GuidToCheck  Pointer to the GUID to compare.

  @return TRUE if GuidToCheck == mSkuConfigTableGuid.
**/
BOOLEAN
IsSkuConfigTableGuid (
  IN VOID  *Context,
  IN VOID  *GuidToCheck
  )
{
  UINT64  KnownLow;
  UINT64  KnownHigh;
  UINT64  CheckLow;
  UINT64  CheckHigh;

  //
  // Read the known GUID as two 64-bit unaligned values.
  //
  KnownLow  = ReadUnaligned64 (&mSkuConfigTableGuid);
  KnownHigh = ReadUnaligned64 ((UINT8 *)&mSkuConfigTableGuid + 8);

  //
  // Read the candidate GUID as two 64-bit unaligned values.
  //
  CheckLow  = ReadUnaligned64 (GuidToCheck);
  CheckHigh = ReadUnaligned64 ((UINT8 *)GuidToCheck + 8);

  return (BOOLEAN)(KnownLow == CheckLow && KnownHigh == CheckHigh);
}

//
// Function: GetSkuConfigTable / sub_608
//

/**
  Locates the platform SKU configuration table pointer.

  Walks the SystemTable->ConfigurationTable[] array (at SystemTable + 0x68
  for count, +0x70 for pointer) looking for an entry whose VendorGuid matches
  mSkuConfigTableGuid.

  The discovered VendorTable pointer is cached in gSkuConfigTable so subsequent
  calls return immediately.

  @param[in] Context  Ignored (may be NULL / uninitialized HOB probe).

  @return Pointer to the SKU configuration table, or NULL if not found.
**/
VOID *
GetSkuConfigTable (
  IN VOID  *Context
  )
{
  UINTN                     Index;
  UINTN                     EntryCount;
  EFI_CONFIGURATION_TABLE   *ConfigTable;

  //
  // Return cached value if already resolved.
  //
  if (gSkuConfigTable == NULL) {
    gSkuConfigTable = NULL;  // Initialize to NULL

    //
    // Get the configuration table count and array pointer from SystemTable.
    //
    EntryCount  = *(UINTN *)((UINT8 *)gSystemTable + 104);   // SystemTable->NumberOfTableEntries
    ConfigTable = *(EFI_CONFIGURATION_TABLE **)((UINT8 *)gSystemTable + 112);  // SystemTable->ConfigurationTable

    if (ConfigTable != NULL) {
      //
      // Walk the ConfigurationTable array looking for our GUID.
      // Table entries are 24 bytes (16-byte GUID + 8-byte pointer).
      //
      for (Index = 0; Index < EntryCount; Index++) {
        if (IsSkuConfigTableGuid (Context, &ConfigTable[Index].VendorGuid)) {
          gSkuConfigTable = ConfigTable[Index].VendorTable;
          break;
        }
      }

      if (gSkuConfigTable == NULL) {
        //
        // ASSERT_EFI_ERROR output for table not found.
        //
        PlatformDebugPrint (
          0x80000000LL,
          "\nASSERT_EFI_ERROR (Status = %r)\n",
          0x800000000000000ELL   // EFI_NOT_FOUND encoding
          );

        PlatformAssert (
          "e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
          54,
          "!EFI_ERROR (Status)"
          );
      }
    } else {
      //
      // ConfigurationTable is NULL -- system not ready.
      //
      PlatformDebugPrint (
        0x80000000LL,
        "\nASSERT_EFI_ERROR (Status = %r)\n",
        0x800000000000000ELL
        );

      PlatformAssert (
        "e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
        55,
        "mHobList != ((void *) 0)"
        );
    }
  }

  return gSkuConfigTable;
}

//
// Function: ModuleEntryPoint / sub_390
//

/**
  Standard UEFI DXE driver entry point.

  Called by DxeCore during driver dispatch. Performs:

  1. Caches ImageHandle and SystemTable as globals.
  2. Caches BootServices and RuntimeServices from SystemTable.
  3. Asserts on NULL for all cached pointers.
  4. Locates the SKU config table via GetSkuConfigTable().
  5. Locates the platform protocol.
  6. Installs three static data protocols:
     - NUMPT (24-byte interface, under NUMPT_PROTOCOL_GUID)
     - PIRQ  (16-byte interface, under  PIRQ_PROTOCOL_GUID)
     - ACPF  (16-byte interface, under  ACPF_PROTOCOL_GUID)

  @param[in] ImageHandle  UEFI image handle assigned to this driver.
  @param[in] SystemTable  Pointer to the UEFI system table.

  @return EFI_SUCCESS, or error from protocol lookups/installations.
**/
EFI_STATUS
EFIAPI
StaticSkuDataDxeEntryPoint (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS  Status;
  VOID        *Protocol;

  //
  // Cache ImageHandle.
  //
  gImageHandle = ImageHandle;
  if (gImageHandle == NULL) {
    PlatformAssert (
      "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      51,
      "gImageHandle != ((void *) 0)"
      );
  }

  //
  // Cache SystemTable.
  //
  gSystemTable = SystemTable;
  if (gSystemTable == NULL) {
    PlatformAssert (
      "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      57,
      "gST != ((void *) 0)"
      );
  }

  //
  // Cache BootServices.
  //
  gBootServices = SystemTable->BootServices;
  if (gBootServices == NULL) {
    PlatformAssert (
      "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      63,
      "gBS != ((void *) 0)"
      );
  }

  //
  // Cache RuntimeServices.
  //
  gRuntimeServices = SystemTable->RuntimeServices;
  if (gRuntimeServices == NULL) {
    PlatformAssert (
      "e:\\hs\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c",
      47,
      "gRT != ((void *) 0)"
      );
  }

  //
  // Locate the SKU configuration table (cached in gSkuConfigTable).
  // This walks SystemTable->ConfigurationTable[] looking for our GUID.
  //
  GetSkuConfigTable (NULL);

  //
  // Locate platform protocol on the ImageHandle.
  // This protocol handles InstallProtocol calls.
  //
  Status = gBootServices->LocateProtocol (
                            &mSkuConfigTableGuid,
                            NULL,
                            &Protocol
                            );

  if (!EFI_ERROR (Status)) {
    //
    // Install NUMPT protocol: GUID at 0x40C8, interface at 0x40B0, size 24.
    //
    Status = ((PLATFORM_PROTOCOL *)Protocol)->InstallProtocol (
                                                Protocol,
                                                (EFI_GUID *)&mNumptProtocolGuid,
                                                &mNumptProtocolIf,
                                                24
                                                );

    if (!EFI_ERROR (Status)) {
      //
      // Install PIRQ protocol: GUID at 0x40E8, interface at 0x40D8, size 16.
      //
      Status = ((PLATFORM_PROTOCOL *)Protocol)->InstallProtocol (
                                                  Protocol,
                                                  (EFI_GUID *)&mPirqProtocolGuid,
                                                  &mPirqProtocolIf,
                                                  16
                                                  );

      if (!EFI_ERROR (Status)) {
        //
        // Install ACPF protocol: GUID at 0x9030, interface at 0x9020, size 16.
        //
        Status = ((PLATFORM_PROTOCOL *)Protocol)->InstallProtocol (
                                                    Protocol,
                                                    (EFI_GUID *)&mAcpfProtocolGuid,
                                                    &mAcpfProtocolIf,
                                                    16
                                                    );
      }
    }
  }

  return Status;
}

//
// NOTE: The static data structures mNumptProtocolIf, mPirqProtocolIf,
// and mAcpfProtocolIf are defined in the .data section of the PE image
// at fixed offsets (0x40B0, 0x40D8, 0x9020 respectively). Their contents
// were set at build time by the UBA framework and are treated as
// read-only data at runtime.
//
// The NUMPT interface references two additional tables:
//   - NUMPT SkuTable (0x9060): { {0x9110,25}, {0xDB30,2}, {0xDB60,275},
//                                  {0xBD80,67}, {0xF528,1}, {0x0000,0} }
//   - NUMPT SkuCountTable (0x9040): { {0xD690,59}, {0xC2C0,211} }
//
// The PIRQ interface references one table (0x90D8):
//   - { {0xBD70,7}, {0x9660,1}, {0x9240,526} }
//   where PIRQ routing entries at 0x9240+ are 32 bytes each:
//     [Enable/Disable, MMIO Addr Low, MMIO Addr High, IRQ source, ...]
//
// The ACPF interface is self-contained (board type field).
//