Newer
Older
AMI-Aptio-BIOS-Reversed / FpgaDxe / FpgaDxe.c
@Ajax Dong Ajax Dong 2 days ago 52 KB Init
/** @file
  FPGA Initialization DXE Driver -- FpgaDxe

  This module implements FPGA initialization for the Purley platform (HR650X).
  It performs the following tasks:

  1. Reads FPGA configuration from a HOB (Hand-Off Block) or creates one
     from UEFI variables ("FpgaSocketConfig").
  2. Locates PCI(e) root bridge I/O and USRA (Universal Segment Resource
     Access) protocols for MMIO/PCI config space access.
  3. Initializes S3 boot script services to save/restore FPGA register
     state across S3 resumes.
  4. On ReadyToBoot, enumerates FPGA devices per active socket, programs
     PCI bus/subordinate numbers, FME BARs, temperature thresholds, HSSI
     configuration, and miscellaneous FPGA control registers.
  5. Triggers a software SMI to finalize FPGA initialization in SMM.

  Source path (original build):
    e:\hs\PurleySktPkg\Dxe\FpgaInit\FpgaDxe\FpgaDxe.c
    e:\hs\Build\HR6N0XMLK\DEBUG_VS2015\X64\PurleySktPkg\Dxe\FpgaInit\FpgaDxe\FpgaDxe\DEBUG\AutoGen.c

  Build config: VS2015, X64, DEBUG
  Module size:  0x6D80 bytes (28 KB)

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

#include "FpgaDxe.h"

//
// ---------------------------------------------------------------------------
// Global variable storage
// ---------------------------------------------------------------------------
//
EFI_HANDLE           gImageHandle  = NULL;
EFI_SYSTEM_TABLE     *gSystemTable = NULL;
EFI_BOOT_SERVICES    *gBootServices = NULL;
EFI_RUNTIME_SERVICES *gRuntimeServices = NULL;
VOID                 *gDS           = NULL;   // qword_67B0
VOID                 *mPcd          = NULL;   // qword_67A0
VOID                 *mPciUsra      = NULL;   // qword_67B8
VOID                 *mUsra         = NULL;   // qword_6808
VOID                 *mHobList      = NULL;   // qword_67C0
VOID                 *mEventDxeSmmReadyToLock = NULL;  // qword_67E0
VOID                 *gEfiSmmReadyToLockProtocol = NULL; // qword_67E8
UINTN                gPciExpressBaseAddress = 0;        // qword_67C8
VOID                 *mSmmCommunication     = NULL;     // qword_6818
VOID                 *mSmmCommRegion        = NULL;     // qword_6810

//
// FPGA HOB configuration data (from unk_6880)
//
UINT8 gFpgaConfigValid;        // byte_6880 -- non-zero if HOB is valid
UINT8 gFpgaSktActive;          // byte_6883 -- bitmask of active sockets
UINT8 gFpgaSktConfig5;         // byte_6885
UINT8 gFpgaSktConfig6;         // byte_6886
UINT8 gFpgaSktConfig31;        // byte_689F
UINT8 gFpgaSktConfig32;        // byte_68A0
UINT8 gFpgaDxeUnlock;          // byte_68A5 -- if ==1, skip DXE lock config
UINT8 gFpgaSktConfigBuf[7];    // unk_6887 (per-socket fields)
UINT8 gFpgaSktTempThresh[2];   // byte_689B, byte_689C

UINT64 gFmeBar[FPGA_MAX_SOCKET];  // qword_6840 (4 entries)
UINT64 gGlobalNvsArea;            // qword_68A8

//
// S3 boot script context
//
UINT8  *gS3BootScriptBuf      = NULL;  // qword_6828
UINT8  *gS3BootScriptBackup   = NULL;  // qword_6830
UINT8  gBootScriptFlag1       = 0;     // byte_67D8
UINT8  gBootScriptFlag2       = 0;     // byte_6800
VOID   *gSmmReadyToLockEvent1= NULL;   // qword_67F0
VOID   *gSmmReadyToLockEvent2= NULL;   // qword_67D0
VOID   *gSmmReadyToLockEvent3= NULL;   // qword_67F8

//
// LockBox GUID storage (mutable runtime data, unk_6740/60/70/50)
//
UINT8 gLockBoxGuid1[16];  // qword_6740
UINT8 gLockBoxGuid2[16];  // qword_6760
UINT8 gLockBoxGuid3[16];  // qword_6770

// ---------------------------------------------------------------------------
// Internal helper prototypes
// ---------------------------------------------------------------------------

STATIC
VOID
InternalAssert (
  CONST CHAR8 *FileName,
  UINTN       LineNumber,
  CONST CHAR8 *Description
  );

STATIC
EFI_STATUS
GetDxeServicesTable (
  VOID
  );

STATIC
EFI_STATUS
GetPcdProtocol (
  VOID
  );

STATIC
EFI_STATUS
GetMmPciBaseProtocol (
  VOID
  );

STATIC
EFI_STATUS
GetHobList (
  VOID
  );

STATIC
EFI_STATUS
GetUsraProtocol (
  VOID
  );

STATIC
EFI_STATUS
GetSmmCommunication (
  VOID
  );

STATIC
VOID
S3BootScriptEventNotify (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  );

STATIC
VOID
S3BootScriptBackupNotify (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  );

STATIC
BOOLEAN
CompareGuid (
  IN CONST EFI_GUID *Guid1,
  IN CONST EFI_GUID *Guid2
  );

// ---------------------------------------------------------------------------
// Internal: ZeroMem / CopyMem (base library primitives)
// ---------------------------------------------------------------------------

/**
  ZeroMem: fills a buffer with zeros.

  @param[out] Buffer  Pointer to buffer to zero.
  @param[in]  Length  Number of bytes to zero.
**/
STATIC
VOID *
InternalZeroMem (
  OUT VOID   *Buffer,
  IN  UINTN  Length
  )
{
  //
  // Zero in 8-byte chunks, then remaining bytes.
  //
  ZeroMem (Buffer, Length);
  return Buffer;
}

/**
  CopyMem: copies one buffer to another, handling overlap correctly.

  @param[out] DestinationBuffer  Pointer to the destination buffer.
  @param[in]  SourceBuffer       Pointer to the source buffer.
  @param[in]  Length             Number of bytes to copy.
**/
STATIC
VOID *
InternalCopyMem (
  OUT VOID       *DestinationBuffer,
  IN  CONST VOID *SourceBuffer,
  IN  UINTN      Length
  )
{
  return CopyMem (DestinationBuffer, SourceBuffer, Length);
}

// ---------------------------------------------------------------------------
// 1 -- Library constructor: UefiBootServicesTableLib, UefiRuntimeServicesTableLib
// ---------------------------------------------------------------------------

/**
  Initialize global UEFI boot/runtime services table pointers.

  Called from the DXE driver entry point before any other initialization.

  @param[in] ImageHandle  The firmware allocated handle for the EFI image.
  @param[in] SystemTable  A pointer to the EFI System Table.
**/
STATIC
VOID
InitializeLibServices (
  IN EFI_HANDLE       ImageHandle,
  IN EFI_SYSTEM_TABLE *SystemTable
  )
{
  gImageHandle     = ImageHandle;
  ASSERT (gImageHandle != NULL);

  gSystemTable     = SystemTable;
  ASSERT (gSystemTable != NULL);

  gBootServices    = SystemTable->BootServices;
  ASSERT (gBootServices != NULL);

  gRuntimeServices = SystemTable->RuntimeServices;
  ASSERT (gRuntimeServices != NULL);
}

// ---------------------------------------------------------------------------
// 2 -- DxeServicesTableLib constructor
// ---------------------------------------------------------------------------

/**
  Locates and caches the DXE Services Table pointer.

  @retval EFI_SUCCESS  gDS is now valid.
  @retval other        DXE Services Table not found.
**/
STATIC
EFI_STATUS
GetDxeServicesTable (
  VOID
  )
{
  EFI_STATUS Status;

  Status = gBS->LocateProtocol (
                  &gEfiDxeServicesTableGuid,
                  NULL,
                  &gDS
                  );
  ASSERT_EFI_ERROR (Status);
  ASSERT (gDS != NULL);
  return Status;
}

// ---------------------------------------------------------------------------
// 3 -- PcdLib constructor
// ---------------------------------------------------------------------------

/**
  Locates and caches the PCD protocol.

  @retval EFI_SUCCESS  mPcd is valid.
  @retval other        PCD protocol not found.
**/
STATIC
EFI_STATUS
GetPcdProtocol (
  VOID
  )
{
  EFI_STATUS Status;

  if (mPcd != NULL) {
    return EFI_SUCCESS;
  }

  Status = gBS->LocateProtocol (
                  &gEfiPcdProtocolGuid,
                  NULL,
                  &mPcd
                  );
  ASSERT_EFI_ERROR (Status);
  ASSERT (mPcd != NULL);
  return Status;
}

// ---------------------------------------------------------------------------
// 4 -- DxeMmPciBaseLib constructor
// ---------------------------------------------------------------------------

/**
  Locates and caches the MM PCI USRA protocol.

  @retval EFI_SUCCESS  mPciUsra is valid.
  @retval other        Protocol not found.
**/
STATIC
EFI_STATUS
GetMmPciBaseProtocol (
  VOID
  )
{
  EFI_STATUS Status;

  if (mPciUsra != NULL) {
    return EFI_SUCCESS;
  }

  Status = gBS->LocateProtocol (
                  &gEfiMmPciBaseProtocolGuid,
                  NULL,
                  &mPciUsra
                  );
  ASSERT_EFI_ERROR (Status);
  ASSERT (mPciUsra != NULL);
  return Status;
}

// ---------------------------------------------------------------------------
// 5 -- DxeHobLib constructor
// ---------------------------------------------------------------------------

/**
  Locates and caches the HOB list pointer from the DXE Services Table.

  @retval EFI_SUCCESS  mHobList is valid.
  @retval other        HOB list not found.
**/
STATIC
EFI_STATUS
GetHobList (
  VOID
  )
{
  EFI_STATUS Status;

  if (mHobList != NULL) {
    return EFI_SUCCESS;
  }

  Status = EfiGetSystemConfigurationTable (
             &gEfiHobListGuid,
             &mHobList
             );
  ASSERT_EFI_ERROR (Status);
  ASSERT (mHobList != NULL);
  return Status;
}

// ---------------------------------------------------------------------------
// 6 -- Guid comparison helper
// ---------------------------------------------------------------------------

/**
  Compares two EFI GUIDs.

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

  @retval TRUE   The GUIDs are equal.
  @retval FALSE  The GUIDs differ.
**/
STATIC
BOOLEAN
CompareGuid (
  IN CONST EFI_GUID *Guid1,
  IN CONST EFI_GUID *Guid2
  )
{
  UINT64 *Ptr1;
  UINT64 *Ptr2;

  Ptr1 = (UINT64 *)Guid1;
  Ptr2 = (UINT64 *)Guid2;

  return (Ptr1[0] == Ptr2[0] && Ptr1[1] == Ptr2[1]);
}

// ---------------------------------------------------------------------------
// 7 -- HOB traversal helpers
// ---------------------------------------------------------------------------

/**
  Returns the first HOB of type EFI_HOB_TYPE_GUID_EXT.

  @param[in] Guid  Pointer to the GUID to match.

  @return Pointer to the HOB if found, NULL otherwise.
**/
STATIC
VOID *
GetFirstGuidHob (
  IN EFI_GUID *Guid
  )
{
  EFI_PEI_HOB_POINTERS Hob;

  if (mHobList == NULL) {
    return NULL;
  }

  Hob.Raw = mHobList;
  while (Hob.Header->HobType != EFI_HOB_TYPE_END_OF_HOB_LIST) {
    if (Hob.Header->HobType == EFI_HOB_TYPE_GUID_EXT) {
      if (CompareGuid (Guid, (EFI_GUID *)(Hob.Raw + 8))) {
        return Hob.Raw;
      }
    }
    Hob.Raw = (UINT8 *)Hob.Raw + Hob.Header->HobLength;
  }
  return NULL;
}

// ---------------------------------------------------------------------------
// 8 -- Debug library: DebugPrint / DebugAssert wrappers
// ---------------------------------------------------------------------------

/**
  Internal debug print wrapper.  Writes to the debug console.

  @param[in] ErrorLevel  Debug error level.
  @param[in] Format      Print format string.
  @param[in] ...         Variable arguments.

  @return The status from the underlying debug protocol, or 0 if not available.
**/
UINT8
DebugPrint (
  IN UINTN        ErrorLevel,
  IN CONST CHAR8  *Format,
  ...
  )
{
  VA_LIST         Marker;
  EFI_DEBUG_PROTOCOL *DebugProtocol;

  DebugProtocol = (EFI_DEBUG_PROTOCOL *)gDebugProtocol;

  if (DebugProtocol == NULL) {
    return 0;
  }

  //
  // Check whether this error level should be displayed and whether
  // the debug protocol supports it.
  //
  if (DebugProtocol->IsValid (ErrorLevel)) {
    VA_START (Marker, Format);
    DebugProtocol->Write (ErrorLevel, Format, Marker);
    VA_END (Marker);
  }

  return 0;
}

// ---------------------------------------------------------------------------
// 9 -- PCI Express MMIO access
// ---------------------------------------------------------------------------

/**
  Translates a PCI Express address (in the ECAM range) to the MMIO base
  and reads/writes via the PCI Express memory-mapped configuration space.

  Address format: [31:28] unused | [27:20] Bus | [19:15] Device | [14:12] Func | [11:0] Register

  @param[in] Address  PCI Express address (up to 28 bits valid).

  @return The MMIO virtual address of the config register.
**/
STATIC
UINT8 *
PciExpressGetAddr (
  IN UINTN  Address
  )
{
  ASSERT ((Address & ~0xFFFFFFF) == 0);
  return (UINT8 *)(gPciExpressBaseAddress + Address);
}

/**
  Gets PCD value (UINT64).

  @param[in] TokenNumber  PCD token number.

  @return The PCD value.
**/
UINT64
PcdGet64 (
  IN UINTN TokenNumber
  )
{
  UINT64 Value;

  if (mPcd == NULL) {
    return 0;
  }

  //
  // mPcd->Get64 (TokenNumber)
  //
  Value = ((PCD_PROTOCOL *)mPcd)->Get64 (TokenNumber);
  return Value;
}

// ---------------------------------------------------------------------------
// 10 -- USRA (Universal Segment Resource Access) wrappers
// ---------------------------------------------------------------------------

/**
  Reads 32-bit via USRA MMIO operation.

  Builds a USRA descriptor with operation type 512 (MMIO read)
  and calls mUsra->Read().

  @param[in] Socket    Socket index.
  @param[in] Bus       Bus number.
  @param[in] DevFunc   Device and function (encoded).
  @param[in] Offset    Register offset.

  @return The 32-bit value read.
**/
UINT32
UsraReadMmio (
  IN UINT8   Socket,
  IN UINT8   Bus,
  IN UINT8   DevFunc,
  IN UINT16  Offset
  )
{
  USRA_DESCRIPTOR Descriptor;
  UINT32          Value;

  Descriptor.OpCode    = 0;
  Descriptor.Socket    = Socket;
  Descriptor.OpType    = USRA_OP_READ_MMIO;  // 512
  Descriptor.Address   = (Offset & 0xFFF) |
                         ((Socket & 7) |
                          (8 * (DevFunc & 0x1F | (32 * Bus)))) << 12;

  ((USRA_PROTOCOL *)mUsra)->Read (&Descriptor, &Value);
  return Value;
}

/**
  Writes 32-bit via USRA MMIO operation.

  Builds a USRA descriptor with operation type 8704 (MMIO write)
  and calls mUsra->Write().

  @param[in] Socket    Socket index.
  @param[in] Bus       Bus number.
  @param[in] DevFunc   Device and function (encoded).
  @param[in] Offset    Register offset.
  @param[in] Value     Value to write.
**/
VOID
UsraWriteMmio (
  IN UINT8   Socket,
  IN UINT8   Bus,
  IN UINT8   DevFunc,
  IN UINT16  Offset,
  IN UINT32  Value
  )
{
  USRA_DESCRIPTOR Descriptor;

  Descriptor.OpCode    = 0;
  Descriptor.Socket    = Socket;
  Descriptor.OpType    = USRA_OP_WRITE_MMIO;  // 8704
  Descriptor.Address   = (Offset & 0xFFF) |
                         ((Socket & 7) |
                          (8 * (DevFunc & 0x1F | (32 * Bus)))) << 12;

  ((USRA_PROTOCOL *)mUsra)->Write (&Descriptor, &Value);
}

/**
  Reads 32-bit via USRA PCI config operation.

  Builds a USRA descriptor with operation type 0x2000 (PCI config read)
  and calls mUsra->Read().

  @param[in] Socket    Socket index.
  @param[in] Bus       Bus number.
  @param[in] DevFunc   Device and function (encoded).
  @param[in] Offset    Register offset.

  @return The 32-bit value read.
**/
UINT32
UsraReadPciCfg (
  IN UINT8   Socket,
  IN UINT8   Bus,
  IN UINT8   DevFunc,
  IN UINT16  Offset
  )
{
  USRA_DESCRIPTOR Descriptor;
  UINT32          Value;

  Descriptor.OpCode    = 0;
  Descriptor.Socket    = Socket;
  Descriptor.OpType    = USRA_OP_READ_PCI;  // 0x2000
  Descriptor.Address   = (Offset & 0xFFF) |
                         ((DevFunc & 0x1F | (32 * Bus)) << 15);

  ((USRA_PROTOCOL *)mUsra)->Read (&Descriptor, &Value);
  return Value;
}

/**
  Reads byte via USRA PCI config operation (non-aligned access).

  Builds a USRA descriptor with operation type 0 (PCI config read, no alignment)
  and calls mUsra->Read().

  @param[in] Socket      Socket index.
  @param[in] Bus         Bus number.
  @param[in] RegAddress  Full register address (bus, device, function, offset).

  @return The 8-bit value read.
**/
UINT8
UsraReadPciCfgByte (
  IN UINT8   Socket,
  IN UINT8   Bus,
  IN UINT32  RegAddress
  )
{
  USRA_DESCRIPTOR Descriptor;
  UINT8           Value;

  Descriptor.OpCode    = 0;
  Descriptor.Socket    = Socket;
  Descriptor.OpType    = 0;  // PCI byte read
  Descriptor.Address   = (RegAddress & 0xFFF) | (Bus << 20);

  ((USRA_PROTOCOL *)mUsra)->Read (&Descriptor, &Value);
  return Value;
}

// ---------------------------------------------------------------------------
// 11 -- SMM LockBox protocol locate
// ---------------------------------------------------------------------------

/**
  Locates the SMM Communication protocol for LockBox operations.

  @return Pointer to SMM Communication protocol, or NULL if not found.
**/
STATIC
SMM_COMMUNICATION_PROTOCOL *
GetSmmCommunication (
  VOID
  )
{
  EFI_STATUS Status;

  if (mSmmCommunication == NULL) {
    Status = gBS->LocateProtocol (
                    &gEfiSmmCommunicationProtocolGuid,
                    NULL,
                    &mSmmCommunication
                    );
    if (EFI_ERROR (Status)) {
      mSmmCommunication = NULL;
    }
  }

  return (SMM_COMMUNICATION_PROTOCOL *)mSmmCommunication;
}

/**
  Locates the SMM Communication Region Table for LockBox buffer sharing.

  @return Virtual address of the SMM communication buffer, or NULL.
**/
STATIC
VOID *
GetSmmCommRegion (
  VOID
  )
{
  EFI_STATUS                   Status;
  EFI_SMM_COMMUNICATION_REGION_TABLE *RegionTable;
  UINT32                       Index;
  UINT32                       NumberOfEntries;
  UINT8                        *Entry;

  if (mSmmCommRegion != NULL) {
    return mSmmCommRegion;
  }

  Status = EfiGetSystemConfigurationTable (
             &gEfiSmmCommunicationRegionTableGuid,
             (VOID **)&RegionTable
             );
  if (EFI_ERROR (Status)) {
    return NULL;
  }

  ASSERT (RegionTable != NULL);

  NumberOfEntries = RegionTable->NumberOfEntries;
  Entry           = (UINT8 *)&RegionTable->Descriptor[0];

  for (Index = 0; Index < NumberOfEntries; Index++) {
    if (RegionTable->Descriptor[Index].Type == SMM_COMM_REGION_TYPE_STANDARD &&
        (RegionTable->Descriptor[Index].PhysicalStart << 12) >= 0x50) {
      mSmmCommRegion = (VOID *)(UINTN)RegionTable->Descriptor[Index].CpuStart;
      break;
    }
    Entry += RegionTable->Descriptor[Index].DescriptorSize;
  }

  return mSmmCommRegion;
}

// ---------------------------------------------------------------------------
// 12 -- SMM LockBox: SaveLockBox
// ---------------------------------------------------------------------------

/**
  Saves a buffer to the SMM LockBox.

  This function communicates with SMM via the SMM Communication protocol
  to store a buffer identified by a GUID for later restoration (e.g., S3 resume).

  @param[in] Guid    GUID identifying the LockBox entry.
  @param[in] Buffer  Pointer to the data to save.
  @param[in] Length  Length of the data in bytes.

  @retval EFI_SUCCESS           The LockBox save succeeded.
  @retval EFI_INVALID_PARAMETER Guid, Buffer, or Length is NULL.
  @retval EFI_UNSUPPORTED       SMM Communication protocol not available.
  @retval other                 Error from SMM communication.
**/
EFI_STATUS
SaveLockBox (
  IN GUID   *Guid,
  IN VOID   *Buffer,
  IN UINTN  Length
  )
{
  SMM_COMMUNICATION_PROTOCOL  *SmmComm;
  VOID                        *CommBuffer;
  LOCK_BOX_COMMAND            *Command;
  EFI_STATUS                  Status;
  UINTN                       CommSize;

  DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib SaveLockBox - Enter\n"));

  if (Guid == NULL || Buffer == NULL || Length == 0) {
    return EFI_INVALID_PARAMETER;
  }

  SmmComm = GetSmmCommunication ();
  if (SmmComm == NULL) {
    return EFI_UNSUPPORTED;
  }

  CommBuffer = GetSmmCommRegion ();
  if (CommBuffer == NULL) {
    CommBuffer = &mSmmCommStackBuffer;  // fallback to stack buffer
  }

  //
  // Initialize the LockBox command structure
  //
  InternalCopyMem (CommBuffer, &gLockBoxGuid1, 16);
  ((LOCK_BOX_COMMAND *)CommBuffer)->HeaderSize   = 48;
  ((LOCK_BOX_COMMAND *)CommBuffer)->ReturnStatus = (UINT64)-1;
  ((LOCK_BOX_COMMAND *)CommBuffer)->Command      = LOCK_BOX_SAVE;
  ((LOCK_BOX_COMMAND *)CommBuffer)->DataSize     = 48;

  InternalCopyMem ((UINT8 *)CommBuffer + 40, Guid, 16);
  ((LOCK_BOX_COMMAND *)CommBuffer)->Buffer       = Buffer;
  ((LOCK_BOX_COMMAND *)CommBuffer)->Length        = Length;

  CommSize = 72;
  Status = SmmComm->Communicate (SmmComm, CommBuffer, &CommSize);
  ASSERT_EFI_ERROR (Status);

  DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib SaveLockBox - Exit (%r)\n",
          ((LOCK_BOX_COMMAND *)CommBuffer)->ReturnStatus));

  return ((LOCK_BOX_COMMAND *)CommBuffer)->ReturnStatus;
}

// ---------------------------------------------------------------------------
// 13 -- SMM LockBox: SetLockBoxAttributes
// ---------------------------------------------------------------------------

/**
  Sets attributes on an existing LockBox entry.

  @param[in] Guid        GUID of the LockBox entry.
  @param[in] Attributes  64-bit attribute flags to set.

  @retval EFI_SUCCESS           Attributes set successfully.
  @retval EFI_INVALID_PARAMETER Guid is NULL.
  @retval EFI_UNSUPPORTED       SMM Communication protocol not available.
  @retval other                 Error from SMM communication.
**/
EFI_STATUS
SetLockBoxAttributes (
  IN GUID   *Guid,
  IN UINT64 Attributes
  )
{
  SMM_COMMUNICATION_PROTOCOL  *SmmComm;
  VOID                        *CommBuffer;
  LOCK_BOX_COMMAND            *Command;
  EFI_STATUS                  Status;
  UINTN                       CommSize;

  DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib SetLockBoxAttributes - Enter\n"));

  if (Guid == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  SmmComm = GetSmmCommunication ();
  if (SmmComm == NULL) {
    return EFI_UNSUPPORTED;
  }

  CommBuffer = GetSmmCommRegion ();
  if (CommBuffer == NULL) {
    CommBuffer = &mSmmCommStackBuffer;
  }

  InternalCopyMem (CommBuffer, &gLockBoxGuid1, 16);
  ((LOCK_BOX_COMMAND *)CommBuffer)->HeaderSize   = 40;
  ((LOCK_BOX_COMMAND *)CommBuffer)->ReturnStatus = (UINT64)-1;
  ((LOCK_BOX_COMMAND *)CommBuffer)->Command      = LOCK_BOX_SET_ATTR;
  ((LOCK_BOX_COMMAND *)CommBuffer)->DataSize     = 40;

  InternalCopyMem ((UINT8 *)CommBuffer + 40, Guid, 16);
  ((LOCK_BOX_COMMAND *)CommBuffer)->Attributes   = 1;

  CommSize = 64;
  Status   = SmmComm->Communicate (SmmComm, CommBuffer, &CommSize);
  ASSERT_EFI_ERROR (Status);

  DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib SetLockBoxAttributes - Exit (%r)\n",
          ((LOCK_BOX_COMMAND *)CommBuffer)->ReturnStatus));

  return ((LOCK_BOX_COMMAND *)CommBuffer)->ReturnStatus;
}

// ---------------------------------------------------------------------------
// 14 -- SMM LockBox: RestoreLockBox
// ---------------------------------------------------------------------------

/**
  Restores a buffer from the SMM LockBox.

  @param[in]      Guid    GUID of the LockBox entry.
  @param[out]     Buffer  Pointer to the buffer receiving the data (optional).
  @param[in,out]  Length  On input, size of Buffer. On output, actual restored size.

  @retval EFI_SUCCESS           LockBox restored successfully.
  @retval EFI_UNSUPPORTED       SMM Communication protocol not available.
  @retval other                 Error from SMM communication.
**/
EFI_STATUS
RestoreLockBox (
  IN GUID       *Guid,
  OUT VOID      *Buffer   OPTIONAL,
  IN OUT UINTN  *Length   OPTIONAL
  )
{
  SMM_COMMUNICATION_PROTOCOL  *SmmComm;
  VOID                        *CommBuffer;
  LOCK_BOX_COMMAND            *Command;
  EFI_STATUS                  Status;
  UINTN                       CommSize;

  DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib RestoreLockBox - Enter\n"));

  SmmComm = GetSmmCommunication ();
  if (SmmComm == NULL) {
    return EFI_UNSUPPORTED;
  }

  CommBuffer = GetSmmCommRegion ();
  if (CommBuffer == NULL) {
    CommBuffer = &mSmmCommStackBuffer;
  }

  InternalCopyMem (CommBuffer, &gLockBoxGuid1, 16);
  ((LOCK_BOX_COMMAND *)CommBuffer)->HeaderSize   = 48;
  ((LOCK_BOX_COMMAND *)CommBuffer)->ReturnStatus = (UINT64)-1;
  ((LOCK_BOX_COMMAND *)CommBuffer)->Command      = LOCK_BOX_RESTORE;
  ((LOCK_BOX_COMMAND *)CommBuffer)->DataSize     = 48;

  InternalCopyMem ((UINT8 *)CommBuffer + 40, &gLockBoxGuid3, 16);
  ((LOCK_BOX_COMMAND *)CommBuffer)->Buffer       = NULL;
  ((LOCK_BOX_COMMAND *)CommBuffer)->Length       = 0;

  CommSize = 72;
  Status   = SmmComm->Communicate (SmmComm, CommBuffer, &CommSize);
  ASSERT_EFI_ERROR (Status);

  DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib RestoreLockBox - Exit (%r)\n",
          ((LOCK_BOX_COMMAND *)CommBuffer)->ReturnStatus));

  return ((LOCK_BOX_COMMAND *)CommBuffer)->ReturnStatus;
}

// ---------------------------------------------------------------------------
// 15 -- Boot script save event notification
// ---------------------------------------------------------------------------

/**
  Notification callback for the SMM Ready-To-Lock event.
  Saves the boot script context to the LockBox.

  @param[in] Event    Event that triggered this notification.
  @param[in] Context  Event-specific context (unused).
**/
STATIC
VOID
EFIAPI
S3BootScriptEventNotify (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  EFI_STATUS Status;

  Status = SaveLockBox (
             (GUID *)&gLockBoxGuid2,
             gS3BootScriptBuf,
             *(UINT32 *)(gS3BootScriptBuf + 16)
             );
  ASSERT_EFI_ERROR (Status);

  gS3BootScriptBuf[15] = 1;  // mark saved
  SetLockBoxAttributes ((GUID *)&gLockBoxGuid2, 0);

  gS3BootScriptBuf[21] = 0;  // clear lock
}

// ---------------------------------------------------------------------------
// 16 -- Boot script backup notification
// ---------------------------------------------------------------------------

/**
  Notification callback for boot script backup. Copies primary script
  data to a backup buffer and sets the backup flag.

  @param[in] Event    Event that triggered this notification.
  @param[in] Context  Event-specific context (unused).
**/
STATIC
VOID
EFIAPI
S3BootScriptBackupNotify (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  if (gS3BootScriptBuf != NULL && gS3BootScriptBuf[15] == 0) {
    //
    // Calculate new length and save the boot script to LockBox
    //
    *(UINT32 *)(gS3BootScriptBuf + 16) = *(UINT32 *)(gS3BootScriptBuf + 8) + 3;
    SaveLockBox (
      (GUID *)&gLockBoxGuid2,
      gS3BootScriptBuf,
      *(UINT32 *)(gS3BootScriptBuf + 16)
      );
    ASSERT_EFI_ERROR (Status);

    gS3BootScriptBuf[15] = 1;
    SetLockBoxAttributes ((GUID *)&gLockBoxGuid2, 0);
    gS3BootScriptBuf[21] = 0;
  }

  //
  // Backup: copy the primary script buffer to the backup location
  //
  if (gS3BootScriptBackup != NULL) {
    if (*(UINT64 *)gS3BootScriptBackup == 0) {
      InternalCopyMem (
        gS3BootScriptBackup,
        gS3BootScriptBuf,
        32
        );
      gS3BootScriptBackup[14] = 1;
    }
    gS3BootScriptBuf = gS3BootScriptBackup;
  }
}

// ---------------------------------------------------------------------------
// 17 -- Boot script context sync (S3 Ready-To-Lock notification event)
// ---------------------------------------------------------------------------

/**
  Called when the SMM Ready-To-Lock protocol is installed.
  Synchronizes the boot script context between primary and backup buffers
  and registers save events.

  @param[in] Event    Event that triggered this notification.
  @param[in] Context  Event-specific context (unused).
**/
STATIC
VOID
EFIAPI
S3BootScriptSyncNotify (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  //
  // If primary and backup are different, copy primary -> backup
  //
  if (gS3BootScriptBuf != gS3BootScriptBackup) {
    S3BootScriptEventNotify (Event, Context);
    if (gS3BootScriptBackup != NULL) {
      if (*(UINT64 *)gS3BootScriptBackup == 0) {
        InternalCopyMem (gS3BootScriptBackup, gS3BootScriptBuf, 32);
        gS3BootScriptBackup[14] = 1;
      }
      gS3BootScriptBuf = gS3BootScriptBackup;
    }
  }

  return 0;
}

// ---------------------------------------------------------------------------
// 18 -- S3 Boot Script Library init
// ---------------------------------------------------------------------------

/**
  Initializes the S3 Boot Script library: allocates a boot script buffer,
  registers notification events for SMM Ready-To-Lock and related protocols.

  @retval EFI_SUCCESS  Boot script library initialized.
**/
EFI_STATUS
S3BootScriptLibInit (
  VOID
  )
{
  UINT64      PcdS3BootScriptBufferSize;
  EFI_STATUS  Status;
  UINT64      BufferSize;
  EFI_EVENT   Event;

  PcdS3BootScriptBufferSize = PcdGet64 (PcdS3BootScriptBufferSizeToken); // 137

  if (PcdS3BootScriptBufferSize == 0) {
    //
    // Allocate boot script table from boot services data
    //
    Status = gBS->AllocatePool (
                    EfiBootServicesData,
                    sizeof (UINT64),
                    (VOID **)&BufferSize
                    );
    ASSERT_EFI_ERROR (Status);

    gS3BootScriptBuf         = (UINT8 *)(UINTN)BufferSize;
    gBootScriptFlag1         = 1;

    PcdGet64 (PcdS3BootScriptBufferSize) = BufferSize; // PcdSet64S

    //
    // Zero-initialize the buffer to size 32
    //
    InternalZeroMem (gS3BootScriptBuf, 32);

    //
    // Register event notification for when SMM Ready-To-Lock protocol appears
    //
    mEventDxeSmmReadyToLock = EfiCreateEventReadyToBoot (
                               TPL_CALLBACK,
                               S3BootScriptEventNotify,
                               NULL
                               );
    ASSERT (mEventDxeSmmReadyToLock != NULL);
  }

  gS3BootScriptBuf[20] = (UINT8)(UINTN)gS3BootScriptBuf;  // store low byte as flag

  //
  // Locate SMM Ready-To-Lock protocol and register additional notifications
  //
  if (!EFI_ERROR (gBS->LocateProtocol (
                         &gEfiSmmReadyToLockProtocolGuid,
                         NULL,
                         &gEfiSmmReadyToLockProtocol
                         ))) {
    Status = gBS->LocateProtocol (
                    &gEfiSmmReadyToLock2ProtocolGuid,
                    NULL,
                    &gEfiSmmReadyToLockProtocol2
                    );
    ASSERT_EFI_ERROR (Status);
    if (Status == EFI_SUCCESS) {
      //
      // Get S3 boot script backup buffer
      //
      BufferSize = PcdGet64 (PcdS3BootScriptBufferSizeToken); // 138
      if (BufferSize == 0) {
        Status = gEfiSmmReadyToLockProtocol2->GetBufferSize (
                                                gEfiSmmReadyToLockProtocol2,
                                                6,
                                                &BufferSize
                                                );
        ASSERT_EFI_ERROR (Status);

        gBootScriptFlag2   = 1;
        PcdGet64 (PcdS3BootScriptBufferSizeToken) = BufferSize; // PcdSet64S

        //
        // Register event for the backup save
        //
        InternalZeroMem (gS3BootScriptBackup, 32);
        Status = gEfiSmmReadyToLockProtocol2->RegisterNotification (
                                                gEfiSmmReadyToLockProtocol2,
                                                S3BootScriptBackupNotify,
                                                &gSmmReadyToLockEvent1
                                                );
        ASSERT_EFI_ERROR (Status);

        Status = gEfiSmmReadyToLockProtocol2->RegisterNotification (
                                                gEfiSmmReadyToLockProtocol2,
                                                S3BootScriptBackupNotify,
                                                &gSmmReadyToLockEvent2
                                                );
        ASSERT_EFI_ERROR (Status);
      }
    }

    //
    // Register sync notification for the final protocol
    //
    Status = gEfiSmmReadyToLockProtocol2->RegisterNotification (
                                            gEfiSmmReadyToLockProtocol2,
                                            S3BootScriptSyncNotify,
                                            &gSmmReadyToLockEvent3
                                            );
    ASSERT_EFI_ERROR (Status);
  }

  return EFI_SUCCESS;
}

// ---------------------------------------------------------------------------
// 19 -- FPGA Configuration HOB retrieval / creation
// ---------------------------------------------------------------------------

/**
  Retrieves the FPGA Configuration HOB. If not found, creates a new HOB
  and initializes it from the "FpgaSocketConfig" UEFI variable.

  The HOB contains:
    - Byte 0:       Valid flag
    - Bytes 1-5:    Socket presence mask and config
    - Byte 15:      Per-socket configuration block
    - Bytes 23-32:  Temperature threshold data
    - Byte 37:      DXE unlock flag

  @param[out] FpgaConfigHob  Pointer to receive the HOB data pointer.

  @retval EFI_SUCCESS            HOB found or created successfully.
  @retval EFI_NOT_FOUND          HOB not found and could not be created.
**/
EFI_STATUS
FpgaConfigurationGetValues (
  OUT VOID **FpgaConfigHob
  )
{
  EFI_STATUS            Status;
  EFI_PEI_HOB_POINTERS  Hob;
  FPGA_CONFIG_HOB       *FpgaHob;
  UINTN                 VariableSize;
  UINT8                 *VariableData;
  UINT8                 *Src;
  UINT8                 *Dst;
  UINTN                 Index;

  //
  // Search for the FPGA configuration HOB by its GUID
  //
  FpgaHob = (FPGA_CONFIG_HOB *)GetFirstGuidHob (&gFpgaConfigHobGuid);
  if (FpgaHob != NULL) {
    *FpgaConfigHob = (VOID *)((UINT8 *)FpgaHob + 24);
    return EFI_SUCCESS;
  }

  //
  // HOB not found -- create it
  //
  DEBUG ((DEBUG_ERROR, "FPGA Configuration Get HOB-> HOB is not found, create it!\n"));

  FpgaHob = (FPGA_CONFIG_HOB *)BuildGuidHob (
                                  &gFpgaConfigHobGuid,
                                  sizeof (FPGA_CONFIG_HOB)
                                  );
  if (FpgaHob == NULL) {
    goto HOB_FAILED;
  }

  InternalZeroMem (FpgaHob, sizeof (FPGA_CONFIG_HOB));
  FpgaHob->Valid          = 1;
  FpgaHob->SegGroup       = 0;       // defaults: bus range unassigned
  FpgaHob->BusLimit       = 0xFF00;  // secondary=0xFF, subordinate=0x00
  FpgaHob->SocketMask     = 0;
  FpgaHob->MaxBus         = 0;
  FpgaHob->MinBus         = 0;

  //
  // Initialize per-socket entries (at offset 15)
  //
  Dst = (UINT8 *)&FpgaHob->Socket[0];
  for (Index = 0; Index < 4; Index++) {
    Dst[0] = 0xFF;   // bus start
    Dst[1] = 11;     // device
    Dst[2] = 0xFF;   // max bus
    Dst[3] = 0xFF;   // subordinate
    Dst[4] = 0;      // reserved
    Dst[5] = 0;      // reserved
    Dst[6] = 0;      // temp threshold N0
    Dst[7] = 0;      // temp threshold N1
    Dst += 8;
  }

  //
  // Try to restore from UEFI variable "FpgaSocketConfig"
  //
  VariableSize = 27;
  VariableData = (UINT8 *)AllocatePool (VariableSize);
  if (VariableData == NULL) {
    goto HOB_FAILED;
  }

  InternalZeroMem (VariableData, VariableSize);

  Status = gRT->GetVariable (
                  L"FpgaSocketConfig",
                  &gFpgaVariableGuid,
                  NULL,
                  &VariableSize,
                  VariableData
                  );
  if (!EFI_ERROR (Status) && VariableData != NULL) {
    DEBUG ((DEBUG_ERROR, "FPGA Configuration Get HOB-> Vaiable found use it!\n"));

    FpgaHob->Socket[0].ConfigReg6 = VariableData[0];
    FpgaHob->MaxBus               = VariableData[13];
    FpgaHob->MinBus               = VariableData[14];
    FpgaHob->DxeUnlock            = VariableData[19];

    //
    // Copy per-socket data (indices 0..4)
    //
    Src = VariableData;
    Dst = (UINT8 *)&FpgaHob->Socket[0];
    for (Index = 0; Index < 4; Index++) {
      Dst[0] = Src[7];   // bus
      Dst[4] = Src[11];  // gap
      Dst[5] = Src[3];   // temp N0
      if (Dst[5] != 0) {
        if (Dst[5] == 0xFF) {
          Dst[5] = 0xFF;
        } else {
          Dst[5] = Dst[5] - 1;
        }
      }
      Dst[6] = Src[8];   // temp N1
      Dst += 7;
      Src += 1;
    }

    FreePool (VariableData);
  }

  FpgaHob->Valid = 1;
  *FpgaConfigHob = (VOID *)((UINT8 *)FpgaHob + 24);
  return EFI_SUCCESS;

HOB_FAILED:
  DEBUG ((DEBUG_ERROR, "FPGA Configuration Get HOB-> HOB IS NULL, could not create!\n"));
  return EFI_NOT_FOUND;
}

// ---------------------------------------------------------------------------
// 20 -- FpgaDxe entry point
// ---------------------------------------------------------------------------

/**
  Main FPGA initialization entry point.

  Initializes all library services, locates protocols, reads the FPGA
  configuration HOB, programs per-socket FPGA active state into ACPI
  NVS (GlobalNvsArea), registers a ReadyToBoot notification event for
  final FPGA device configuration, and initializes S3 boot script support.

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

  @retval EFI_SUCCESS           Initialization completed successfully.
  @retval EFI_NOT_FOUND         FPGA configuration not available.
  @retval EFI_INVALID_PARAMETER Invalid parameters.
**/
EFI_STATUS
EFIAPI
FpgaDxeEntryPoint (
  IN EFI_HANDLE       ImageHandle,
  IN EFI_SYSTEM_TABLE *SystemTable
  )
{
  EFI_STATUS            Status;
  FPGA_CONFIG_HOB_ENTRY *FpgaHob;
  UINTN                 PcdData;
  UINT8                 SocketIndex;
  UINT8                 *GlobalNvsPtr;
  UINT8                 IoData;
  UINTN                 TimerValue;
  UINTN                 *FpgaProtocol;
  BOOLEAN               FpgaActive;

  //
  // Step 1: Initialize library service globals
  //
  InitializeLibServices (ImageHandle, SystemTable);

  //
  // Step 2: Get DXE Services Table
  //
  Status = GetDxeServicesTable ();
  ASSERT_EFI_ERROR (Status);

  //
  // Step 3: Get PCD protocol
  //
  Status = GetPcdProtocol ();
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "FpgaDxe: PCD protocol error %r\n", Status));
    goto EXIT;
  }

  //
  // Step 4: Get MM PCI base protocol (for ECAM access)
  //
  Status = GetMmPciBaseProtocol ();
  ASSERT_EFI_ERROR (Status);

  //
  // Step 5: Get HOB list
  //
  Status = GetHobList ();
  ASSERT_EFI_ERROR (Status);

  //
  // Step 6: Get PCI Express base address from PCD
  //
  gPciExpressBaseAddress = PcdGet64 (PcdPciExpressBaseAddress); // Token 5

  //
  // Step 7: Enable PCI Express MMIO access via PCD bit
  //
  PcdData = PcdGet64 (PcdPciExpressEnable); // Token 4
  if ((INT8)PcdData >= 0) {
    IoData = *(UINT8 *)PciExpressGetAddr (PcdPciExpressEnable); // PcdGet8 wrapper
    IoData |= 0x80;
    *(UINT8 *)PciExpressGetAddr (PcdPciExpressEnable) = IoData;
  }

  //
  // Step 8: Read CMOS diagnostic status
  //
  TimerValue = IoRead32 (0x508);  // CMOS port 0x508
  FpgaActive = (TimerValue & 0x200) != 0;

  //
  // Step 9: Short delay to stabilize FPGA
  //
  TimerValue = IoRead32 (0x508) & 0xFFFFFF;
  while (((TimerValue + 0x165 - IoRead32 (0x508)) & 0x800000) == 0) {
    CpuPause ();
  }

  //
  // Restore CMOS access
  //
  if (FpgaActive) {
    IoWrite8 (0xCF9, 0x08);  // reset request
  } else {
    // No special action needed
  }

  //
  // Step 10: Initialize S3 Boot Script Library
  //
  Status = S3BootScriptLibInit ();
  ASSERT_EFI_ERROR (Status);

  //
  // Step 11: Locate USRA protocol
  //
  Status = gBS->LocateProtocol (
                  &gEfiUsraProtocolGuid,
                  NULL,
                  &mUsra
                  );
  ASSERT_EFI_ERROR (Status);
  ASSERT (mUsra != NULL);

  //
  // Step 12: Get FPGA configuration from HOB
  //
  Status = FpgaConfigurationGetValues (&FpgaHob);
  if (EFI_ERROR (Status)) {
    DEBUG ((
      DEBUG_ERROR,
      "FpgaConfigurationGetValues-> HOB error, return EFI_NOT_FOUND!\n"
      ));
    ASSERT_EFI_ERROR (Status);
    return Status;
  }

  //
  // Extract configuration bytes from HOB
  //
  gFpgaConfigValid  = *(UINT8 *)((UINT8 *)FpgaHob + 0);
  gFpgaSktActive    = *(UINT8 *)((UINT8 *)FpgaHob + 3);
  gFpgaSktConfig5   = *(UINT8 *)((UINT8 *)FpgaHob + 5);
  gFpgaSktConfig6   = *(UINT8 *)((UINT8 *)FpgaHob + 6);
  gFpgaSktConfig31  = *(UINT8 *)((UINT8 *)FpgaHob + 31);
  gFpgaSktConfig32  = *(UINT8 *)((UINT8 *)FpgaHob + 32);
  gFpgaDxeUnlock    = *(UINT8 *)((UINT8 *)FpgaHob + 37);

  //
  // Copy per-socket data
  //
  InternalCopyMem (&gFpgaSktConfigBuf, (UINT8 *)FpgaHob + 7, 7);

  InternalCopyMem (&gFpgaSktTempThresh, (UINT8 *)FpgaHob + 27, 2);

  DEBUG ((DEBUG_INFO, "FpgaSktActive = 0x%X.\n", gFpgaSktActive));

  //
  // Step 13: If no FPGA is active, return successfully (nothing to do)
  //
  if (gFpgaSktActive == 0) {
    DEBUG ((DEBUG_INFO, "FpgaDxeEntryPoint() no FPGA activated.\n"));
    return EFI_SUCCESS;
  }

  //
  // Step 14: Locate GlobalNvsArea ACPI protocol and cache pointer
  //
  Status = gBS->LocateProtocol (
                  &gGlobalNvsAreaProtocolGuid,
                  NULL,
                  &FpgaProtocol
                  );
  ASSERT_EFI_ERROR (Status);
  gGlobalNvsArea = (UINT64)*FpgaProtocol;
  ASSERT (gGlobalNvsArea != NULL);

  //
  // Step 15: Program per-socket FPGA active state into NVS
  //
  for (SocketIndex = 0; SocketIndex < 4; SocketIndex++) {
    FpgaActive = ((1 << SocketIndex) & gFpgaSktActive) != 0;
    *(UINT8 *)((UINTN)gGlobalNvsArea + SocketIndex + 1016) = FpgaActive;
    DEBUG ((DEBUG_INFO, "Socket[%x] FPGA active state = %x\n", SocketIndex, FpgaActive));
  }

  //
  // Step 16: Locate protocol for OEM FPGA data
  //
  Status = gBS->LocateProtocol (
                  &gOemFpgaProtocolGuid,
                  NULL,
                  &gOemFpgaProtocol
                  );
  ASSERT_EFI_ERROR (Status);

  Status = gBS->LocateProtocol (
                  &gFpgaSkuProtocolGuid,
                  NULL,
                  &gFpgaSkuProtocol
                  );
  ASSERT_EFI_ERROR (Status);

  Status = gBS->LocateProtocol (
                  &gFpgaDeviceProtocolGuid,
                  NULL,
                  &gFpgaDeviceProtocol
                  );
  ASSERT_EFI_ERROR (Status);

  //
  // Step 17: Initialize SMBus for FPGA access
  //
  SMBUS_PROTOCOL_OP SMBusOp;
  SMBusOp.Command = 0x93;  // SMBus read byte
  SMBusOp.Address = 0;
  SMBusOp.Value   = 0xFF;
  ((SMBUS_PROTOCOL *)((UINTN)gGlobalNvsArea + 8588))->Execute (&SMBusOp);

  //
  // Step 18: Register ReadyToBoot notification callback
  //
  EfiCreateEventReadyToBoot (
    TPL_CALLBACK,
    FpgaOnReadyToBoot,
    NULL
    );
  DEBUG ((DEBUG_INFO, "Register Event to Update for FPGA device.\n"));

EXIT:
  return Status;
}

// ---------------------------------------------------------------------------
// 21 -- Module entry point (AutoGen)
// ---------------------------------------------------------------------------

/**
  Module entry point. Calls FpgaDxeEntryPoint and, if it fails, enters
  CpuDeadLoop after calling the debug library cleanup.

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

  @return Status code from FpgaDxeEntryPoint (or the ASSERT handler).
**/
EFI_STATUS
EFIAPI
ModuleEntryPoint (
  IN EFI_HANDLE       ImageHandle,
  IN EFI_SYSTEM_TABLE *SystemTable
  )
{
  EFI_STATUS Status;

  Status = FpgaDxeEntryPoint (ImageHandle, SystemTable);
  if (EFI_ERROR (Status)) {
    //
    // Call the driver unload / cleanup handler
    //
    ProcessLibraryDestructor (ImageHandle, SystemTable);
  }

  return Status;
}

// ---------------------------------------------------------------------------
// 22 -- FpgaOnReadyToBoot (ReadyToBoot notification)
// ---------------------------------------------------------------------------

/**
  ReadyToBoot notification callback. Enumerates all FPGA-connected sockets,
  programs PCI configuration space (bus numbers, FME BARs, temperature
  thresholds), configures HSSI and miscellaneous FPGA registers, applies
  DXE lock settings, and triggers a software SMI to finalize FPGA init
  in SMM.

  @param[in] Event    EFI event that triggered this callback.
  @param[in] Context  Event context (unused).
**/
VOID
EFIAPI
FpgaOnReadyToBoot (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  UINTN   SocketIndex;
  UINT8   SocketBit;
  UINT8   McpLimitBus;
  UINTN   FpgaGlobalData;
  UINT8   BusNum;
  UINT16  TempWord;
  UINT8   SecondaryBus;
  UINT8   SubordinateBus;
  UINT8   SegmentNum;
  UINTN   HandleCount;
  EFI_HANDLE *HandleBuffer;
  UINTN   Index;
  UINTN   Handle;
  EFI_PCI_IO_PROTOCOL *PciIo;
  UINTN   Segment;
  UINTN   Bus;
  UINTN   Device;
  UINTN   Func;
  VOID    *FpgaBar;
  UINT32  TmpThresholdN0;
  UINT32  TmpThresholdN1;
  UINT32  RegValue;

  DEBUG ((DEBUG_ERROR, "FpgaOnReadyToBoot()...\n"));

  //
  // Signal that we have entered ReadyToBoot
  //
  gBS->SignalEvent (Event);

  DEBUG ((DEBUG_INFO, "FpgaSktActive = 0x%X.\n", gFpgaSktActive));

  //
  // Initialize SMBus
  //
  ((SMBUS_PROTOCOL *)((UINTN)gGlobalNvsArea + 8588))->Command = 0x94;
  SMBusOp.Execute (0, 0xFF);

  //
  // Zero FME BAR array
  //
  InternalZeroMem (&gFmeBar, sizeof (gFmeBar));

  //
  // Process each active socket
  //
  SocketIndex = 0;
  for (SocketBit = 0; SocketBit < 4; SocketBit++) {
    SocketIndex = SocketBit;

    if ((gFpgaSktActive & (1 << SocketBit)) == 0) {
      continue;
    }

    //
    // Get MCP limit bus and socket bus number
    //
    McpLimitBus = *(UINT8 *)((UINTN)gGlobalNvsArea + SocketBit * 6 + 6904);
    BusNum      = *(UINT8 *)((UINTN)gGlobalNvsArea + SocketBit * 6 + 6856);

    DEBUG ((DEBUG_INFO, "MCP Limit BusNumber = %x\n", McpLimitBus));

    TempWord    = BusNum;

    //
    // Read current PCI secondary/subordinate buses
    //
    SecondaryBus   = UsraReadPciCfgByte (SocketBit, BusNum, 25);
    SubordinateBus = UsraReadPciCfgByte (SocketBit, BusNum, 26);

    //
    // Get segment number from protocol
    //
    SegmentNum = *(UINT8 *)((UINTN)gFpgaSkuProtocol + SocketBit * 43 + 31);

    DEBUG ((
      DEBUG_INFO,
      "FPGA Root Port SegmentNumber = %x, BusNumber = %x, Secondary = 0x%X, Subordinate = 0x%X\n",
      SegmentNum,
      BusNum,
      SecondaryBus,
      SubordinateBus
      ));

    //
    // Enumerate PCI devices to find the virtual FPGA bus
    //
    HandleBuffer = NULL;
    HandleCount  = 0;
    if (!EFI_ERROR (gBS->LocateHandleBuffer (
                           ByProtocol,
                           &gEfiPciIoProtocolGuid,
                           NULL,
                           &HandleCount,
                           &HandleBuffer
                           ))) {
      for (Index = 0; Index < HandleCount; Index++) {
        Handle = HandleBuffer[Index];
        if (!EFI_ERROR (gBS->OpenProtocol (
                               Handle,
                               &gEfiPciIoProtocolGuid,
                               (VOID **)&PciIo,
                               NULL,
                               NULL,
                               EFI_OPEN_PROTOCOL_GET_PROTOCOL
                               ))) {
          PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Func);
          if (Segment == SegmentNum && Bus == BusNum && Device == 0 && Func == 0) {
            break;
          }
          gBS->CloseProtocol (
                 Handle,
                 &gEfiPciIoProtocolGuid,
                 NULL,
                 NULL
                 );
        }
      }

      if (Index >= HandleCount) {
        DEBUG ((DEBUG_ERROR, "Cannot find virtual FPGA bus.\n"));
      } else {
        //
        // Program subordinate bus limit
        //
        DEBUG ((DEBUG_INFO, "Update Device on B%x:D%x:F%x\n", Bus, Device, Func));

        //
        // Program the FPGA device behind this root port
        //
        FpgaPcieDeviceConfig (PciIo, SocketBit);

        //
        // Write secondary/subordinate limits via USRA
        //
        UsraWriteMmio (SocketBit, BusNum, 0, 25, McpLimitBus - 1);
        UsraWriteMmio (SocketBit, BusNum, 0, 26, McpLimitBus - 1);

        //
        // Read FME BAR
        //
        RegValue  = UsraReadMmio (SocketBit, (UINT8)(McpLimitBus - 1), 0, 16);
        FpgaBar   = (VOID *)(UINTN)(RegValue & 0xFFFFFFF0);
        gFmeBar[SocketBit] = (UINT64)(UINTN)FpgaBar;

        DEBUG ((DEBUG_INFO, "FmeBar[%X] = %X\n", SocketBit, FpgaBar));

        //
        // Set primary bus
        //
        UsraWriteMmio (SocketBit, BusNum, 2, 25, McpLimitBus);
        UsraWriteMmio (SocketBit, BusNum, 2, 26, McpLimitBus);

        gBS->CloseProtocol (
               Handle,
               &gEfiPciIoProtocolGuid,
               NULL,
               NULL
               );
      }

      gBS->FreePool (HandleBuffer);
    }
  }

  //
  // Dump Blue BitStream version for active sockets
  //
  DEBUG ((DEBUG_INFO, "DumpBbsVersion () ...\n"));
  for (SocketIndex = 0; SocketIndex < 4; SocketIndex++) {
    if (gFpgaSktActive & (1 << SocketIndex)) {
      RegValue = *(UINT32 *)((UINTN)gFmeBar[SocketIndex] + 100);
      DEBUG ((
        DEBUG_INFO,
        "Socket[%X] Blue BitStream Version: %X.%X.%X.%X\n",
        SocketIndex,
        (RegValue >> 24) & 0xF,
        (RegValue >> 20) & 0xF,
        (RegValue >> 12) & 0xF,
        RegValue & 0xF
        ));
    }
  }

  //
  // Program temperature threshold registers
  //
  for (SocketIndex = 0; SocketIndex < 4; SocketIndex++) {
    if (gFpgaSktActive & (1 << SocketIndex)) {
      TmpThresholdN0 = *(UINT32 *)((UINTN)gFmeBar[SocketIndex] + 4104) & 0xFFFF0000;
      TmpThresholdN1 = *(UINT32 *)((UINTN)gFmeBar[SocketIndex] + 4108) & 0xFFFFEFFF;

      if ((UINT8)(gFpgaSktTempThresh[SocketIndex] - 1) <= 0xFD) {
        TmpThresholdN0 |= (gFpgaSktTempThresh[SocketIndex] & 0xFF) | 0x80;
        TmpThresholdN1 |= 0x1000;
      }

      if ((UINT8)(gFpgaSktTempThresh[SocketIndex] - 1) <= 0xFD) {
        TmpThresholdN0 |= ((gFpgaSktTempThresh[SocketIndex] | 0x80) << 8);
      }

      DEBUG ((
        DEBUG_INFO,
        "TmpThreshold_N0.Data = %X, TmpThreshold_N1.Data = %X\n",
        TmpThresholdN0,
        TmpThresholdN1
        ));

      *(UINT32 *)((UINTN)gFmeBar[SocketIndex] + 4104) = TmpThresholdN0;
      *(UINT32 *)((UINTN)gFmeBar[SocketIndex] + 4108) = TmpThresholdN1;
    }
  }

  //
  // MCP power limit configuration
  //
  if (FpgaMcpPowerLimitConfig () < 0) {
    DEBUG ((DEBUG_ERROR, "FPGA MCP power limit setting failed.\n"));
  }

  //
  // FPGA miscellaneous initialization
  //
  FpgaPcieEarlyConfig ();
  FpgaDxeInit ();

  //
  // PCIe device config
  //
  DEBUG ((DEBUG_INFO, "FpgaPcieDeviceConfig() ...\n"));
  for (SocketIndex = 0; SocketIndex < 4; SocketIndex++) {
    if (gFpgaSktActive & (1 << SocketIndex)) {
      RegValue              = *(UINT32 *)((UINTN)gFmeBar[SocketIndex] + 156);
      *(UINT32 *)((UINTN)gFmeBar[SocketIndex] + 152) |= 0x11;
      *(UINT32 *)((UINTN)gFmeBar[SocketIndex] + 156)  = RegValue;
    }
  }

  FpgaProgramHssiConfig ();
  DEBUG ((DEBUG_INFO, "FpgaMiscConfig () ...\n"));

  for (SocketIndex = 0; SocketIndex < 4; SocketIndex++) {
    if (gFpgaSktActive & (1 << SocketIndex)) {
      RegValue = *(UINT32 *)((UINTN)gFmeBar[SocketIndex] + 16396);
      *(UINT32 *)((UINTN)gFmeBar[SocketIndex] + 16392) &= ~0x40;
      *(UINT32 *)((UINTN)gFmeBar[SocketIndex] + 16396)  = RegValue;
      *(UINT32 *)((UINTN)gFmeBar[SocketIndex] + 16400)  = 64;
    }
  }

  //
  // DXE lock configuration (unless unlock flag is set)
  //
  if (gFpgaDxeUnlock == 1) {
    DEBUG ((DEBUG_INFO, "FPGA DXE unlock enabled, skip DXE lock config.\n"));
  } else {
    DEBUG ((DEBUG_INFO, "FpgaDxeLockConfig() ...\n"));
    for (SocketIndex = 0; SocketIndex < 4; SocketIndex++) {
      if (gFpgaSktActive & (1 << SocketIndex)) {
        RegValue = *(UINT32 *)((UINTN)gFmeBar[SocketIndex] + 132);
        *(UINT32 *)((UINTN)gFmeBar[SocketIndex] + 128) |= 3;
        *(UINT32 *)((UINTN)gFmeBar[SocketIndex] + 132)  = RegValue;
      }
    }
  }

  //
  // Finalize: SMBus command, trigger SMI
  //
  ((SMBUS_PROTOCOL *)((UINTN)gGlobalNvsArea + 8588))->Command = 0x95;
  SMBusOp.Execute (0, 0xFF);

  DEBUG ((DEBUG_INFO, "Trigger software SMI for FPGA.\n"));
  IoWrite8 (0xB2, (UINT8)PcdGet64 (PcdSoftwareSmiTrigger)); // Token 182

  DEBUG ((DEBUG_INFO, "FpgaOnReadyToBoot() End...\n"));
}

// ---------------------------------------------------------------------------
// 23 -- S3 boot script library destructor / cleanup
// ---------------------------------------------------------------------------

/**
  Library destructor called on module unload. Unregisters boot script
  events and closes SMM communication.

  If gS3BootScriptBuf was allocated, signals events, saves boot script
  data to the LockBox, and cleans up SMM protocol registrations.

  @retval EFI_SUCCESS  Cleanup succeeded.
  @retval other        Error during cleanup.
**/
EFI_STATUS
EFIAPI
ProcessLibraryDestructor (
  IN EFI_HANDLE       ImageHandle,
  IN EFI_SYSTEM_TABLE *SystemTable
  )
{
  EFI_STATUS Status;

  //
  // Close SMM Ready-To-Lock event notifications
  //
  if (gEfiSmmReadyToLockProtocol != NULL) {
    if (gSmmReadyToLockEvent1 != NULL) {
      Status = gEfiSmmReadyToLockProtocol->RegisterNotification (
                                            gEfiSmmReadyToLockProtocol,
                                            NULL,
                                            &gSmmReadyToLockEvent1
                                            );
    }
    if (gSmmReadyToLockEvent2 != NULL) {
      Status = gEfiSmmReadyToLockProtocol->RegisterNotification (
                                            gEfiSmmReadyToLockProtocol,
                                            NULL,
                                            &gSmmReadyToLockEvent2
                                            );
    }
  }

  if (gEfiSmmReadyToLockProtocol2 != NULL) {
    if (gSmmReadyToLockEvent3 != NULL) {
      Status = gEfiSmmReadyToLockProtocol2->RegisterNotification (
                                              gEfiSmmReadyToLockProtocol2,
                                              NULL,
                                              &gSmmReadyToLockEvent3
                                              );
    }
  }

  //
  // Close SMM communication protocol
  //
  if (mSmmCommunication != NULL) {
    gBS->CloseProtocol (
           mSmmCommunication,
           &gEfiSmmCommunicationProtocolGuid,
           NULL,
           NULL
           );
    mSmmCommunication = NULL;
  }

  return EFI_SUCCESS;
}