/** @file
  SetupConfigUpdateDxeCLX64L -- UEFI Driver
  HR650X BIOS Setup Configuration Update for the CLX64L Platform

  This DXE driver publishes the CLX64L platform-specific setup configuration
  block. At entry it initialises the standard UEFI library globals (ImageHandle,
  SystemTable, BootServices, RuntimeServices), locates the HOB list from the
  system configuration table, then locates the platform configuration receiver
  protocol and installs the PSET (Platform SETup) configuration data.

  The configuration block has a 24-byte header:
    - Signature "PSET" (0x54455350)
    - Revision 1
    - TotalSize = 0x48C (1164 bytes)
    - Reserved fields

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

#include "SetupConfigUpdateDxeCLX64L.h"

//
// ---------------------------------------------------------------------------
// Globals
// ---------------------------------------------------------------------------

//
// UefiBootServicesTableLib / UefiRuntimeServicesTableLib backing
//
EFI_HANDLE            gImageHandle     = NULL;
EFI_SYSTEM_TABLE     *gST              = NULL;
EFI_BOOT_SERVICES    *gBS              = NULL;
EFI_RUNTIME_SERVICES *gRT              = NULL;

//
// Module globals
//
EFI_HANDLE            mImageHandle     = NULL;  ///< Saved image handle
VOID                 *mHobList         = NULL;  ///< Cached HOB list pointer

//
// GUID instances
//
EFI_GUID  gSetupConfigUpdateProtocolGuid  = SETUP_CONFIG_UPDATE_PROTOCOL_GUID;
EFI_GUID  gConfigReceiverProtocolGuid     = CONFIG_RECEIVER_PROTOCOL_GUID;
EFI_GUID  gConfigDataProtocolGuid         = CONFIG_DATA_PROTOCOL_GUID;
EFI_GUID  gHobListGuid                    = HOB_LIST_GUID;

//
// Embedded HOB list GUID, split across two QWORD-aligned storage locations
// for efficient comparison in CompareGuidPair().
// gHobListGuid = {7739F24C-93D7-11D4-9A3A-0090273FC14D}
//
// Stored as two UINT64 values at gHobListGuidLo (0xB40) and
// gHobListGuidHi (0xB48) for the inline comparison function to access
// without loading the full GUID from .rdata.
//
STATIC CONST UINT64  gHobListGuidLo  = 0x11D493D77739F24CULL;  ///< First  8 bytes
STATIC CONST UINT64  gHobListGuidHi  = 0x4DC13F2790003A9AULL;  ///< Second 8 bytes

//
// Static PSET configuration data header for the CLX64L platform.
// The full configuration block (header + payload) occupies 0x48C bytes.
//
STATIC CONST SETUP_CONFIG_DATA_HEADER  mSetupConfigDataHeader = {
  .Signature  = 0x54455350U,              ///< "PSET"
  .Revision   = 1,
  .TotalSize  = CLX64L_CONFIG_TOTAL_SIZE,
  .Reserved0  = 0,
  .DataSize   = CLX64L_CONFIG_TOTAL_SIZE,
  .Reserved1  = 0,
};

//
// ---------------------------------------------------------------------------
// Helper functions
// ---------------------------------------------------------------------------

/**
  Reads a UINT64 value from memory at the given address.
  Simply dereferences the pointer; the caller is responsible for alignment
  guarantees.

  @param[in]  Buffer  Pointer to the memory to read.

  @return The UINT64 value at Buffer.
**/
UINT64
EFIAPI
ReadUnaligned64 (
  IN CONST VOID  *Buffer
  )
{
  ASSERT (Buffer != NULL);
  return *(CONST UINT64 *)Buffer;
}

/**
  Compares two GUID values by comparing them as two UINT64 pairs.

  This is a specialised comparison used by the HOB list locator.
  It compares the first 8 bytes and second 8 bytes of each GUID.

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

  @retval TRUE   The GUIDs are identical.
  @retval FALSE  The GUIDs differ.
**/
BOOLEAN
EFIAPI
CompareGuidPair (
  IN CONST EFI_GUID  *Guid1,
  IN CONST EFI_GUID  *Guid2
  )
{
  if (ReadUnaligned64 (Guid1) != ReadUnaligned64 (Guid2)) {
    return FALSE;
  }

  if (ReadUnaligned64 ((CONST UINT8 *)Guid1 + 8) !=
      ReadUnaligned64 ((CONST UINT8 *)Guid2 + 8)) {
    return FALSE;
  }

  return TRUE;
}

/**
  Assert handler -- writes an assertion failure to the debug log.

  Displays the file name, line number, and failing expression via the
  debug protocol (located through the Standard Error / Debug Assert
  interface).

  @param[in]  FileName     The source file name of the assertion.
  @param[in]  LineNumber   The line number of the assertion.
  @param[in]  Description  The assertion expression text.
**/
VOID
EFIAPI
DebugAssert (
  IN CONST CHAR8  *FileName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *Description
  )
{
  //
  // Locate the debug assert protocol from Boot Services.
  // (The protocol interface is cached in a module global.)
  //
  STATIC VOID  *mAssertProtocol = NULL;
  EFI_STATUS    Status;

  if (mAssertProtocol == NULL && gBS != NULL) {
    Status = gBS->LocateProtocol (
                    &gEfiDebugAssertProtocolGuid,
                    NULL,
                    &mAssertProtocol
                    );
    if (EFI_ERROR (Status)) {
      return;
    }
  }

  if (mAssertProtocol != NULL) {
    //
    // Call the assert function at the protocol's standard offset.
    //
    ((EFI_DEBUG_ASSERT_PROTOCOL *)mAssertProtocol)->Assert (
                                                       FileName,
                                                       LineNumber,
                                                       Description
                                                       );
  }
}

//
// ---------------------------------------------------------------------------
// HOB list locator
// ---------------------------------------------------------------------------

/**
  Locates the HOB list from the system configuration table.

  Iterates SystemTable->ConfigurationTable looking for the entry whose
  VendorGuid matches gHobListGuid. On success the pointer is cached in
  the mHobList global for subsequent calls.

  This function is the GetHobList() implementation used in place of the
  standard DxeHobLib routine, with the GUID comparison performed using
  the embedded gHobListGuidLo/gHobListGuidHi constants.

  @return  Pointer to the HOB list, or NULL if not found.
**/
VOID *
EFIAPI
GetHobList (
  VOID
  )
{
  UINTN                    Index;
  EFI_CONFIGURATION_TABLE *ConfigTable;
  UINT64                  *GuidEntry;
  UINT64                  *HobGuidLo;
  UINT64                  *HobGuidHi;

  //
  // Return cached value if already resolved.
  //
  if (mHobList != NULL) {
    return mHobList;
  }

  mHobList = NULL;

  //
  // Sanity-check: the system configuration table must have entries.
  //
  if (gST->NumberOfTableEntries == 0) {
    //
    // No configuration table entries -- emit diagnostic and assert.
    //
    DEBUG ((DEBUG_SETUP_CONFIG,
            "ASSERT_EFI_ERROR (Status = No HOB configuration table)\n"));
    DEBUG ((DEBUG_SETUP_CONFIG,
            "%a(%d): !EFI_ERROR (Status)\n", __FILE__, __LINE__));
    //
    // Fall through to the NULL check below.
    //
  } else {
    //
    // Walk the configuration table looking for the HOB list GUID.
    // Each entry is an EFI_CONFIGURATION_TULE (16-byte GUID + pointer).
    //
    ConfigTable = gST->ConfigurationTable;
    HobGuidLo   = (UINT64 *)&gHobListGuidLo;
    HobGuidHi   = (UINT64 *)&gHobListGuidHi;

    for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
      GuidEntry = (UINT64 *)&ConfigTable[Index].VendorGuid;

      //
      // Compare as two QWORDs (first 8 bytes, then second 8 bytes).
      //
      if ((GuidEntry[0] == *HobGuidLo) && (GuidEntry[1] == *HobGuidHi)) {
        //
        // VendorTable follows the GUID in the configuration table entry.
        // Cast through byte pointer arithmetic to avoid strict aliasing.
        //
        mHobList = *(VOID **)((UINT8 *)GuidEntry + 16);
        break;
      }
    }

    //
    // If the HOB list was not found, emit a diagnostic.
    //
    if (mHobList == NULL) {
      DEBUG ((DEBUG_SETUP_CONFIG,
              "ASSERT_EFI_ERROR (Status = HOB list GUID not found)\n"));
      DEBUG ((DEBUG_SETUP_CONFIG,
              "%a(%d): !EFI_ERROR (Status)\n", __FILE__, __LINE__));
    }
  }

  //
  // The HOB list must be non-NULL at this point.
  //
  if (mHobList == NULL) {
    DEBUG ((DEBUG_SETUP_CONFIG,
            "%a(%d): mHobList != ((void *) 0)\n", __FILE__, __LINE__));
  }

  return mHobList;
}

//
// ---------------------------------------------------------------------------
// Module entry point
// ---------------------------------------------------------------------------

/**
  Module entry point.

  Initialises the UEFI globals (ImageHandle, SystemTable, BootServices,
  RuntimeServices), resolves the HOB list, then locates the configuration
  receiver protocol and installs the CLX64L platform setup data.

  This entry mirrors the standard _ModuleEntryPoint produced by the
  UefiBootServicesTableLib / UefiRuntimeServicesTableLib combination.

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

  @retval EFI_SUCCESS           Configuration installed successfully.
  @retval EFI_INVALID_PARAMETER ImageHandle or SystemTable is NULL.
  @retval EFI_NOT_FOUND         A required protocol was not found.
  @retval Others                The configuration installation failed.
**/
EFI_STATUS
EFIAPI
SetupConfigUpdateEntry (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE *SystemTable
  )
{
  EFI_STATUS  Status;
  VOID       *ReceiverProtocol;

  //
  // ---- Phase 1: UEFI Library Initialisation ----
  //

  gImageHandle = ImageHandle;
  if (gImageHandle == NULL) {
    DebugAssert (
      __FILE__,
      __LINE__,
      "gImageHandle != ((void *) 0)"
      );
  }

  gST = SystemTable;
  if (gST == NULL) {
    DebugAssert (
      __FILE__,
      __LINE__,
      "gST != ((void *) 0)"
      );
  }

  gBS = gST->BootServices;
  if (gBS == NULL) {
    DebugAssert (
      __FILE__,
      __LINE__,
      "gBS != ((void *) 0)"
      );
  }

  gRT = gST->RuntimeServices;
  if (gRT == NULL) {
    DebugAssert (
      __FILE__,
      __LINE__,
      "gRT != ((void *) 0)"
      );
  }

  //
  // ---- Phase 2: HOB list resolution ----
  //

  mHobList = GetHobList ();

  //
  // ---- Phase 3: Debug log platform identification ----
  //

  DEBUG ((DEBUG_SETUP_CONFIG,
          "UBA:SETUPConfigUpdate-TypeClx64L\n"));

  //
  // ---- Phase 4: Install setup configuration ----
  //

  //
  // Locate the configuration receiver protocol.
  // gBS->LocateProtocol() at offset 0x140 in the Boot Services table.
  //
  Status = gBS->LocateProtocol (
                  &gConfigReceiverProtocolGuid,
                  NULL,                             // Registration (optional)
                  &ReceiverProtocol
                  );

  if (EFI_ERROR (Status)) {
    //
    // Protocol not found -- return the error status.
    //
    return Status;
  }

  //
  // Install the setup config via the receiver protocol.
  // Function at offset 0x10 in the protocol interface.
  // Signature: (EFI_STATUS *)(VOID *This, EFI_GUID *ProtocolGuid,
  //                           VOID *ConfigData, UINTN ConfigDataSize)
  //
  Status = ((EFI_STATUS (EFIAPI *)(
              VOID        *This,
              EFI_GUID    *ProtocolGuid,
              VOID        *ConfigData,
              UINTN       ConfigDataSize
              )) ((EFI_STATUS **)ReceiverProtocol)[2]) (  // offset 0x10 = index 2
    ReceiverProtocol,
    &gConfigDataProtocolGuid,
    (VOID *)&mSetupConfigDataHeader,
    sizeof (mSetupConfigDataHeader)
    );

  return Status;
}