/** @file
  IIO Configuration Update DXE driver - Lightning Ridge EXRP platform variant.

  This DXE driver sends IIO (Integrated IO) configuration data tables to the
  UBA protocol for the Lightning Ridge EXRP platform. The configuration tables
  contain PCIe register AND/OR mask updates to be applied to IIO root ports
  across all sockets.

  The driver flow:
    1. Initialize UEFI service table pointers (ModuleEntryPoint).
    2. Locate the HOB list and find the IIO config HOB (HobLibInit).
    3. Locate the UBA_PROTOCOL.
    4. Call UBA protocol's SetIIOConfigData for each of 4 GUID-identified
       configuration blocks (socket config, misc config, PCIe config, extra).
    5. The UBA core applies these config updates during IIO initialization.

  Build path (from PDB):
    e:\hs\Build\HR6N0XMLK\DEBUG_VS2015\X64\PurelyRpPkg\Uba\UbaMain\Dxe\
    TypeLightningRidgeEXRP\IioCfgUpdateDxe\IioCfgUpdateDxe\DEBUG\
    IioCfgUpdateDxeLightningRidgeEXRP.pdb

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

#include "IioCfgUpdateDxeLightningRidgeEXRP.h"

//
// Global UEFI system table pointers (initialized by ModuleEntryPoint)
//
EFI_HANDLE               gImageHandle = NULL;       ///< 0x0D88 - EFI image handle
EFI_SYSTEM_TABLE         *gSystemTable = NULL;      ///< 0x0D78 - EFI system table
EFI_BOOT_SERVICES        *gBootServices = NULL;     ///< 0x0D80 - EFI boot services table
EFI_RUNTIME_SERVICES     *gRuntimeServices = NULL;  ///< 0x0D90 - EFI runtime services table

//
// Cached protocol/state pointers
//
VOID                     *mDebugProtocol = NULL;    ///< 0x0D98 - Cached DebugLib protocol pointer
VOID                     *mHobList = NULL;          ///< 0x0DA0 - Cached HOB list pointer
UINT8                    mPlatformSku;              ///< 0x0DA8 - Detected platform SKU type

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

///
/// UBA Protocol GUID
///
static EFI_GUID mUbaProtocolGuid = { 0xE03E0D46, 0x5263, 0x4845, { 0xB0, 0xA4, 0x58, 0xD5, 0x7B, 0x31, 0x77, 0xE2 } };

///
/// IIO configuration data block GUIDs
///
static EFI_GUID mIioCfgUpdateGuid1 = { 0x6FE6C559, 0x4F35, 0x4111, { 0x98, 0xE1, 0x33, 0x2A, 0x25, 0x15, 0x12, 0xF3 } };
static EFI_GUID mIioCfgUpdateGuid2 = { 0x0F722F2A, 0x650F, 0x448A, { 0xAB, 0xB7, 0x04, 0xEE, 0xCD, 0x75, 0xBB, 0x30 } };
static EFI_GUID mIioCfgUpdateGuid3 = { 0xEBD11A00, 0x8C5C, 0x4F71, { 0xBB, 0x9E, 0x53, 0x94, 0x03, 0x2B, 0x01, 0xF4 } };
static EFI_GUID mIioCfgUpdateGuid4 = { 0x123BD082, 0x3201, 0x465C, { 0xB1, 0x39, 0x0C, 0xB8, 0xC7, 0x72, 0x08, 0xF8 } };

///
/// HOB GUID used to find the IIO configuration HOB in the HOB list
///
static EFI_GUID mIioCfgHobMatchGuid = { 0x7739F24C, 0x93D7, 0x11D4, { 0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } };

///
/// DebugLib protocol GUID
///
static EFI_GUID mDebugLibProtocolGuid = { 0xE0D4DF48, 0xCB79, 0x4B33, { 0x95, 0x68, 0x20, 0xE8, 0xAA, 0xA1, 0xEC, 0x47 } };

// ===========================================================================
// IIO Configuration Data
// ===========================================================================

///
/// IIO Configuration Update Table (PIIO structure).
/// Contains headers and PCIe register update entries for IIO device
/// configuration on Lightning Ridge EXRP platforms.
///
/// The structure is composed of:
///   PIIO_STRUCTURE Header - with signature, sizes, and counts
///   IIO_CFG_ENTRY Entries[] - array of PCIe config updates
///
/// The entries define AND/OR mask operations to apply to specific
/// PCIe configuration registers on specific socket/bus/device/function
/// targets across all IIO instances.
///
PIIO_STRUCTURE mIioConfigData = {
  .Signature   = PIIO_STRUCTURE_SIGNATURE,   ///< "PIIO"
  .Revision    = 1,
  .HeaderSize  = 0x0D38,
  .EntrySize   = 0x3C,                        ///< 60 bytes per entry (IIO_CFG_ENTRY size)
  .NumEntries  = 0x50C,                       ///< 1292 entries
  .TotalSize   = 0xC60,                       ///< 3168 bytes total
  .Reserved    = 0xD8,                        ///< Reserved (216)
};

///
/// IIO Configuration Entries.
/// Each entry defines a PCIe register AND/OR mask update.
///
/// Entry fields: {Socket, Bus, Device, Func, Register(16-bit), AndMask, OrMask, Flags, Reserved[3]}
///
static IIO_CFG_ENTRY mIioConfigEntries[] = {
  // Socket-level entries
  { 0x01, 0xFF, 0x00, 0xFF, 0x00FF, 0xFF, 0xFF, 0x01, {0, 0, 0} },   // Socket 1
  { 0x02, 0xFF, 0x00, 0xFF, 0x00FF, 0xFF, 0xFF, 0x01, {0, 0, 0} },   // Socket 2
  { 0x03, 0xFF, 0x00, 0xFF, 0x00FF, 0xFF, 0xFF, 0x01, {0, 0, 0} },   // Socket 3
  { 0x04, 0xFF, 0x00, 0xFF, 0x00FF, 0xFF, 0xFF, 0x01, {0, 0, 0} },   // Socket 4
  { 0x05, 0xFF, 0x00, 0xFF, 0x00FF, 0xFF, 0xFF, 0x00, {0, 0, 0} },   // Socket 5 (disabled)
  { 0x09, 0x01, 0x01, 0xFF, 0x01FF, 0x00, 0x40, 0x00, {0, 0, 0} },   // Socket 9 Bus1 Dev1 Reg=0x01FF AND=0x00 OR=0x40 (disabled)
  { 0x15, 0xFF, 0x00, 0xFF, 0x00FF, 0xFF, 0xFF, 0x00, {0, 0, 0} },   // Socket 21 (disabled)
  { 0x16, 0x05, 0x01, 0xFF, 0x00FF, 0xFF, 0xFF, 0x00, {0, 0, 0} },   // Socket 22 Bus5 Dev1 (disabled)
  { 0x1A, 0x07, 0x00, 0xFF, 0x00FF, 0xFF, 0xFF, 0x00, {0, 0, 0} },   // Socket 26 Bus7 Dev0 (disabled)
  { 0x1E, 0x0A, 0x00, 0xFF, 0x00FF, 0xFF, 0xFF, 0x00, {0, 0, 0} },   // Socket 30 Bus10 Dev0 (disabled)
  { 0x2A, 0xFF, 0x00, 0xFF, 0x00FF, 0xFF, 0xFF, 0x01, {0, 0, 0} },   // Socket 42
  { 0x2B, 0x06, 0x01, 0xFF, 0x00FF, 0xFF, 0xFF, 0x00, {0, 0, 0} },   // Socket 43 Bus6 Dev1 (disabled)
  { 0x33, 0x08, 0x00, 0xFF, 0x00FF, 0xFF, 0xFF, 0x00, {0, 0, 0} },   // Socket 51 Bus8 Dev0 (disabled)
  { 0x2F, 0xFF, 0x00, 0xFF, 0x00FF, 0xFF, 0xFF, 0x00, {0, 0, 0} },   // Socket 47 (disabled)
  { 0x3F, 0xFF, 0x00, 0xFF, 0x00FF, 0xFF, 0xFF, 0x01, {0, 0, 0} },   // Socket 63
  { 0x44, 0x03, 0x01, 0xFF, 0x00FF, 0xFF, 0xFF, 0x00, {0, 0, 0} },   // Socket 68 Bus3 Dev1 (disabled)
  { 0x48, 0x04, 0x00, 0xFF, 0x00FF, 0xFF, 0xFF, 0x00, {0, 0, 0} },   // Socket 72 Bus4 Dev0 (disabled)
  { 0x40, 0xFF, 0x00, 0xFF, 0x00FF, 0xFF, 0xFF, 0x01, {0, 0, 0} },   // Socket 64

  //
  // NOTE: In the original binary, there are more entries following these.
  // Full entry count is 0x50C (1292). The entries above are the first 18.
  // The remaining entries follow the same IIO_CFG_ENTRY format.
  //
  // A complete dump would require extracting all 1292 entries from the
  // original binary at offset 0xC3C.
  //
};

// ===========================================================================
// Function Implementations
// ===========================================================================

/**
  Reads a 64-bit value from potentially unaligned memory.
  This is a wrapper around a direct QWORD read with null-pointer check.

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

  @return The 64-bit value, or zero if Buffer is NULL.
**/
UINT64
EFIAPI
ReadUnaligned64 (
  IN CONST VOID  *Buffer
  )
{
  //
  // Assert if buffer is NULL (debug builds only).
  //
  if (Buffer == NULL) {
    AssertHandler (
      "e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
      192,
      "Buffer != ((void *) 0)"
      );
  }

  //
  // Perform direct QWORD read (may be unaligned - x86 handles this in hardware).
  //
  return *(UINT64 *)Buffer;
}

/**
  Compares two GUIDs by comparing them as two 64-bit values.

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

  @return TRUE if the GUIDs are identical, FALSE otherwise.
**/
BOOLEAN
EFIAPI
CompareGuid (
  IN EFI_GUID  *Guid1,
  IN EFI_GUID  *Guid2
  )
{
  UINT64  Guid1First;
  UINT64  Guid1Second;
  UINT64  Guid2First;
  UINT64  Guid2Second;

  //
  // Read both halves of both GUIDs as unaligned 64-bit values.
  //
  Guid1First  = ReadUnaligned64 (Guid1);
  Guid1Second = ReadUnaligned64 ((UINT8 *)Guid1 + 8);
  Guid2First  = ReadUnaligned64 (Guid2);
  Guid2Second = ReadUnaligned64 ((UINT8 *)Guid2 + 8);

  //
  // Both halves must match.
  //
  return (BOOLEAN)(Guid1First == Guid2First && Guid1Second == Guid2Second);
}

/**
  Gets the DebugLib protocol instance.

  Attempts to locate the DebugLib protocol. If not already cached, allocates
  a pool buffer and calls LocateProtocol. The protocol pointer is cached in
  the global mDebugProtocol for subsequent calls.

  @return Pointer to the DebugLib protocol interface, or NULL if not found
          or if the allocation request is too large (>16).
**/
VOID *
GetDebugLibProtocol (
  VOID
  )
{
  VOID   *DebugProtocol;
  UINTN  PoolSize;
  EFI_STATUS  Status;

  //
  // Return cached pointer if already initialized.
  //
  DebugProtocol = mDebugProtocol;
  if (DebugProtocol != NULL) {
    return DebugProtocol;
  }

  //
  // Allocate a small pool buffer for protocol discovery.
  // PoolSize is set to 0x10 + 0x1F = 0x2F (47) to align up to 32 bytes,
  // though the actual allocation request is for 0x1F (31) = MEMORY_TYPE_BOOT_SERVICES_DATA.
  //
  PoolSize = MEMORY_TYPE_BOOT_SERVICES_DATA;
  mDebugProtocol = gBootServices->AllocatePool (PoolSize);

  //
  // Check if allocation was reasonable. If the pointer value is > 16 bytes,
  // it's likely a real allocation, not an error.
  //
  if ((UINTN)mDebugProtocol > 0x10) {
    //
    // Locate the DebugLib protocol by GUID.
    //
    Status = gBootServices->LocateProtocol (
                              &mDebugLibProtocolGuid,
                              NULL,
                              &mDebugProtocol
                              );
    if (EFI_ERROR (Status)) {
      mDebugProtocol = NULL;
    }
  } else {
    //
    // Allocation returned an unexpectedly small value - treat as failure.
    //
    mDebugProtocol = NULL;
  }

  return mDebugProtocol;
}

/**
  Platform-aware debug print function.

  Before printing, this function checks the RTC CMOS and a platform info
  register to determine the system's platform SKU type. This SKU detection
  determines which debug messages are relevant. The debug level is also
  masked against the UBA protocol's debug level filtering.

  Note: The RTC CMOS register 0x4B at index 0x70 is used as a non-volatile
  platform SKU indicator. Additionally, a memory-mapped I/O register at
  0xFDAF0490 may override the SKU.

  @param[in] DebugLevel    Debug message level (e.g., UBA_DEBUG_ERROR).
  @param[in] FormatString  Format string for the debug message.
  @param[in] ...           Variable arguments for the format string.
**/
VOID
EFIAPI
DebugPrintUba (
  IN UINTN       DebugLevel,
  IN CONST CHAR8 *FormatString,
  ...
  )
{
  VA_LIST          VaList;
  UINT64           FilterMask;
  VOID             *DebugProtocol;
  UINT8            CmosSku;
  UINT8            PlatformInfo;
  UINT8            EffectiveSku;
  UINT64           ActualLevel;

  VA_START (VaList, FormatString);

  //
  // Get the DebugLib protocol; if not available, skip the print.
  //
  DebugProtocol = GetDebugLibProtocol ();
  if (DebugProtocol == NULL) {
    return;
  }

  //
  // Read the platform SKU from RTC CMOS register 0x4B.
  // CMOS index 0x4B is selected via I/O port 0x70, data read via port 0x71.
  // The NMI-disable bit (0x80) is preserved in the index write.
  //
  // RTC CMOS register layout:
  //   Bit 7 of port 0x70 = NMI disable
  //   Bits 6-0 of port 0x70 = CMOS register index
  //
  IoWrite8 (RTC_CMOS_INDEX_PORT, (IoRead8 (RTC_CMOS_INDEX_PORT) & 0x80) | RTC_CMOS_INDEX_SKU);
  CmosSku = IoRead8 (RTC_CMOS_DATA_PORT);

  //
  // Determine effective SKU:
  // - If raw CMOS value is 0 (uninitialized/cleared), read the platform info
  //   register at 0xFDAF0490 bit 1 (VT-d / IIO mode indicator).
  // - CMOS value of 1 = Platform Type 1
  // - CMOS value of 2 = Platform Type 2
  // - CMOS value of 3 = Platform Type 3
  // - CMOS value of 4 = Platform Type 4
  // - Values > 3 with CMOS=0 trigger the platform ROM fallback.
  //
  EffectiveSku = CmosSku;
  if (CmosSku > 3) {
    EffectiveSku = CmosSku;
    if (CmosSku == 0) {
      //
      // Read platform info register to determine IIO mode.
      // Bit 1 of 0xFDAF0490 indicates IIO configuration mode.
      // 0xFDAF0490 is a memory-mapped register in the platform controller hub.
      //
      EffectiveSku = (*(volatile UINT8 *)PLATFORM_INFO_REGISTER & 0x02) | 0x01;
    }
  }

  //
  // Map platform SKU to debug level filter mask.
  //   SKU 0 (uninitialized) -> UBA_DEBUG_ERROR (0x80000000)
  //   SKU 1 (Type1)         -> UBA_DEBUG_INFO  (0x80000040)
  //   SKU 2 (Type2)         -> UBA_DEBUG_ERROR (0x80000000)
  //   SKU >3 (Type3+)       -> UBA_DEBUG_ERROR (0x80000000)
  //
  // Note: The default mask for SKU 0 and SKU > 3 is UBA_DEBUG_ERROR,
  // while SKU 1 gets the higher verbosity UBA_DEBUG_INFO mask.
  //
  EffectiveSku--;
  if (EffectiveSku <= 0xFD) {
    //
    // Valid SKU range (1-4 maps to 0-3 after decrement).
    //
    FilterMask = UBA_DEBUG_ERROR;   // Default: only errors
    if (CmosSku == 1) {
      FilterMask = UBA_DEBUG_INFO;  // Type1: allow info-level messages
    }
  } else {
    //
    // Out of range or zero - use debug error level only.
    //
    FilterMask = UBA_DEBUG_ERROR;
  }

  //
  // If the requested debug level passes the filter, call the DebugLib
  // protocol's DebugPrint function (offset +0 from the protocol interface).
  //
  if ((FilterMask & DebugLevel) != 0) {
    //
    // DebugProtocol layout:
    //   +0: DebugPrint (function pointer)
    //   +8: Assert (function pointer)
    //
    ((DEBUG_PRINT_FUNC)((VOID **)DebugProtocol)[0])(
      DebugLevel,
      FormatString,
      (UINT64 *)VaList
      );
  }

  VA_END (VaList);
}

/**
  ASSERT assertion handler wrapper.

  When an assertion fails, this function formats the assertion info
  and calls the DebugLib protocol's ASSERT handler.

  @param[in] FileName   Source file name string.
  @param[in] LineNumber Line number in the source file.
  @param[in] Expression Failed assertion expression string.
**/
VOID
EFIAPI
AssertHandler (
  IN CONST CHAR8 *FileName,
  IN UINTN       LineNumber,
  IN CONST CHAR8 *Expression
  )
{
  VOID   *DebugProtocol;
  EFI_STATUS  Status;

  DebugProtocol = GetDebugLibProtocol ();
  if (DebugProtocol != NULL) {
    //
    // Call DebugProtocol->Assert (at offset +8).
    //
    ((DEBUG_ASSERT_FUNC)((VOID **)DebugProtocol)[1])(
      FileName,
      LineNumber,
      Expression
      );
  }
}

/**
  Initializes the HOB (Hand-Off Block) list pointer.

  Retrieves the HOB list from the SystemTable's configuration table and
  searches for the IIO-specific HOB by GUID matching. The HOB list pointer
  is cached in the global mHobList variable.

  The HOB list is found in the UEFI SystemTable's firmware vendor table
  entries. Specifically:
    - SystemTable->NumberOfTableEntries (at +104/0x68) gives the count
    - SystemTable->ConfigurationTable (at +112/0x70) is the array pointer
    - Each entry is 24 bytes: GUID (16) + Pointer (8)

  @param[in] ImageHandle  The firmware allocated handle for the EFI image.

  @return Pointer to the found HOB, or NULL if no matching HOB was found.
**/
VOID *
HobLibInit (
  IN EFI_HANDLE  ImageHandle
  )
{
  EFI_CONFIGURATION_TABLE  *ConfigTable;
  UINTN                    TableIndex;
  UINTN                    TableCount;
  VOID                     *Hob;
  EFI_STATUS               Status;
  VOID                     *Result;

  //
  // Return cached HOB pointer if already found.
  //
  Result = mHobList;
  if (Result != NULL) {
    return Result;
  }

  //
  // Initialize HOB list to NULL.
  //
  mHobList = NULL;
  TableIndex = 0;

  //
  // Iterate through the SystemTable's configuration table entries.
  // SystemTable layout (offsets from SystemTable pointer):
  //   +0x68 (104): NumberOfTableEntries (UINTN)
  //   +0x70 (112): ConfigurationTable (EFI_CONFIGURATION_TABLE *)
  //   Each entry = 24 bytes: VendorGuid (16) + VendorTable (8)
  //
  TableCount = gSystemTable->NumberOfTableEntries;
  if (TableCount == 0) {
    //
    // No configuration table entries - ASSERT and return NULL.
    //
    DebugPrintUba (
      UBA_DEBUG_ERROR,
      "\nASSERT_EFI_ERROR (Status = %r)\n",
      ASSERT_EFI_ERROR_STATUS
      );
    AssertHandler (
      "e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
      54,
      "!EFI_ERROR (Status)"
      );
    Result = mHobList;
    if (Result == NULL) {
      AssertHandler (
        "e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
        55,
        "mHobList != ((void *) 0)"
        );
    }
    return Result;
  }

  ConfigTable = gSystemTable->ConfigurationTable;

  //
  // Search through all configuration table entries.
  //
  for (TableIndex = 0; TableIndex < TableCount; TableIndex++) {
    //
    // Check if this entry's GUID matches our IIO HOB match GUID.
    //
    if (CompareGuid (&ConfigTable[TableIndex].VendorGuid, &mIioCfgHobMatchGuid)) {
      //
      // Found the matching HOB - return its data pointer.
      //
      Result = ConfigTable[TableIndex].VendorTable;
      mHobList = Result;
      return Result;
    }
  }

  //
  // No matching HOB found - ASSERT.
  //
  DebugPrintUba (
    UBA_DEBUG_ERROR,
    "\nASSERT_EFI_ERROR (Status = %r)\n",
    ASSERT_EFI_ERROR_STATUS
    );
  AssertHandler (
    "e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
    54,
    "!EFI_ERROR (Status)"
    );
  Result = mHobList;
  if (Result == NULL) {
    AssertHandler (
      "e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
      55,
      "mHobList != ((void *) 0)"
      );
  }
  return Result;
}

/**
  Returns EFI_UNSUPPORTED status stub.

  @return EFI_UNSUPPORTED Always returns EFI_UNSUPPORTED.
**/
EFI_STATUS
EFIAPI
IioCfgUpdateUnsupported (
  VOID
  )
{
  return EFI_UNSUPPORTED;
}

/**
  Main IIO configuration update routine.

  This function performs the core IIO config update by:
    1. Printing a debug message identifying this module.
    2. Locating the UBA_PROTOCOL via gBS->LocateProtocol().
    3. Iterating through all four IIO config GUIDs and calling
       the UBA protocol's SetIIOConfigData function (at offset +16)
       for each GUID with the PIIO configuration data structure.

  The configuration data (mIioConfigData + mIioConfigEntries) describes
  PCIe register AND/OR mask updates to be applied to IIO root ports
  during system initialization.

  @retval EFI_SUCCESS           All IIO configuration data was registered
                                with the UBA protocol successfully.
  @retval EFI_UNSUPPORTED       The UBA protocol was not found.
  @retval EFI_INVALID_PARAMETER One of the SetIIOConfigData calls failed.
**/
EFI_STATUS
IioCfgUpdateMain (
  VOID
  )
{
  UBA_PROTOCOL  *UbaProtocol;
  EFI_STATUS    Status;
  UINTN         ConfigSize;

  //
  // Initialize config size to sizeof(IIO_CFG_ENTRY) = 0x3C = 60 bytes.
  // This is the per-entry size used by the UBA protocol handler.
  //
  ConfigSize = sizeof (IIO_CFG_ENTRY);

  //
  // Print module identification string for debug/trace purposes.
  //
  DebugPrintUba (
    UBA_DEBUG_ERROR,
    "UBA:IioCfgUpdate-TypeLightningRidgeEXRP\n"
    );

  //
  // Locate the UBA protocol.
  // gBS->LocateProtocol() is at gBootServices offset +320 (0x140)
  // in the BootServices table (function index 41 since each entry is 8 bytes).
  //
  Status = gBootServices->LocateProtocol (
                            &mUbaProtocolGuid,
                            NULL,
                            (VOID **)&UbaProtocol
                            );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Register each of the four IIO configuration blocks.
  // Each call uses the same PIIO configuration data structure but
  // is identified by a different GUID, allowing the UBA core to
  // distinguish between different IIO config block types.
  //
  // SetIIOConfigData is at UbaProtocol offset +16 (function index 2).
  //

  Status = UbaProtocol->SetIIOConfigData (
                          UbaProtocol,
                          &mIioCfgUpdateGuid1,
                          &mIioConfigData,
                          ConfigSize
                          );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = UbaProtocol->SetIIOConfigData (
                          UbaProtocol,
                          &mIioCfgUpdateGuid2,
                          &mIioConfigData,
                          ConfigSize
                          );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = UbaProtocol->SetIIOConfigData (
                          UbaProtocol,
                          &mIioCfgUpdateGuid3,
                          &mIioConfigData,
                          ConfigSize
                          );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = UbaProtocol->SetIIOConfigData (
                          UbaProtocol,
                          &mIioCfgUpdateGuid4,
                          &mIioConfigData,
                          ConfigSize
                          );
  return Status;
}

/**
  Entry point for the IIO Configuration Update DXE driver.

  Standard UEFI driver entry point. Initializes the global UEFI system
  table pointers (ImageHandle, SystemTable, BootServices, RuntimeServices),
  calls HobLibInit() to locate the IIO configuration HOB, then calls
  IioCfgUpdateMain() to perform the IIO configuration data update.

  The entry point performs the following initialization:
    1. Saves ImageHandle and SystemTable to globals.
    2. Validates all required table pointers (non-NULL checks).
    3. Saves BootServices (SystemTable->BootServices) to global.
    4. Saves RuntimeServices (SystemTable->RuntimeServices) to global.
    5. Initializes the HOB list via HobLibInit().
    6. Calls IioCfgUpdateMain() to send IIO config data to UBA protocol.

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

  @return EFI_STATUS      Status code from IioCfgUpdateMain().
**/
EFI_STATUS
EFIAPI
ModuleEntryPoint (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS  Status;

  //
  // Save image handle pointer.
  //
  gImageHandle = ImageHandle;
  if (ImageHandle == NULL) {
    AssertHandler (
      "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      51,
      "gImageHandle != ((void *) 0)"
      );
  }

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

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

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

  //
  // Initialize HOB list (find IIO configuration HOB).
  //
  HobLibInit (ImageHandle);

  //
  // Perform the IIO configuration data update.
  //
  Status = IioCfgUpdateMain ();
  return Status;
}