/** @file
  SmbiosDataUpdateDxeNeonCityFPGA -- UBA SMBIOS Data Update implementation.

  This file implements the UBA SMBIOS data update driver for the NeonCityFPGA
  platform. It constructs and updates SMBIOS types 8 (Port Connector), 9
  (System Slots), and 41 (Onboard Devices Extended Information) by reading
  platform-specific hardware configuration through PCI config space via the
  MmPciBase protocol (gEfiMmPciBaseProtocolGuid / USRA protocol).

  Copyright (C) Lenovo. All rights reserved.
**/

#include "SmbiosDataUpdateDxeNeonCityFPGA.h"

// ===========================================================================
// Global variable declarations (from UEFI library headers and this module)
// ===========================================================================

// System table and boot services (set by sub_38C, consumed by all functions)
extern EFI_SYSTEM_TABLE   *gST;
extern EFI_BOOT_SERVICES  *gBS;
extern EFI_HANDLE          gImageHandle;
extern EFI_RUNTIME_SERVICES *gRT;

// Module-specific globals
static EFI_HII_STRING_PROTOCOL   *gHiiString      = NULL;  // 0x3928
static EFI_HII_DATABASE_PROTOCOL *gHiiDatabase     = NULL;  // 0x3948
static EFI_HII_IMAGE_PROTOCOL    *gHiiImage         = NULL;  // 0x3930
static EFI_HII_FONT_PROTOCOL     *gHiiFont          = NULL;  // 0x3940
static EFI_HII_CONFIG_ROUTING_PROTOCOL *gHiiConfigRouting = NULL; // 0x3938
static VOID                       *gHobList          = NULL;  // 0x3920
static EFI_SMBIOS_PROTOCOL       *gSmbios           = NULL;  // 0x3958
static EFI_SMBIOS_PROTOCOL       *gSmbios2          = NULL;  // 0x3968
static EFI_SMBIOS_PROTOCOL       *gSmbios3          = NULL;  // 0x3970
static EFI_SMBIOS_PROTOCOL       *gSmbios4          = NULL;  // 0x3978
static UBA_SMBIOS_UPDATE_PROTOCOL *gUbaSmbiosUpdate  = NULL;  // 0x3960
static EFI_HII_HANDLE             gSmbiosStringPack  = NULL;  // 0x38F0
static MM_PCI_BASE_PROTOCOL      *gMmPciBase         = NULL;  // 0x3980
static EFI_DXE_SERVICES          *gDS                = NULL;  // 0x3950

// Debug output protocol and HOB list
static VOID *mDebugProtocol = NULL;  // 0x3918 (DebugLib protocol)

// ===========================================================================
// Low-level utility functions
// ===========================================================================

/**
  ZeroMem wrapper -- zeroes a memory buffer.
  @param[in] Buffer  Pointer to buffer to zero.
  @param[in] Length  Number of bytes to zero.
  @return Buffer.
*/
static
VOID *
EFIAPI
ZeroMem (
  IN VOID   *Buffer,
  IN UINTN  Length
  )
{
  // sub_280 at 0x280 -- memset to 0 in 8-byte chunks plus trailing bytes
  // (inline implementation from BaseMemoryLibRepStr)
  CHAR8 *Buf = (CHAR8 *)Buffer;
  if (Length == 0) return Buffer;
  SetMem (Buf, Length, 0);
  return Buffer;
}

/**
  CopyMem wrapper -- copies a memory buffer with overlap handling.
  @param[out] Destination  Destination buffer.
  @param[in]  Source       Source buffer.
  @param[in]  Length       Number of bytes to copy.
  @return Destination.
*/
static
VOID *
EFIAPI
CopyMem (
  OUT VOID       *Destination,
  IN  const VOID *Source,
  IN  UINTN      Length
  )
{
  // sub_300 at 0x300 + sub_20AC at 0x20AC
  // CopyMem implementation with forward/backward overlap detection
  return CopyMem (Destination, Source, Length);
}

// ===========================================================================
// PCI config access via MmPciBase (USRA protocol)
// ===========================================================================

/**
  Read a 32-bit value from PCI config space using the MmPciBase protocol.

  This uses the USRA (Unified System Register Access) protocol identified by
  gEfiMmPciBaseProtocolGuid. The register address is encoded as:
    Address = ((Bus & 0xFF) | (Device & 0x1F) << 8 | (Function & 7) << 13) << 12

  @param[in]  Bus       PCI bus number.
  @param[in]  Device    PCI device number (5 bits).
  @param[in]  Function  PCI function number (3 bits).
  @param[in]  Register  Register offset within PCI config space.
  @param[out] Value     Pointer to receive the 32-bit value.

  @retval EFI_SUCCESS           Read successful.
  @retval EFI_INVALID_PARAMETER Invalid register.
  @retval EFI_NOT_FOUND         Protocol not located.
*/
EFI_STATUS
MmioPciRead32 (
  IN  UINT8   Bus,
  IN  UINT8   Device,
  IN  UINT8   Function,
  IN  UINT16  Register,
  OUT UINT32  *Value
  )
{
  // sub_2064 at 0x2064
  UINT32  Address;
  UINT32  Result;

  // Build the USRA address: (Bus|Device<<8|Func<<13) << 12 + Register
  Address = ((Function & 7) | ((Device & 0x1F) << 3) | (Bus << 8)) << 12;
  Address |= (Register & 0xFFF);

  // Call MmPciBase->Read(Address) at offset +24 (0x18)
  Result = gMmPciBase->Read (gMmPciBase, Address);
  *Value = Result;
  return EFI_SUCCESS;
}

// ===========================================================================
// Debug output functions
// ===========================================================================

/**
  Get the debug output protocol instance (lazily resolved).

  Uses AllocatePool/FreePool as a UEFI environment guard before calling
  LocateProtocol. If the protocol cannot be located, returns NULL.

  @return Pointer to the debug output protocol, or NULL.
*/
static
VOID *
GetDebugProtocol (
  VOID
  )
{
  // sub_1044 at 0x1044
  // Allocates 31 bytes then frees as a guard, then calls LocateProtocol
  // for the DebugLib protocol GUID at 0x31C0
  if (mDebugProtocol == NULL) {
    VOID *Guard;
    Guard = AllocatePool (31);
    if (Guard == NULL) return NULL;
    FreePool (Guard);
    // Only proceed if AllocatePool succeeded (environments may not have it)
    if ((UINTN)Guard <= 0x10) {
      return NULL;
    }
    gBS->LocateProtocol (&gEfiDebugProtocolGuid, NULL, &mDebugProtocol);
    if (mDebugProtocol == NULL) {
      mDebugProtocol = NULL;
    }
  }
  return mDebugProtocol;
}

/**
  Debug print with platform-specific debug level filtering.

  Reads the CMOS debug level register (0x4B) through RTC ports 0x70/0x71.
  Falls back to MMIO 0xFDAF0490 if CMOS level is 0. Filters output against
  the requested ErrorLevel.

  @param[in] ErrorLevel  Debug error level mask.
  @param[in] Format      Print format string.
  @param[in] ...         Variable arguments.
*/
static
VOID
DebugPrint (
  IN UINTN       ErrorLevel,
  IN const CHAR8 *Format,
  ...
  )
{
  // sub_10C4 at 0x10C4
  VOID         *Protocol;
  UINT8         CmosLevel;
  VA_LIST      Va;

  Protocol = GetDebugProtocol ();
  if (Protocol == NULL) return;

  // Read CMOS register 0x4B via RTC ports 0x70/0x71
  CmosLevel = IoRead8 (0x70);
  IoWrite8 (0x70, (CmosLevel & 0xCB) | 0x4B);  // 0x4B = CMOS debug level register
  CmosLevel = IoRead8 (0x71);

  if (CmosLevel > 3) {
    // Values > 3 are invalid -- use current value unless it's 0
    if (CmosLevel == 0) {
      // Fallback: MMIO at fixed address 0xFDAF0490
      CmosLevel = (MmioRead8 (0xFDAF0490) & 2) | 1;
    }
  }

  if ((CmosLevel - 1) <= 0xFD) {
    UINTN FilterLevel;
    if (CmosLevel == 1) {
      FilterLevel = 0x80000004;  // EFI_DWORD(0x80000004) -- error only
    } else {
      FilterLevel = 0x80000006;  // EFI_DWORD(0x80000006) -- warning & error
    }
    if (FilterLevel & ErrorLevel) {
      VA_START (Va, Format);
      ((DEBUG_OUTPUT_PROTOCOL *)Protocol)->DebugPrint (ErrorLevel, Format, Va);
      VA_END (Va);
    }
  }
}

/**
  Debug assertion handler.

  @param[in] FileName     Source file name.
  @param[in] LineNumber   Line number where assertion occurred.
  @param[in] Description  Assertion description string.
*/
static
VOID
DebugAssert (
  IN const CHAR8  *FileName,
  IN UINTN         LineNumber,
  IN const CHAR8  *Description
  )
{
  // sub_114C at 0x114C
  VOID *Protocol;
  Protocol = GetDebugProtocol ();
  if (Protocol != NULL) {
    ((DEBUG_OUTPUT_PROTOCOL *)Protocol)->DebugAssert (
      FileName, LineNumber, Description
      );
  }
}

// ===========================================================================
// ReadUnaligned helpers
// ===========================================================================

/**
  Read a 32-bit unaligned value from memory.

  @param[in] Buffer  Pointer to read from (may be unaligned).
  @return The 32-bit value.
*/
static
UINT32
ReadUnaligned32 (
  IN const VOID *Buffer
  )
{
  // sub_12AC at 0x12AC
  ASSERT (Buffer != NULL);
  return *(volatile UINT32 *)Buffer;
}

/**
  Read a 64-bit unaligned value from memory.

  @param[in] Buffer  Pointer to read from (may be unaligned).
  @return The 64-bit value.
*/
static
UINT64
ReadUnaligned64 (
  IN const VOID *Buffer
  )
{
  // sub_12DC at 0x12DC
  ASSERT (Buffer != NULL);
  return *(volatile UINT64 *)Buffer;
}

/**
  Write a 64-bit unaligned value to memory.

  @param[out] Buffer  Pointer to write to (may be unaligned).
  @param[in]  Value   Value to write.
  @return Value.
*/
static
UINT64
WriteUnaligned64 (
  OUT VOID   *Buffer,
  IN  UINT64  Value
  )
{
  // sub_130C at 0x130C
  ASSERT (Buffer != NULL);
  *(volatile UINT64 *)Buffer = Value;
  return Value;
}

/**
  Compare two GUIDs using unaligned 64-bit reads.

  @param[in] Guid1  First GUID pointer.
  @param[in] Guid2  Second GUID pointer.
  @return TRUE if identical, FALSE otherwise.
*/
static
BOOLEAN
IsGuidEqual (
  IN const EFI_GUID *Guid1,
  IN const EFI_GUID *Guid2
  )
{
  // sub_11D4 at 0x11D4
  return ReadUnaligned64 (Guid1) == ReadUnaligned64 (Guid2) &&
         ReadUnaligned64 ((UINT8 *)Guid1 + 8) == ReadUnaligned64 ((UINT8 *)Guid2 + 8);
}

// ===========================================================================
// Memory allocation helpers
// ===========================================================================

/**
  Allocate zero-filled pool.

  @param[in] Size  Number of bytes to allocate.
  @return Pointer to allocated and zeroed buffer, or NULL.
*/
static
VOID *
AllocateZeroPool (
  IN UINTN Size
  )
{
  // sub_137C at 0x137C
  VOID *Buf = AllocatePool (Size);
  if (Buf != NULL) {
    ZeroMem (Buf, Size);
  }
  return Buf;
}

/**
  Free pool and assert on failure.

  @param[in] Buffer  Pointer to free.
  @return EFI_STATUS from FreePool call.
*/
static
EFI_STATUS
FreePoolAssert (
  IN VOID *Buffer
  )
{
  // sub_13A4 at 0x13A4
  EFI_STATUS Status = gBS->FreePool (Buffer);
  ASSERT_EFI_ERROR (Status);
  return Status;
}

// ===========================================================================
// UEFI configuration table / HOB list operations
// ===========================================================================

/**
  Locate a configuration table by GUID.

  Scans gST->ConfigurationTable[] for a matching GUID. Each table entry
  is 0x18 (24) bytes: 16-byte GUID + 8-byte pointer.

  @param[in]  TableGuid  GUID of the table to find.
  @param[out] Table      Receives the pointer to the table data.

  @return EFI_SUCCESS           Table found.
  @return EFI_NOT_FOUND         Table not found.
*/
EFI_STATUS
GetConfigurationTable (
  IN  EFI_GUID  *TableGuid,
  OUT VOID      **Table
  )
{
  // sub_13E8 at 0x13E8 (EfiGetSystemConfigurationTable)
  UINTN Index;

  ASSERT (TableGuid != NULL);
  ASSERT (Table != NULL);

  *Table = NULL;
  if (gST->NumberOfTableEntries == 0) {
    return EFI_NOT_FOUND;
  }

  for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
    if (IsGuidEqual (TableGuid, &gST->ConfigurationTable[Index].VendorGuid)) {
      *Table = gST->ConfigurationTable[Index].VendorTable;
      return EFI_SUCCESS;
    }
  }

  return EFI_NOT_FOUND;
}

/**
  Get the HOB list pointer (lazily resolved).

  @return Pointer to the HOB list, or NULL.
*/
static
VOID *
GetHobList (
  VOID
  )
{
  // sub_16E8 at 0x16E8
  EFI_STATUS  Status;

  if (gHobList == NULL) {
    Status = GetConfigurationTable (&gEfiHobListGuid, &gHobList);
    ASSERT_EFI_ERROR (Status);
    ASSERT (gHobList != NULL);
  }
  return gHobList;
}

// ===========================================================================
// Language / platform string operations
// ===========================================================================

/**
  Get the current platform language.

  Uses RT->GetVariable to read "PlatformLang" UEFI variable.

  @param[out] Language  Receives allocated platform language string.
                         Caller must free with FreePool.

  @return EFI_SUCCESS           Language retrieved.
  @return EFI_NOT_FOUND         PlatformLang variable not found.
  @return EFI_OUT_OF_RESOURCES  Memory allocation failed.
*/
EFI_STATUS
GetPlatformLanguage (
  OUT CHAR8 **Language
  )
{
  // sub_14AC at 0x14AC
  UINTN      Size;
  EFI_STATUS Status;

  ASSERT (Language != NULL);

  Size   = 0;
  *Language = NULL;

  Status = gRT->GetVariable (
                  L"PlatformLang",
                  &gEfiPlatformLangGuid,
                  NULL,
                  &Size,
                  NULL
                  );

  if (Status == EFI_BUFFER_TOO_SMALL) {
    *Language = AllocatePool (Size);
    if (*Language == NULL) {
      ASSERT (*Language != NULL);
      return EFI_OUT_OF_RESOURCES;
    }

    Status = gRT->GetVariable (
                    L"PlatformLang",
                    &gEfiPlatformLangGuid,
                    NULL,
                    &Size,
                    *Language
                    );
    if (EFI_ERROR (Status)) {
      FreePoolAssert (*Language);
      *Language = NULL;
    }
  }

  return Status;
}

/**
  Find a supported language within a language list and return a copy.

  Languages are separated by semicolons in the SupportedLanguages string.
  Matches up to 3 characters of each language tag.

  @param[in] SupportedLanguages  Semicolon-separated language list.
  @param[in] DefaultLanguage     Default to use if SupportedLanguages is empty
                                 (first character of the format argument).
  @param[in] ...                 Variable arguments; second arg is the target
                                 language to search for.

  @return Allocated copy of the matched language string, or NULL.
*/
static
CHAR8 *
FindLanguage (
  IN CHAR8   *SupportedLanguages,
  IN CHAR8   DefaultLanguage,
  ...
  )
{
  // sub_15A4 at 0x15A4
  CHAR8       *TargetLanguage;
  VA_LIST     Args;
  UINTN       TargetLen;
  CHAR8       *LangPtr;
  UINTN       LangLen;

  ASSERT (SupportedLanguages != NULL);

  VA_START (Args, DefaultLanguage);
  TargetLanguage = VA_ARG (Args, CHAR8 *);
  VA_END (Args);

  TargetLen = AsciiStrLen (TargetLanguage);
  if (TargetLen > 3) TargetLen = 3;

  LangPtr = SupportedLanguages;
  while (*LangPtr != '\0') {
    // Skip over semicolons
    while (*LangPtr == ';') LangPtr++;

    LangLen = 0;
    while (LangPtr[LangLen] != '\0' && LangPtr[LangLen] != ';') {
      LangLen++;
    }

    if (TargetLen <= LangLen) {
      if (AsciiStrnCmp (LangPtr, TargetLanguage, TargetLen) == 0) {
        CHAR8 *Result = AllocateZeroPool (LangLen + 1);
        if (Result != NULL) {
          CopyMem (Result, LangPtr, LangLen);
        }
        return Result;
      }
    }
    LangPtr += LangLen;
  }

  // Fall back to first language in SupportedLanguages
  LangPtr = SupportedLanguages;
  while (*LangPtr == ';') LangPtr++;
  LangLen = 0;
  while (LangPtr[LangLen] != '\0' && LangPtr[LangLen] != ';') {
    LangLen++;
  }
  if (LangLen > 0) {
    CHAR8 *Result = AllocateZeroPool (LangLen + 1);
    if (Result != NULL) {
      CopyMem (Result, LangPtr, LangLen);
    }
    return Result;
  }

  return NULL;
}

// ===========================================================================
// HII string and package operations
// ===========================================================================

/**
  Get the HII string for a given StringId, localized to the current platform
  language.

  @param[in]  HiiHandle  HII handle for the string package.
  @param[in]  StringId   String token ID.
  @param[in]  Language   Pointer to NULL (accepts default language).

  @return Allocated string value, or NULL on failure. Caller must free.
*/
static
CHAR16 *
GetHiiString (
  IN EFI_HII_HANDLE  HiiHandle,
  IN EFI_STRING_ID   StringId,
  IN CHAR8           *Language
  )
{
  // sub_1A44 at 0x1A44
  UINTN     Size;
  CHAR16    *String;
  EFI_STATUS Status;

  ASSERT (HiiHandle != NULL);
  ASSERT (StringId != 0);

  // Skip the "Language" lookup used in the original code
  // which calls gHiiString->GetString() at [gHiiString + 0x18] (offset +24)

  Size = 0;
  String = NULL;

  // Query required buffer size
  Status = gHiiString->GetString (
                         gHiiString,
                         Language,       // Language string (or NULL for auto)
                         HiiHandle,
                         StringId,
                         &Size,
                         NULL
                         );

  if (Status == EFI_BUFFER_TOO_SMALL) {
    String = AllocateZeroPool (Size);
    if (String != NULL) {
      Status = gHiiString->GetString (
                             gHiiString,
                             Language,
                             HiiHandle,
                             StringId,
                             &Size,
                             String
                             );
      if (EFI_ERROR (Status)) {
        FreePoolAssert (String);
        return NULL;
      }
    }
  }

  return String;
}

/**
  Get the HII string for a given StringId with explicit language handling.

  Resolves the platform language via GetPlatformLanguage, then calls
  GetHiiString. Falls back to "en-US" hardcoded at 0x2AFA if no platform
  language is found.

  @param[in] HiiHandle  HII handle.
  @param[in] StringId   String token ID.
  @param[in] Language   Optional language override (NULL = auto-detect).

  @return Allocated string, or NULL.
*/
static
CHAR16 *
GetLocalizedHiiString (
  IN EFI_HII_HANDLE  HiiHandle,
  IN EFI_STRING_ID   StringId,
  IN CHAR8           *Language OPTIONAL
  )
{
  // sub_176C at 0x176C (full version with language resolution)
  CHAR8     *PlatformLang;
  CHAR16    *Result;
  EFI_STATUS Status;

  ASSERT (HiiHandle != NULL);
  ASSERT (StringId != 0);

  Result = NULL;
  PlatformLang = NULL;

  // Get platform language
  Status = GetPlatformLanguage (&PlatformLang);
  if (!EFI_ERROR (Status) && PlatformLang != NULL) {
    // The HII handle might need language-specific string resolution
    // FindLanguage would select the best match
    Result = GetHiiString (HiiHandle, StringId, "en-US");
  } else {
    // Fallback to default language
    Result = GetHiiString (HiiHandle, StringId, "en-US");
  }

  if (PlatformLang != NULL) {
    FreePoolAssert (PlatformLang);
  }

  return Result;
}

// ===========================================================================
// SMBIOS string management
// ===========================================================================

/**
  Search for the next string in an SMBIOS structure's string area.

  The string area in an SMBIOS record starts after the fixed-length structure.
  Two consecutive NULL bytes terminate the string area.

  @param[in,out] StringArea   Pointer to pointer to current position.
  @param[out]    StringOffset Receives the offset of the next string within
                              the original structure.

  @return EFI_SUCCESS           Next string found.
  @return EFI_NOT_FOUND         No more strings (end of string area).
*/
static
EFI_STATUS
GetNextSmbiosString (
  IN OUT CHAR8   **StringArea,
  OUT    UINTN   *StringOffset
  )
{
  // sub_1DC8 at 0x1DC8
  CHAR8  *Base;
  UINTN  Offset;
  UINTN  Index;

  Base   = *StringArea;
  Offset = (UINTN)(*StringArea)[1];  // Original code: reads from offset +1

  while (TRUE) {
    if (Base[Offset] == '\0') {
      Offset++;
      if (Base[Offset] == '\0') {
        // End of string area
        *StringOffset = Offset + 2;
        return EFI_NOT_FOUND;
      }
      Offset++;
    }

    for (Index = 0; Index < 64; Index++) {
      if (Base[Offset + Index] == '\0') break;
    }

    if (Index == 64) break;  // String too long, abort
    Offset += Index;
    *StringOffset = Offset;
    return EFI_SUCCESS;
  }

  return EFI_NOT_FOUND;
}

/**
  Remove and reinsert an SMBIOS record (or add if not present).

  Uses gSmbios->RemoveString() then gSmbios->Add() to update a string
  in an existing SMBIOS record. This is how string overrides are applied.

  @param[in] Buffer  Pointer to the SMBIOS record buffer.
*/
static
EFI_STATUS
UpdateSmbiosRecord (
  IN VOID *Buffer
  )
{
  // sub_1E1C at 0x1E1C -- calls gSmbios3->RemoveString(0, -2, Buffer)
  // and gSmbios3->Add()
  EFI_STATUS Status;

  // Lazy init of gSmbios3
  if (gSmbios3 == NULL) {
    Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&gSmbios3);
    if (EFI_ERROR (Status)) return Status;
  }

  // Remove all strings from the record (StringId=0, then call with -2 marker)
  // then add the record
  gSmbios3->RemoveString (gSmbios3, 0, 0xFFFE, Buffer);
  return EFI_SUCCESS;
}

/**
  Enumerate and remove SMBIOS records of a given type, then remove them.

  This counts how many records of the given type exist, then removes them
  one at a time by calling gSmbios4->Remove(-1) and gSmbios4->Add().

  @param[in] Type  SMBIOS type to process (8, 9, or 41).

  @return EFI_SUCCESS  All records of the given type were processed.
*/
static
EFI_STATUS
RemoveSmbiosRecordsByType (
  IN UINT8 Type
  )
{
  // sub_1FB4 at 0x1FB4
  EFI_STATUS       Status;
  UINTN            Count;
  EFI_SMBIOS_HANDLE SmbiosHandle;
  UINTN            Index;

  // Lazy init gSmbios2
  if (gSmbios2 == NULL) {
    Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&gSmbios2);
    if (EFI_ERROR (Status)) return Status;
  }

  // Count existing records of this type
  Count = 0;
  SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
  while (gSmbios2->GetNext (gSmbios2, &SmbiosHandle, NULL, NULL, NULL) == EFI_SUCCESS) {
    Count++;
  }

  // Remove each record
  for (Index = 0; Index < Count; Index++) {
    Status = RemoveSingleSmbiosRecord (Type);
    if (EFI_ERROR (Status)) break;
  }

  if (Count == 0) return EFI_SUCCESS;

  return EFI_SUCCESS;
}

/**
  Remove a single SMBIOS record by using the Smbios protocol's string remove.

  @param[in] Type  SMBIOS type to target.

  @return EFI_STATUS from the operation.
*/
static
EFI_STATUS
RemoveSingleSmbiosRecord (
  IN UINT8 Type
  )
{
  // sub_1F50 at 0x1F50
  EFI_SMBIOS_HANDLE Handle;
  EFI_STATUS        Status;

  // Lazy init gSmbios4
  if (gSmbios4 == NULL) {
    Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&gSmbios4);
    if (EFI_ERROR (Status)) return Status;
  }

  Status = gSmbios4->GetNext (gSmbios4, &Handle, NULL, NULL, NULL);
  if (EFI_ERROR (Status)) return Status;

  gSmbios4->RemoveString (gSmbios4, Handle, SMBIOS_HANDLE_PI_RESERVED, NULL);
  return EFI_SUCCESS;
}

// ===========================================================================
// String handling utilities
// ===========================================================================

/**
  Get the length of a NULL-terminated ASCII string (max 1000000 chars).

  @param[in] String  The string to measure.

  @return Length in bytes, excluding the terminator.
*/
static
UINTN
AsciiStrLen (
  IN const CHAR8 *String
  )
{
  // sub_2148 at 0x2148
  UINTN Len;

  ASSERT (String != NULL);

  Len = 0;
  while (String[Len] != '\0') {
    if (Len >= PCD_MAX_ASCII_STRING_LENGTH) {
      ASSERT (Len < PCD_MAX_ASCII_STRING_LENGTH);
    }
    Len++;
  }
  return Len;
}

/**
  Compare two ASCII strings up to n characters.

  @param[in] FirstString   First string.
  @param[in] SecondString  Second string.
  @param[in] Length        Maximum number of characters to compare.

  @return 0 if equal, negative if First < Second, positive if First > Second.
*/
static
INTN
AsciiStrnCmp (
  IN const CHAR8  *FirstString,
  IN const CHAR8  *SecondString,
  IN UINTN         Length
  )
{
  // sub_21B4 at 0x21B4
  ASSERT (AsciiStrSize (FirstString) != -1);
  ASSERT (AsciiStrSize (SecondString) != -1);
  ASSERT (Length <= PCD_MAX_ASCII_STRING_LENGTH);

  while (*FirstString && *SecondString && *FirstString == *SecondString && Length > 1) {
    FirstString++;
    SecondString++;
    Length--;
  }
  return (INTN)(UINT8)*FirstString - (INTN)(UINT8)*SecondString;
}

/**
  Get the size of a NULL-terminated ASCII string including the terminator.

  @param[in] String  The string.

  @return Size in bytes including the NULL terminator.
*/
static
UINTN
AsciiStrSize (
  IN const CHAR8 *String
  )
{
  // Equivalent to AsciiStrLen(String) + 1
  return AsciiStrLen (String) + 1;
}

/**
  Get the length of a NULL-terminated Unicode string (max DestMax).

  @param[in] String   The string.
  @param[in] DestMax  Maximum length.

  @return Length in characters, excluding the terminator.
  @return DestMax if the string is longer than DestMax-1.
  @return 0 if String is NULL or DestMax is 0.
*/
static
UINTN
StrnLenS (
  IN const CHAR16 *String,
  IN UINTN         DestMax
  )
{
  // sub_2280 at 0x2280
  ASSERT (((UINTN)String & 1) == 0);  // Must be 2-byte aligned

  if (String == NULL || DestMax == 0) return 0;

  if (String[0] == L'\0') return 0;

  UINTN Len = 0;
  while (Len < DestMax - 1) {
    if (String[++Len] == L'\0') return Len;
  }
  return DestMax;
}

/**
  Get the length of a NULL-terminated ASCII string (max DestMax).

  @param[in] String   The string.
  @param[in] DestMax  Maximum length.

  @return Length in bytes, excluding the terminator.
  @return DestMax if the string is longer than DestMax-1.
  @return 0 if String is NULL or DestMax is 0.
*/
static
UINTN
AsciiStrnLenS (
  IN const CHAR8  *String,
  IN UINTN         DestMax
  )
{
  // sub_22E8 at 0x22E8
  if (String == NULL || DestMax == 0) return 0;

  if (String[0] == '\0') return 0;

  UINTN Len = 0;
  while (Len < DestMax - 1) {
    if (String[++Len] == '\0') return Len;
  }
  return DestMax;
}

/**
  Copy a Unicode string to an ASCII buffer with safe length handling.

  This is an inline implementation of UnicodeStrnToAsciiStrS that handles
  overlap detection (similar to internal SafeString functions).

  @param[out] Destination  ASCII destination buffer.
  @param[in]  Source       Unicode source string.
  @param[in]  DestMax      Maximum size of destination buffer.

  @return EFI_SUCCESS           Copy completed.
  @return EFI_INVALID_PARAMETER Destination or Source is NULL.
  @return EFI_BUFFER_TOO_SMALL  DestMax <= SourceLen.
  @return EFI_SECURITY_VIOLATION Overlap detected.
*/
static
EFI_STATUS
UnicodeStrnToAsciiStrS (
  OUT CHAR8   *Destination,
  IN  CHAR16  *Source,
  IN  UINTN   DestMax
  )
{
  // sub_2314 at 0x2314
  UINTN SourceLen;

  ASSERT (((UINTN)Source & 1) == 0);
  ASSERT (Destination != NULL);
  ASSERT (Source != NULL);
  ASSERT (DestMax <= PCD_MAX_ASCII_STRING_LENGTH);
  ASSERT (DestMax != 0);

  SourceLen = StrnLenS (Source, DestMax);
  if (DestMax <= SourceLen) {
    ASSERT (DestMax > SourceLen);
    return EFI_BUFFER_TOO_SMALL;
  }

  // Check overlap
  if ((CHAR8 *)Source >= Destination) {
    if (Destination >= (CHAR8 *)&Source[SourceLen + 1]) {
      // No overlap -- safe forward copy
    } else {
      // Overlap detected
      ASSERT (!InternalSafeStringIsOverlap (
        Destination, DestMax, (VOID *)Source, (SourceLen + 1) * sizeof (CHAR16)
        ));
      return EFI_SECURITY_VIOLATION;
    }
  } else {
    if ((CHAR16 *)Destination >= &Source[DestMax / sizeof (CHAR16)]) {
      // No overlap
    } else {
      ASSERT (!InternalSafeStringIsOverlap (
        Destination, DestMax, (VOID *)Source, (SourceLen + 1) * sizeof (CHAR16)
        ));
      return EFI_SECURITY_VIOLATION;
    }
  }

  // Perform the copy, narrowing CHAR16 to CHAR8
  CHAR8 *Dst = Destination;
  CHAR16 *Src = Source;
  while (*Src) {
    ASSERT (*Src < 0x100);  // Must fit in CHAR8
    *Dst++ = (CHAR8)*Src++;
  }
  *Dst = '\0';

  return EFI_SUCCESS;
}

// ===========================================================================
// HII string concatenation with SMBIOS record update
// ===========================================================================

/**
  Concatenate a new ASCII string into an SMBIOS record's string area,
  updating the record via the SMBIOS protocol.

  This function takes an SMBIOS record buffer (pointed to by a1), a language
  index (a3), and a source Unicode string (a4). It:
    1. Converts the Unicode string to ASCII
    2. Finds the correct insertion point in the SMBIOS string area based on
       the language index
    3. Rebuilds the string area with the new string inserted
    4. Calls Smbios protocol to string-update the record

  @param[in] Buffer     SMBIOS record buffer.
  @param[in] StringId   SMBIOS string ID (1-based index).
  @param[in] LanguageIndex  Language variant index.
  @param[in] StringSrc  Source Unicode string from HII.

  @return EFI_SUCCESS           String updated.
  @return EFI_OUT_OF_RESOURCES  Memory allocation failed.
*/
static
EFI_STATUS
UpdateSmbiosString (
  IN VOID    *Buffer,
  IN UINTN   StringId,
  IN UINTN   LanguageIndex,
  IN CHAR16  *StringSrc
  )
{
  // sub_1AE8 at 0x1AE8
  CHAR8    *AsciiString;
  UINTN    AsciiLen;
  UINTN    StringAreaOffset;
  CHAR8    *TargetPos;
  UINTN    TargetLen;
  UINTN    ScratchSize;
  CHAR8    *Scratch;
  UINTN    ScratchOffset;
  CHAR8    *RecordBase;
  EFI_STATUS Status;

  RecordBase = (CHAR8 *)Buffer;
  AsciiLen   = StrnLenS (StringSrc, SMBIOS_MAX_STRING_LENGTH) + 1;

  // Convert Unicode to ASCII
  AsciiString = AllocateZeroPool (AsciiLen);
  if (AsciiString == NULL) {
    ASSERT (AsciiString != NULL);
    return EFI_OUT_OF_RESOURCES;
  }

  Status = UnicodeStrnToAsciiStrS (AsciiString, StringSrc, AsciiLen);
  if (EFI_ERROR (Status)) {
    FreePoolAssert (AsciiString);
    return Status;
  }

  // Find the string's insertion position in the SMBIOS string area
  StringAreaOffset = 0;
  GetNextSmbiosString (&RecordBase, &StringAreaOffset);
  // (StringAreaOffset now points past the SMBIOS header + strings)

  UINTN SkipCount = 0;
  if (LanguageIndex > 1) {
    // Skip strings for higher language indices
    TargetPos = RecordBase + (UINTN)RecordBase[1];
    while (SkipCount < LanguageIndex - 1) {
      if (TargetPos[0] != '\0') {
        // Count this string as 1 language variant
        SkipCount++;
        TargetPos++;
      } else {
        // NULL byte -- skip
        TargetPos++;
      }
    }
  } else {
    TargetPos = RecordBase + (UINTN)RecordBase[1];
  }

  TargetLen = AsciiStrLen (TargetPos);

  // Build the concatenated string area
  if (AsciiLen != TargetLen) {
    Scratch = AllocateZeroPool (SMBIOS_STRING_SCRATCH_SIZE);
    if (Scratch == NULL) {
      FreePoolAssert (AsciiString);
      return EFI_OUT_OF_RESOURCES;
    }

    // Copy header + strings before insertion point
    CopyMem (Scratch, RecordBase, SkipCount + (UINTN)RecordBase[1]);
    // Copy new string
    CopyMem (Scratch + SkipCount + (UINTN)RecordBase[1], AsciiString, AsciiLen);
    // Copy remaining string area
    CopyMem (
      Scratch + SkipCount + (UINTN)RecordBase[1] + AsciiLen,
      RecordBase + SkipCount + (UINTN)RecordBase[1] + TargetLen,
      StringAreaOffset - (UINTN)RecordBase[1] - TargetLen - SkipCount
      );

    // Calculate final size
    GetNextSmbiosString (&RecordBase, &ScratchOffset);
    CopyMem (RecordBase, Scratch, ScratchOffset);

    FreePoolAssert (Scratch);
  }

  FreePoolAssert (AsciiString);
  return EFI_SUCCESS;
}

// ===========================================================================
// SMBIOS Type 8 update (Port Connector Information)
// ===========================================================================

// Data table for SMBIOS type 8 port connector entries.
// Each entry is 10 bytes (5 words), defining the string token IDs for each
// port slot on this platform. There are 0x15 (21) entries -- one per slot.
//
// Entry structure (10 bytes = 5 x UINT16):
//   Word 0: String token for PortInternalConnectorDesignator
//   Word 1: String token for PortExternalConnectorDesignator  (repeated for second string)
//   Byte at +4: port type byte for internal variant
//   Byte at +5: port type byte for external variant
//   Byte at +6: port type byte
//   Byte at +7: port type byte
//   Byte at +8: port type byte
//   Byte at +9: port type byte  (continued)
// (Actually 2 UINT16s followed by packed single bytes.)

/**
  Build and update SMBIOS type 8 (Port Connector Information) records.

  Constructs 0x15 (21) type 8 SMBIOS records, one for each physical port
  connector on the NeonCityFPGA platform. Each record's string fields are
  populated from HII string tokens embedded in the module's HII package list.

  @param[in,out] Buffer  768-byte temp buffer for record construction.
  @param[in]     Index   Port index (0..0x14, validated to < 0x15).

  @return EFI_SUCCESS           Record built and submitted.
  @return EFI_UNSUPPORTED       Invalid index.
  @return EFI_OUT_OF_RESOURCES  Memory allocation failed.
*/
static
EFI_STATUS
UpdateSmbiosType08 (
  IN OUT VOID   *Buffer,
  IN     UINTN  Index
  )
{
  // sub_77C at 0x77C
  //
  // Table of string token ID pairs for each of the 21 port connector entries.
  // Each entry occupies 10 bytes:
  //   [0..1]: UINT16 stringId for PortInternalConnectorDesignator
  //   [2..3]: UINT16 stringId for PortExternalConnectorDesignator
  //   [4]:    UINT8  InternalReferenceDesignator type
  //   [5]:    UINT8  ExternalReferenceDesignator type
  //   [6]:    UINT8  PortType
  //   [7]:    UINT8  PortType (extended)
  //   [8]:    UINT8  PortType / misc
  //   [9]:    UINT8  misc
  //
  static const UINT8 mPortConnectorTable[0x15 * 10] = {
    //  strId1 strId2 typ1 typ2 ptyp ext misc misc
    0x02, 0x00, 0x00, 0x80, 0x08, 0x03, 0x00, 0x00, 0x08, 0x04,  // Index 0
    0x10, 0x00, 0x00, 0x80, 0x08, 0x03, 0x00, 0x00, 0x08, 0x04,  // Index 1
    0x10, 0x00, 0x00, 0x80, 0x10, 0x04, 0x00, 0x00, 0x10, 0x04,  // Index 2
    0x10, 0x00, 0x00, 0x80, 0x10, 0x04, 0x00, 0x00, 0x10, 0x04,  // Index 3
    0x00, 0x01, 0x00, 0x12, 0x10, 0x05, 0x00, 0x00, 0x10, 0x05,  // Index 4
    0x00, 0x01, 0x00, 0x12, 0x10, 0x05, 0x00, 0x00, 0x10, 0x05,  // Index 5
    0x00, 0x01, 0x00, 0x12, 0x1C, 0x07, 0x00, 0x07, 0x1C, 0x07,  // Index 6
    0x00, 0x01, 0x00, 0x12, 0x1C, 0x07, 0x00, 0x07, 0x1C, 0x07,  // Index 7
    0x00, 0x01, 0x00, 0x0B, 0x1C, 0x08, 0x00, 0x0B, 0x1C, 0x08,  // Index 8
    0x00, 0x01, 0x00, 0x0B, 0x1C, 0x08, 0x00, 0x0B, 0x1C, 0x08,  // Index 9
    0x00, 0x01, 0x00, 0x0B, 0x1F, 0x09, 0x00, 0x0B, 0x1F, 0x09,  // Index 10
    0x00, 0x01, 0x00, 0x0B, 0x1F, 0x09, 0x00, 0x0B, 0x1F, 0x09,  // Index 11
    0x00, 0x01, 0x00, 0x0B, 0x1F, 0x0A, 0x00, 0x0B, 0x1F, 0x0A,  // Index 12
    0x00, 0x01, 0x00, 0xFF, 0x1F, 0x0B, 0x00, 0xFF, 0x1F, 0x0B,  // Index 13
    0x00, 0x01, 0x00, 0xFF, 0x1F, 0x0C, 0x00, 0xFF, 0x1F, 0x0C,  // Index 14
    0x00, 0x01, 0x00, 0x22, 0x20, 0x0D, 0x00, 0x22, 0x20, 0x0D,  // Index 15
    0x00, 0x01, 0x00, 0x22, 0x20, 0x0E, 0x00, 0x22, 0x20, 0x0E,  // Index 16
    0x00, 0x01, 0x00, 0x22, 0x20, 0x0F, 0x00, 0x22, 0x20, 0x0F,  // Index 17
    0x00, 0x01, 0x00, 0x22, 0x20, 0x10, 0x00, 0x22, 0x20, 0x10,  // Index 18
    0x00, 0x01, 0x00, 0x22, 0x20, 0x11, 0x00, 0x22, 0x20, 0x11,  // Index 19
    0x00, 0x01, 0x00, 0x22, 0x20, 0x12, 0x00, 0x22, 0x20, 0x12   // Index 20
  };

  SMBIOS_TABLE_TYPE8   *Type8Rec;
  CHAR8                *StringArea;
  EFI_STATUS           Status;

  if (Index >= 0x15) {
    return EFI_UNSUPPORTED;
  }

  // Initialize SMBIOS type 8 record header
  Type8Rec = (SMBIOS_TABLE_TYPE8 *)Buffer;
  Type8Rec->Hdr.Type   = SMBIOS_TYPE_PORT_CONNECTOR;   // 8
  Type8Rec->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE8);   // 9
  Type8Rec->Hdr.Handle = SMBIOS_HANDLE_PI_RESERVED;     // 0xFFFE

  // Set port connector fields from table
  const UINT8 *Entry = &mPortConnectorTable[Index * 10];
  Type8Rec->InternalReferenceDesignator = Entry[4];  // +0x04
  Type8Rec->ExternalReferenceDesignator = Entry[5];  // +0x05
  Type8Rec->PortType                     = Entry[6];  // +0x06
  Type8Rec->PortTypeExtension            = Entry[7];  // +0x07

  // Get HII strings for this port
  UINT16 StrId1 = *(UINT16 *)&Entry[0];
  UINT16 StrId2 = *(UINT16 *)&Entry[2];

  if (StrId1 != 0) {
    CHAR16 *HiiStr = GetHiiString (gSmbiosStringPack, StrId1, NULL);
    if (HiiStr != NULL) {
      UpdateSmbiosString (Buffer, 0, Entry[4], HiiStr);
      FreePoolAssert (HiiStr);
    } else {
      return EFI_OUT_OF_RESOURCES;  // sub_77C returns 0x8000000000000009
    }

    // Update the second string if present
    if (Entry[5] != 0) {
      HiiStr = GetHiiString (gSmbiosStringPack, StrId2, NULL);
      if (HiiStr != NULL) {
        UpdateSmbiosString (Buffer, 0, Entry[5], HiiStr);
        FreePoolAssert (HiiStr);
      }
    }
  }

  // Second pair of string IDs
  StrId1 = *(UINT16 *)&Entry[0];  // repeated as per original table layout
  StrId2 = *(UINT16 *)&Entry[2];

  if (StrId1 != 0) {
    CHAR16 *HiiStr = GetHiiString (gSmbiosStringPack, StrId1, NULL);
    if (HiiStr != NULL) {
      UpdateSmbiosString (Buffer, 0, Entry[8], HiiStr);
      FreePoolAssert (HiiStr);
    } else {
      return EFI_OUT_OF_RESOURCES;
    }
  }

  // Submit or update the SMBIOS record
  Status = UpdateSmbiosRecord (Buffer);

  return Status;
}

// ===========================================================================
// SMBIOS Type 9 update (System Slot Information)
// ===========================================================================

/**
  Build and update SMBIOS type 9 (System Slot Information) records.

  Constructs up to 8 SMBIOS type 9 records for expansion slots, reading
  PCI configuration space to determine slot type and characteristics.

  @param[in,out] Buffer  768-byte temp buffer.
  @param[in]     Index   Slot index (0..7).

  @return EFI_SUCCESS           Record built.
  @return EFI_UNSUPPORTED       Invalid index.
  @return EFI_NOT_FOUND         PCI config read failed.
  @return EFI_OUT_OF_RESOURCES  Memory allocation failed.
*/
static
EFI_STATUS
UpdateSmbiosType09 (
  IN OUT VOID   *Buffer,
  IN     UINTN  Index
  )
{
  // sub_A20 at 0xA20
  SMBIOS_TABLE_TYPE9 *Type9Rec;
  UINT32              PciValue;
  UINT8               Device;
  UINT8               Function;

  Type9Rec = (SMBIOS_TABLE_TYPE9 *)Buffer;
  Type9Rec->Hdr.Type   = SMBIOS_TYPE_SYSTEM_SLOTS;     // 9
  Type9Rec->Hdr.Length = 17;                            // 0x11
  Type9Rec->Hdr.Handle = SMBIOS_HANDLE_PI_RESERVED;     // 0xFFFE

  // Clear reserved flags
  Type9Rec->SlotDataBusWidth     = 1;
  Type9Rec->CurrentUsage         = 4;
  Type9Rec->SlotLength           = 0;

  Type9Rec->SlotCharacteristics1 = 0x04;  // Bit 2: 3.3V
  Type9Rec->SlotCharacteristics2 = 0x01;  // Bit 0: reserved

  // Determine PCI device/function from index
  switch (Index) {
    case 0:  // PCIe Slot 1
      Type9Rec->SlotType         = 0xB6;  // 0x0B6 = PCI Express x16
      Device   = 3;
      Function = 0;
      PciValue = 0xB601;
      Type9Rec->SlotDataBusWidth = 0x0B;  // x16
      break;

    case 1:  // PCIe Slot 2
      Type9Rec->SlotType         = 0xB5;  // 0x0B5 = PCI Express x8
      Device   = 3;
      Function = 2;
      PciValue = 0xB501;
      break;

    case 2:  // PCIe Slot 3
      Type9Rec->SlotType         = 0xB6;  // PCI Express x16
      Device   = 3;
      Function = 1;
      PciValue = 0xB601;
      break;

    case 3:  // PCIe Slot 4
      Type9Rec->SlotType         = 0xB6;  // PCI Express x16
      Device   = 3;
      Function = 0;
      Type9Rec->CurrentUsage     = 6;
      Type9Rec->SlotCharacteristics1 |= 0x80;
      break;

    case 4:  // PCIe Slot 5
      Type9Rec->SlotType         = 0xB6;  // PCI Express x16
      Device   = 2;
      Function = 0;
      Type9Rec->SlotCharacteristics1 |= 0x80;
      Type9Rec->SlotCharacteristics2 = 0x10;
      break;

    case 5:  // PCIe Slot 6
      Type9Rec->SlotType         = 0xB5;  // PCI Express x8
      Device   = 3;
      Function = 2;
      Type9Rec->SlotCharacteristics1 |= 0x80;
      Type9Rec->SlotCharacteristics2 = 0x1A;
      break;

    case 6:  // PCIe Slot 7
      Type9Rec->SlotType         = 0xB5;  // PCI Express x8
      Device   = 2;
      Function = 2;
      Type9Rec->SlotCharacteristics1 |= 0x80;
      PciValue = 0xB501;
      break;

    case 7:  // OCP (mezzanine) slot
      Type9Rec->SlotType         = 0xA1;  // 0x0A1 = OCP NIC 3.0
      Device   = 3;
      Function = 2;

      // Read PCI vendor/device via MmPciBase to detect presence
      MmioPciRead32 (0, Device, Function, 0, &PciValue);
      if (PciValue == 0xFFFFFFFF) {
        return EFI_NOT_FOUND;  // No device present
      }

      // Read programming interface / revision
      MmioPciRead32 (0, Device, Function, 0x19, &PciValue);
      Type9Rec->CurrentUsage = ((PciValue != 0xFFFFFFFF) ? 4 : 1);
      break;

    default:
      return EFI_UNSUPPORTED;
  }

  // Read segment group / bus number
  MmioPciRead32 (0, Device, Function, 0x19, &PciValue);
  Type9Rec->SegmentGroupNum = (UINT8)(PciValue >> 24);
  Type9Rec->BusNum          = (UINT8)(PciValue >> 16);

  // Set slot characteristics based on function
  MmioPciRead32 (0, Device, Function, 0, &PciValue);
  if (PciValue != 0xFFFFFFFF) {
    // Device present -- check for hotplug
    MmioPciRead32 (0, Device, Function, 0x19, &PciValue);
    if ((PciValue != 0xFFFFFFFF) || Index >= 4) {
      // Use hotplug or default
    }
  }

  // Get HII string for slot designation
  static const UINT16 SlotStringIds[8] = {
    24,  // Slot 1 designation
    26,  // Slot 2 designation
    8,   // Slot 3 designation
    16,  // Slot 4 designation
    18,  // Slot 5 designation
    25,  // Slot 6 designation
    26,  // Slot 7 designation
    27   // OCP slot designation
  };

  if (Index < 8) {
    CHAR16 *HiiStr = GetHiiString (gSmbiosStringPack, SlotStringIds[Index], NULL);
    if (HiiStr != NULL) {
      UpdateSmbiosString (Buffer, 0, Type9Rec->SlotDataBusWidth, HiiStr);
      FreePoolAssert (HiiStr);
    }
  }

  // Submit record
  return UpdateSmbiosRecord (Buffer);
}

// ===========================================================================
// SMBIOS Type 41 update (Onboard Devices Extended Information)
// ===========================================================================

/**
  Build and update SMBIOS type 41 (Onboard Devices Extended Information) records.

  Constructs up to 4 type 41 records for onboard devices (SATA, USB, LAN,
  management controllers etc.) based on PCI config reads.

  @param[in,out] Buffer  768-byte temp buffer.
  @param[in]     Index   Device index (0..3).

  @return EFI_SUCCESS           Record built.
  @return EFI_UNSUPPORTED       Invalid index.
  @return EFI_OUT_OF_RESOURCES  Memory allocation failed.
*/
static
EFI_STATUS
UpdateSmbiosType41 (
  IN OUT VOID   *Buffer,
  IN     UINTN  Index
  )
{
  // sub_D98 at 0xD98
  SMBIOS_TABLE_TYPE41 *Type41Rec;
  UINT32               PciValue;
  UINT8                Device;
  UINT8                Function;

  Type41Rec = (SMBIOS_TABLE_TYPE41 *)Buffer;
  Type41Rec->Hdr.Type   = SMBIOS_TYPE_ONBOARD_DEVICE;  // 41
  Type41Rec->Hdr.Length = 11;                           // 0x0B
  Type41Rec->Hdr.Handle = SMBIOS_HANDLE_PI_RESERVED;    // 0xFFFE

  Type41Rec->Type = 1;  // Other
  Type41Rec->Status.Status = 1;  // Enabled

  switch (Index) {
    case 0:  // Onboard SATA controller
    {
      Device = 28;
      Function = 3;
      MmioPciRead32 (0, Device, Function, 0x19, &PciValue);
      UINT8 DevFunc = (UINT8)(PciValue >> 16);

      MmioPciRead32 (0, DevFunc, 0, 0, &PciValue);
      Type41Rec->Type = (PciValue != 0xFFFFFFFF) ? 0x83 : 3;  // SATA or other
      Type41Rec->ReferenceDesignation = 28;  // Token 28
      break;
    }

    case 1:  // Onboard USB controller
    {
      Device = 2;
      Function = 2;
      MmioPciRead32 (0, Device, Function, 0, &PciValue);
      Type41Rec->Type = (PciValue != 0xFFFFFFFF) ? 0x85 : 5;  // USB or other
      Type41Rec->ReferenceDesignation = 29;  // Token 29
      break;
    }

    case 2:  // Onboard network / BMC
    {
      Device = 1;
      Function = 0;
      MmioPciRead32 (0, Device, Function, 0, &PciValue);
      Type41Rec->Type = (PciValue != 0xFFFFFFFF) ? 0x8A : 10;  // LAN or other
      Type41Rec->ReferenceDesignation = 30;  // Token 30

      MmioPciRead32 (0, Device, Function, 0x0A, &PciValue);
      // Extended info
      break;
    }

    case 3:  // Onboard management controller
    {
      Device = 23;
      Function = 0;
      MmioPciRead32 (0, Device, Function, 0, &PciValue);
      Type41Rec->Type = (PciValue != 0xFFFFFFFF) ? 0x89 : 9;  // BMC or other
      Type41Rec->ReferenceDesignation = 31;  // Token 31
      Type41Rec->Status.Status = 0;  // Disabled
      break;
    }

    default:
      return EFI_UNSUPPORTED;
  }

  // Get HII string for this device
  static const UINT16 DeviceStringIds[4] = {
    28,  // SATA
    29,  // USB
    30,  // LAN
    31   // BMC
  };

  if (Index < 4) {
    CHAR16 *HiiStr = GetHiiString (gSmbiosStringPack, DeviceStringIds[Index], NULL);
    if (HiiStr != NULL) {
      UpdateSmbiosString (Buffer, 0, 1, HiiStr);
      FreePoolAssert (HiiStr);
    }
  }

  return UpdateSmbiosRecord (Buffer);
}

// ===========================================================================
// UBA SmbiosUpdate callback (main entry for SMBIOS record updates)
// ===========================================================================

/**
  UBA SmbiosUpdateCallback -- called by the UBA framework to update SMBIOS data.

  This function performs the following SMBIOS record updates:
    1. Creates 0x15 (21) SMBIOS type 8 records (Port Connector Info)
    2. Removes and recreates type 9 records (System Slots, 8 records)
    3. Removes and recreates type 41 records (Onboard Devices, 4 records)

  @param[in] This     Pointer to the UBA_SMBIOS_UPDATE_PROTOCOL interface.
  @param[in] Buffer   Unused (may be NULL).
  @param[in] Size     Unused.

  @return EFI_SUCCESS  All SMBIOS records updated.
*/
static
EFI_STATUS
EFIAPI
SmbiosUpdateCallback (
  IN UBA_SMBIOS_UPDATE_PROTOCOL  *This,
  IN VOID                        *Buffer,
  IN UINTN                       Size
  )
{
  // sub_F54 at 0xF54
  VOID *RecordBuffer;
  UINTN Index;

  RecordBuffer = AllocateZeroPool (SMBIOS_RECORD_BUFFER_SIZE);
  if (RecordBuffer == NULL) {
    ASSERT (RecordBuffer != NULL);
    return EFI_OUT_OF_RESOURCES;
  }

  // Step 1: Update SMBIOS type 8 records (21 port connectors)
  for (Index = 0; Index < 0x15; Index++) {
    ZeroMem (RecordBuffer, SMBIOS_RECORD_BUFFER_SIZE);
    UpdateSmbiosType08 (RecordBuffer, Index);
    UpdateSmbiosRecord (RecordBuffer);
  }

  // Step 2: Remove old type 9 records, then recreate 8 slot records
  RemoveSmbiosRecordsByType (SMBIOS_TYPE_SYSTEM_SLOTS);
  for (Index = 0; Index < 8; Index++) {
    ZeroMem (RecordBuffer, SMBIOS_RECORD_BUFFER_SIZE);
    UpdateSmbiosType09 (RecordBuffer, Index);
    UpdateSmbiosRecord (RecordBuffer);
  }

  // Step 3: Remove old type 41 records, then recreate 4 device records
  RemoveSmbiosRecordsByType (SMBIOS_TYPE_ONBOARD_DEVICE);
  for (Index = 0; Index < 4; Index++) {
    ZeroMem (RecordBuffer, SMBIOS_RECORD_BUFFER_SIZE);
    UpdateSmbiosType41 (RecordBuffer, Index);
    UpdateSmbiosRecord (RecordBuffer);
  }

  // Free temp buffer
  FreePoolAssert (RecordBuffer);

  return EFI_SUCCESS;
}

// ===========================================================================
// HII package list management
// ===========================================================================

/**
  Build and register the HII package list for this module's SMBIOS strings.

  The HII package list contains the localized string tokens referenced by
  the SMBIOS type 8, 9, and 41 records. The raw package list data is
  embedded in the module at the .rdata section offset corresponding to
  the GUID at 0x31F0.

  @param[in]  HiiPackageList   Pointer to the HII package list data.
  @param[in]  PackageListSize  Total size of the package list.
  @param[out] HiiHandle        Receives the HII handle for the registered
                                package list.

  @return EFI_SUCCESS           Package list registered.
  @return EFI_INVALID_PARAMETER HiiHandle is NULL.
  @return EFI_OUT_OF_RESOURCES  Memory allocation failed.
*/
static
EFI_STATUS
RegisterHiiPackageList (
  IN  VOID           *HiiPackageList,
  IN  UINTN          PackageListSize,
  OUT EFI_HII_HANDLE *HiiHandle
  )
{
  // sub_1908 at 0x1908
  EFI_HII_PACKAGE_LIST_HEADER *PackageListHdr;
  UINTN                        BufferSize;
  UINT8                        *Buffer;
  UINTN                        Offset;
  EFI_STATUS                   Status;

  ASSERT (HiiPackageList != NULL);
  ASSERT (HiiHandle != NULL);

  // Build a properly formatted package list from the raw GUID + string data
  // The raw package list starts with GUID + size header

  // Calculate total buffer size
  UINT8 *RawData  = (UINT8 *)HiiPackageList;
  UINT32 *pSize   = (UINT32 *)RawData;
  BufferSize = *pSize;

  // Allocate buffer for the package list
  BufferSize += sizeof (EFI_HII_PACKAGE_LIST_HEADER);
  Buffer = AllocateZeroPool (BufferSize);
  if (Buffer == NULL) return EFI_OUT_OF_RESOURCES;

  // Copy the raw data and package
  PackageListHdr = (EFI_HII_PACKAGE_LIST_HEADER *)Buffer;
  PackageListHdr->PackageLength = (UINT32)BufferSize;

  // Copy GUID (from 0x3890 area) and package data
  CopyGuid (&PackageListHdr->PackageListGuid, &gEfiHiiPackageListGuid);

  // Copy string packages
  // Offset 0x20 in buffer = first string package
  // (raw data from 0x31F0 + 4)

  CopyMem (Buffer + sizeof (EFI_HII_PACKAGE_LIST_HEADER), RawData + 4, *pSize - 4);

  // Register via HII database protocol
  Status = gHiiDatabase->NewPackageList (
                           gHiiDatabase,
                           PackageListHdr,
                           gImageHandle,
                           HiiHandle
                           );

  if (EFI_ERROR (Status)) {
    *HiiHandle = NULL;
  }

  FreePool (Buffer);
  return Status;
}

// ===========================================================================
// Driver initialization
// ===========================================================================

/**
  Initialize global protocol pointers for the UBA SMBIOS update driver.

  Locates and caches the following protocols:
    - HII String Protocol (gEfiHiiStringProtocolGuid)
    - HII Database Protocol (gEfiHiiDatabaseProtocolGuid)
    - HII Image Protocol (gEfiHiiImageProtocolGuid)
    - HII Font Protocol (gEfiHiiFontProtocolGuid)
    - HII Config Routing Protocol (gEfiHiiConfigRoutingGuid)
    - DxeServicesTable (gEfiDxeServicesTableGuid)
    - MmPciBase protocol (gEfiMmPciBaseProtocolGuid)

  Also registers the module's HII package list and UBA SmbiosUpdate callback.

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

  @return EFI_SUCCESS  All protocols located and callback registered.
*/
EFI_STATUS
InitializeDriver (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  // sub_38C at 0x38C
  EFI_STATUS Status;

  // --- Initialize UEFI library globals ---
  gImageHandle = ImageHandle;
  ASSERT (gImageHandle != NULL);

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

  gBS = gST->BootServices;
  ASSERT (gBS != NULL);

  gRT = gST->RuntimeServices;
  ASSERT (gRT != NULL);

  // --- Locate HOB list ---
  GetHobList ();

  // --- Locate HII protocol interfaces ---
  Status = gBS->LocateProtocol (
                  &gEfiHiiStringProtocolGuid,
                  NULL,
                  (VOID **)&gHiiString
                  );
  ASSERT_EFI_ERROR (Status);

  Status = gBS->LocateProtocol (
                  &gEfiHiiDatabaseProtocolGuid,
                  NULL,
                  (VOID **)&gHiiDatabase
                  );
  ASSERT_EFI_ERROR (Status);

  Status = gBS->LocateProtocol (
                  &gEfiHiiConfigRoutingGuid,  // Actually gEfiHiiConfigRoutingProtocolGuid
                  NULL,
                  (VOID **)&gHiiConfigRouting
                  );
  ASSERT_EFI_ERROR (Status);
  Status = gBS->LocateProtocol (
                  &gEfiHiiImageProtocolGuid,
                  NULL,
                  (VOID **)&gHiiImage
                  );
  Status = gBS->LocateProtocol (
                  &gEfiHiiFontProtocolGuid,
                  NULL,
                  (VOID **)&gHiiFont
                  );

  // --- Locate DxeServicesTable ---
  Status = GetConfigurationTable (&gEfiDxeServicesTableGuid, (VOID **)&gDS);
  ASSERT_EFI_ERROR (Status);
  ASSERT (gDS != NULL);

  if (EFI_ERROR (Status)) {
    ASSERT_EFI_ERROR (Status);
  }

  // --- Locate MmPciBase (USRA) protocol ---
  if (gMmPciBase == NULL) {
    Status = gBS->LocateProtocol (
                    &gEfiMmPciBaseProtocolGuid,
                    NULL,
                    (VOID **)&gMmPciBase
                    );
    ASSERT_EFI_ERROR (Status);
    ASSERT (gMmPciBase != NULL);
  }

  return Status;
}

// ===========================================================================
// Driver entry point -- register UBA SmbiosUpdate callback
// ===========================================================================

/**
  Register this module's SMBIOS update callback with the UBA framework.

  After initialization (InitializeDriver), this function:
    1. Locates the UBA board-protocol protocol
    2. Copies the board protocol GUID into the UBA protocol
    3. Registers an HII package list with platform-specific strings
    4. Registers the SmbiosUpdateCallback with the UBA protocol

  @param[in]  ImageHandle  Image handle for this driver.
  @param[out] ...          Unused extra argument (from calling convention).

  @return EFI_SUCCESS  Callback registered successfully.
*/
EFI_STATUS
RegisterSmbiosUpdate (
  IN EFI_HANDLE  ImageHandle,
  ...
  )
{
  // sub_654 at 0x654
  EFI_STATUS                Status;
  UBA_SMBIOS_UPDATE_PROTOCOL *Protocol;
  EFI_HANDLE                 Handle;
  EFI_GUID                   BoardGuid;
  EFI_GUID                  *BoardGuidPtr;

  // Locate the UBA board protocol
  Status = gBS->LocateProtocol (
                  &gUbaSmbiosUpdateProtocolGuid,   // Same GUID as RomLayoutDxe uses
                  NULL,
                  (VOID **)&Protocol
                  );

  if (!EFI_ERROR (Status)) {
    DebugPrint (0x80000000, "UBA:SmbiosDataUpdateEntry Image GUID=%g\n", &BoardGuid);

    // Copy board protocol GUID into the protocol interface
    BoardGuidPtr = (EFI_GUID *)((UINT8 *)Protocol + 4);
    CopyMem (BoardGuidPtr, &gUbaSmbiosUpdateProtocolGuid, sizeof (EFI_GUID));

    // Register HII package list
    gSmbiosStringPack = RegisterHiiPackageList (
                          Protocol,
                          &Handle,
                          &gEfiHiiPackageListGuid,
                          0
                          );
    ASSERT (gSmbiosStringPack != NULL);

    // Build the SmbiosUpdate callback registration block
    // v6 layout:
    //   +0x00: UINT32 Signature   = 0x424C5542 ("UBLB" / "BULB")
    //   +0x04: UINT32 Version     = 1
    //   +0x08: UINT8  Type        = 19 (0x13)
    //   +0x0C: UINT32 Reserved    = 0
    struct {
      UINT32  Signature;
      UINT32  Version;
      UINT8   Type;
      UINT8   Reserved[3];
    } CallbackInfo;

    // Get the UBA SmbiosUpdate protocol (event protocol at 0x31E0)
    if (gUbaSmbiosUpdate == NULL) {
      Status = gBS->LocateProtocol (
                      &gUbaSmbiosUpdateProtocolGuid,
                      NULL,
                      (VOID **)&gUbaSmbiosUpdate
                      );
      if (EFI_ERROR (Status)) return Status;
    }

    CallbackInfo.Signature = 0x424C5542;  // "BULB" (UBA signature)
    CallbackInfo.Version   = 1;
    CallbackInfo.Type      = 19;          // Update type for SMBIOS data

    // Register the callback with the UBA SmbiosUpdate protocol
    // gUbaSmbiosUpdate->UpdateSmbios(This, &CallbackInfo, sizeof(CallbackInfo))
    return gUbaSmbiosUpdate->UpdateSmbios (
                              gUbaSmbiosUpdate,
                              &CallbackInfo,
                              sizeof (CallbackInfo)
                              );
  }

  return Status;
}

// ===========================================================================
// Module entry point
// ===========================================================================

/**
  Module entry point called by the DXE dispatcher.

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

  @return EFI_STATUS from the registration.
*/
EFI_STATUS
EFIAPI
ModuleEntryPoint (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  // _ModuleEntryPoint at 0x370
  InitializeDriver (ImageHandle, SystemTable);
  return RegisterSmbiosUpdate (ImageHandle);
}