Newer
Older
AMI-Aptio-BIOS-Reversed / UsbOcUpdateDxeNeonCityFPGA / UsbOcUpdateDxeNeonCityFPGA.c
@Ajax Dong Ajax Dong 2 days ago 21 KB Init
/**
 * @file UsbOcUpdateDxeNeonCityFPGA.c
 *
 * @brief UsbOcUpdateDxeNeonCityFPGA - UEFI DXE driver for USB over-current
 *        (OC) protection configuration on the NeonCityFPGA platform.
 *
 * MODULE TYPE: DXE Driver (Index 0010 in BIOS FFS)
 * UEFI PHASE:  DXE
 *
 * FLOW SUMMARY:
 *   1. _ModuleEntryPoint() (0x390) initializes UEFI globals, locates the HOB
 *      list via GetHobList(), prints a debug banner, locates the UBA
 *      NeonCityFPGA board-type protocol, and registers USB OC configuration.
 *   2. GetHobList() (0x5F8) scans SystemTable->ConfigurationTable[] for
 *      EFI_HOB_LIST_GUID using IsHobListGuid().
 *   3. DebugPrint() (0x530) resolves the DebugLib protocol, checks the CMOS
 *      debug level, and calls the DebugLib protocol's output function.
 *   4. DebugAssert() (0x5B8) calls the DebugLib protocol's assertion handler.
 *   5. ReadUnaligned64() (0x740) reads a 64-bit value from potentially
 *      unaligned memory with a NULL check.
 *
 * GUIDs (in .data segment):
 *   0xB40 - DebugLib protocol GUID:  36232936-0E76-31C8-A13A-3AF2FC1C3932
 *   0xB50 - UBA Board-Type Protocol: E03E0D46-5263-4845-B0A4-58D57B3177E2
 *   0xB60 - USB OC Config Protocol:  2638009E-3850-4E4B-B05D-042A32DBB9D1
 *   0xB70 - EFI HOB List GUID:       7739F24C-93D7-11D4-9A3A-0090273FC14D
 *
 * USB OC Configuration Data (in .data segment):
 *   0xB80 - UBA_USBOC_CONFIG_DATA header ("PUSB", version 2, size 0x48c)
 *   0xB90 - Table 1: Front panel port-to-OC-pin mapping (16 UINT32 entries)
 *   0xBD0 - Table 2: Rear panel/backplane port-to-OC-pin mapping (20 UINT32)
 *
 * HARDWARE:
 *   - CMOS RTC ports 0x70/0x71: Debug level register at index 0x4B
 *   - MMIO 0xFDAF0490: Board configuration register (fallback for debug level)
 */

#include "UsbOcUpdateDxeNeonCityFPGA.h"

// ============================================================================
// Static (Module-Level) Global Variables
// ===========================================================================/

//
// NOTE: These globals are placed at specific absolute addresses in the binary's
// .data segment. Their names and types match the decompiled references.
//
// Address      Name              Type
// --------     ----              ----
// 0xC30        gST               EFI_SYSTEM_TABLE*     (SystemTable)
// 0xC38        BootServices      EFI_BOOT_SERVICES*    (gBS)
// 0xC40        gImageHandle      EFI_HANDLE            (ImageHandle)
// 0xC48        RuntimeServices   EFI_RUNTIME_SERVICES* (gRT)
// 0xC50        qword_C50         VOID*                 (mDebugProtocol)
// 0xC58        qword_C58         VOID*                 (mHobList)
// 0xC60        byte_C60          UINT8                 (mCmosDebugLevel)
//

static VOID   *mDebugProtocol;     /* qword_C50 at 0xC50 */
static VOID   *mHobList;           /* qword_C58 at 0xC58 */
static UINT8   mCmosDebugLevel;    /* byte_C60 at 0xC60 */

// ============================================================================
// Constant Data (in .rdata and .data sections)
// ===========================================================================/

//
// These constants are embedded in the .data section of the binary. They are
// referenced by absolute address in the compiled code.
//
// EFI_GUID  mDebugProtocolGuid        @ 0xB40 = DEBUGLIB_PROTOCOL_GUID
// EFI_GUID  mUbaBoardTypeProtocolGuid @ 0xB50 = UBA_BOARD_TYPE_PROTOCOL_GUID
// EFI_GUID  mUsbOcConfigProtocolGuid  @ 0xB60 = USBOC_CONFIG_PROTOCOL_GUID
// EFI_GUID  mEfiHobListGuid           @ 0xB70 = HOB_LIST_GUID
//
// The GUID halves used for the optimized comparison in IsHobListGuid() reside
// in the same GUID buffer:
//   UINT64 mEfiHobListGuidFirstHalf  (first  8 bytes of GUID at 0xB70)
//   UINT64 mEfiHobListGuidSecondHalf (second 8 bytes of GUID at 0xB78)
//
// UBA_USBOC_CONFIG_DATA mUsbOcConfigData @ 0xB80
//   Signature:      "PUSB" (0x42535550)
//   Version:        2
//   Size:           0x48c
//   PortToOcPinUsbPort1[16]:  @ 0xB90  Front panel port-OC mapping
//   PortToOcPinUsbPort2[20]:  @ 0xBD0  Rear panel port-OC mapping
//

// ============================================================================
// Local (Forward) Function Declarations
// ===========================================================================/

/**
 * Retrieves the DebugLib protocol interface from gBS, caching the result.
 *
 * Performs a UEFI environment validation check via gBS->AllocatePool and
 * gBS->FreePool, then calls gBS->LocateProtocol() with the DebugLib protocol
 * GUID. The result is cached in mDebugProtocol.
 *
 * @return Pointer to the DebugLib protocol interface, or NULL if unavailable.
 */
STATIC
VOID *
GetDebugProtocol (
  VOID
  );

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

/**
 * Module entry point for UsbOcUpdateDxeNeonCityFPGA.
 *
 * Initializes UEFI global variables (gImageHandle, gST, gBS, gRT), locates the
 * HOB list via GetHobList(), prints a debug banner via DebugPrint(), locates
 * the UBA NeonCityFPGA board-type protocol, and registers the USB OC
 * configuration data by calling the protocol's RegisterUsbOcConfig function.
 *
 * Calling sequence:
 *   1. gImageHandle = ImageHandle         (asserts if NULL)
 *   2. gST = SystemTable                   (asserts if NULL)
 *   3. gBS = SystemTable->BootServices     (asserts if NULL)
 *   4. gRT = SystemTable->RuntimeServices  (asserts if NULL)
 *   5. GetHobList(ImageHandle)             (caches HobList pointer)
 *   6. DebugPrint(DEBUG_INFO, "UBA:UsbOcUpdate-TypeNeonCityFPGA\n")
 *   7. gBS->LocateProtocol(&mUbaBoardTypeProtocolGuid, NULL, &Interface)
 *   8. Interface->RegisterUsbOcConfig(Interface,
 *         &mUsbOcConfigProtocolGuid, &mUsbOcConfigData, sizeof(mUsbOcConfigData))
 *
 * @param[in] ImageHandle  The firmware-allocated handle for this driver image.
 * @param[in] SystemTable  A pointer to the EFI System Table.
 *
 * @return EFI_SUCCESS     The USB OC config protocol was registered.
 * @return Other           Returned directly from LocateProtocol if the UBA
 *                         board-type protocol is not available.
 *
 * @note 0x45a: call [gBS + 0x140] = gBS->LocateProtocol
 * @note 0x481: call [Interface + 0x10] = Interface->RegisterUsbOcConfig
 */
EFI_STATUS
EFIAPI
_ModuleEntryPoint (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS  Status;
  VOID        *Interface;

  //
  // Cache ImageHandle with assertion check.
  //
  gImageHandle = ImageHandle;
  if (ImageHandle == NULL) {
    DebugAssert (
      __FILE__,
      __LINE__,
      "gImageHandle != ((void *) 0)"
      );
  }

  //
  // Cache SystemTable with assertion check.
  //
  gST = SystemTable;
  if (SystemTable == NULL) {
    DebugAssert (
      __FILE__,
      __LINE__,
      "gST != ((void *) 0)"
      );
  }

  //
  // Cache BootServices from SystemTable with assertion check.
  //
  gBS = SystemTable->BootServices;
  if (gBS == NULL) {
    DebugAssert (
      __FILE__,
      __LINE__,
      "gBS != ((void *) 0)"
      );
  }

  //
  // Cache RuntimeServices from SystemTable with assertion check.
  //
  gRT = SystemTable->RuntimeServices;
  if (gRT == NULL) {
    DebugAssert (
      __FILE__,
      __LINE__,
      "gRT != ((void *) 0)"
      );
  }

  //
  // Locate the HOB list from the system configuration table.
  // Required for HOB-based drivers that follow.
  //
  GetHobList (ImageHandle);

  //
  // Print debug banner identifying this driver.
  //
  Interface = NULL;
  DebugPrint (DEBUG_INFO, "UBA:UsbOcUpdate-TypeNeonCityFPGA\n");

  //
  // Locate the UBA NeonCityFPGA board-type protocol.
  // @note 0x45a: call [gBS + 0x140] (gBS->LocateProtocol)
  //   rcx = &mUbaBoardTypeProtocolGuid  (UBA protocol GUID)
  //   rdx = NULL                         (no registration handle)
  //   r8  = &Interface                   (output pointer)
  //
  Status = gBS->LocateProtocol (
                  &mUbaBoardTypeProtocolGuid,
                  NULL,
                  &Interface
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Call the board-type protocol's RegisterUsbOcConfig function at offset 0x10.
  // This registers the USB OC configuration protocol for NeonCityFPGA.
  //
  // @note 0x481: call [Interface + 0x10]
  //   rcx = Interface              (This pointer)
  //   rdx = &mUsbOcConfigProtocolGuid (USB OC config protocol GUID)
  //   r8  = &mUsbOcConfigData      ("PUSB" config data structure)
  //   r9  = sizeof(UBA_USBOC_CONFIG_DATA) = 0x10 (16 bytes for header only)
  //
  // NOTE: The fourth parameter (ConfigDataSize) is 0x10 (16 bytes) on this
  // platform, which covers only the UBA_USBOC_CONFIG_DATA header (Signature +
  // Version + Size). The port mapping tables follow the header in the same
  // structure but the registration function knows the total size from the
  // Size field within the structure.
  //
  return ((UBA_NEONCITYFPGA_BOARD_TYPE_PROTOCOL *)Interface)->RegisterUsbOcConfig (
           Interface,
           &mUsbOcConfigProtocolGuid,
           &mUsbOcConfigData,
           sizeof (UBA_USBOC_CONFIG_DATA)
           );
}

/**
 * Locates the HOB (Hand-Off Block) list from the UEFI System Table's
 * configuration table array.
 *
 * Iterates through SystemTable->ConfigurationTable[] looking for an entry
 * whose VendorGuid matches EFI_HOB_LIST_GUID. The comparison is done by
 * comparing the first 8 bytes and second 8 bytes of the GUID as 64-bit
 * integers via ReadUnaligned64().
 *
 * Results are cached in mHobList. If the HOB list GUID is not found,
 * an ASSERT_EFI_ERROR is raised via DebugPrint and DebugAssert, followed
 * by a second assertion if mHobList is still NULL.
 *
 * @param[in] ImageHandle  Passed through from entry but unused in the loop.
 *
 * @return Pointer to the HOB list, or 0 if not found.
 *
 * @note 0x627: SystemTable->NumberOfTableEntries is at gST + 0x68
 * @note 0x635: SystemTable->ConfigurationTable is at gST + 0x70
 *              Each entry is 0x18 (24) bytes:
 *                +0x00: EFI_GUID VendorGuid (16 bytes)
 *                +0x10: VOID *VendorTable   (8 bytes)
 */
VOID *
GetHobList (
  IN EFI_HANDLE  ImageHandle
  )
{
  UINTN  Index;
  UINTN  TableCount;
  EFI_CONFIGURATION_TABLE  *ConfigTable;

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

  //
  // Initialize HOB list pointer to NULL.
  //
  mHobList = NULL;

  //
  // Get the number of configuration table entries from gST.
  //
  TableCount = gST->NumberOfTableEntries;

  //
  // If there are entries, scan them for EFI_HOB_LIST_GUID.
  //
  if (TableCount > 0) {
    //
    // Get pointer to the configuration table array.
    //
    ConfigTable = gST->ConfigurationTable;

    for (Index = 0; Index < TableCount; Index++) {
      //
      // Compare current entry's VendorGuid against EFI_HOB_LIST_GUID.
      // The comparison splits the 16-byte GUID into two 8-byte halves:
      //   - First 8 bytes  (GUID.Data1 + GUID.Data2 + GUID.Data3 high)
      //   - Second 8 bytes (GUID.Data3 low + GUID.Data4)
      // This matches the EFI_HOB_LIST_GUID: 7739F24C-93D7-11D4-9A3A-0090273FC14D
      //   - First 8 bytes: 0x11D493D77739F24C
      //   - Second 8 bytes: 0x4DC13F2700903A9A
      //
      if (IsHobListGuid (ImageHandle, &ConfigTable[Index].VendorGuid)) {
        //
        // Found the HOB list entry. Extract the VendorTable pointer.
        //
        mHobList = ConfigTable[Index].VendorTable;
        return mHobList;
      }
    }
  }

  //
  // HOB list GUID not found in configuration table.
  // Raise ASSERT_EFI_ERROR with EFI_NOT_FOUND (0x800000000000000E).
  //
  DebugPrint (EFI_NOT_FOUND, "\nASSERT_EFI_ERROR (Status = %r)\n");

  DebugAssert (
    "e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
    54,
    "!EFI_ERROR (Status)"
    );

  //
  // If mHobList is still NULL after the search, raise another assertion.
  //
  if (mHobList == NULL) {
    DebugAssert (
      "e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
      55,
      "mHobList != ((void *) 0)"
      );
  }

  return mHobList;
}

/**
 * Compares a GUID against the EFI_HOB_LIST_GUID by comparing the first 8 bytes
 * and second 8 bytes independently.
 *
 * Instead of a full 16-byte EFI_GUID comparison, this function uses two
 * 8-byte unaligned reads (ReadUnaligned64) to compare the GUID halves.
 * The reference values are the pre-cached first and second 8-byte halves
 * of the EFI_HOB_LIST_GUID in the .data section.
 *
 * @param[in] ImageHandle  Unused parameter (passed for calling convention
 *                         compatibility with the UBA protocol interface).
 * @param[in] GuidPtr      Pointer to the EFI_GUID to compare.
 *
 * @retval TRUE   The GUID at GuidPtr matches EFI_HOB_LIST_GUID.
 * @retval FALSE  The GUID does not match.
 */
BOOLEAN
IsHobListGuid (
  IN EFI_HANDLE  ImageHandle,
  IN EFI_GUID    *GuidPtr
  )
{
  //
  // Compare first 8 bytes of the GUID.
  // The reference value is the first 8 bytes of the EFI_HOB_LIST_GUID
  // stored in the .data section at offset 0xB70 (mEfiHobListGuidFirstHalf).
  //
  if (ReadUnaligned64 (&mEfiHobListGuidFirstHalf) != ReadUnaligned64 (GuidPtr)) {
    return FALSE;
  }

  //
  // Compare second 8 bytes of the GUID.
  // GuidPtr + 8 points to the second half of the 16-byte GUID structure.
  //
  return ReadUnaligned64 (&mEfiHobListGuidSecondHalf) == ReadUnaligned64 ((UINT8 *)GuidPtr + 8);
}

/**
 * Debug print function.
 *
 * Resolves the DebugLib protocol interface via GetDebugProtocol(), checks the
 * CMOS debug level to determine if the requested error level is enabled, and
 * if so, calls the DebugLib protocol's output function (first function pointer
 * at offset 0x00 of the protocol interface).
 *
 * The CMOS debug level is read from RTC CMOS register 0x4B:
 *   - Register index is set to 0x4B (preserving bit 7 for NMI enable)
 *   - Values 0-3 mean level 4 (DEBUG_INFO) for the mask
 *   - Value 0 with a special board config at MMIO 0xFDAF0490 uses
 *     (register & 2) | 1 instead (board configuration check)
 *   - Otherwise the raw value - 1 determines the level:
 *       level 1 -> mask 0x80000004 (DEBUG_INIT | DEBUG_INFO)
 *       level >1 -> mask 0x80000046 (extended debug flags)
 *
 * @param[in] ErrorLevel  The debug error level mask to check.
 * @param[in] Format      A format string for the debug message.
 * @param[in] ...         Variable arguments for the format string.
 *
 * @return The return value from the DebugLib protocol's output function,
 *         or 0 if the protocol is not available or the error level is masked.
 *
 * @note 0x55b: in al, 0x70  -- read current CMOS index
 * @note 0x560: out 0x70, al -- write CMOS index (set reg 0x4B)
 * @note 0x565: in al, 0x71  -- read value from CMOS data port
 * @note 0x582: MMIO read at 0xFDAF0490 (board config fallback)
 */
UINTN
EFIAPI
DebugPrint (
  IN UINTN       ErrorLevel,
  IN CONST CHAR8 *Format,
  ...
  )
{
  UINTN   ReturnValue;
  UINT8   CmosValue;
  UINT8   DebugLevel;
  UINT32  DebugMask;
  VOID    *DebugProtocol;
  VA_LIST VaList;

  VA_START (VaList, Format);

  //
  // Get the DebugLib protocol interface (cached, or resolved lazily).
  //
  DebugProtocol = GetDebugProtocol ();
  ReturnValue = 0;

  if (DebugProtocol != NULL) {
    //
    // Read debug level from CMOS register 0x4B.
    // Access RTC CMOS ports 0x70/0x71:
    //   Port 0x70 = CMOS index/address register
    //   Port 0x71 = CMOS data register
    //
    // Read current CMOS index register value, mask off NMI enable bit (bit 7)
    // and certain control bits (mask 0xCB), set the register address to 0x4B.
    //
    // @note 0x55b: in al, 0x70  -- io_read8(RTC_INDEX_PORT)
    // @note 0x55d: and al, 0xCB -- preserve NMI bit, clear bits 2,4,5
    // @note 0x55f: or al, 0x4B  -- select CMOS register 0x4B
    // @note 0x561: out 0x70, al -- io_write8(RTC_INDEX_PORT, value)
    // @note 0x566: in al, 0x71  -- io_read8(RTC_DATA_PORT)
    //
    CmosValue = IoRead8 (RTC_INDEX_PORT);
    CmosValue = (CmosValue & 0xCB) | CMOS_DEBUG_LEVEL_REGISTER;
    IoWrite8 (RTC_INDEX_PORT, CmosValue);

    //
    // Read the debug level value from CMOS data port.
    //
    DebugLevel = IoRead8 (RTC_DATA_PORT);

    //
    // Determine the debug mask based on the CMOS value.
    //
    if (DebugLevel > 3) {
      //
      // For values > 3, check the cached CMOS debug level (byte_C60 at 0xC60).
      // If the cached level is 0, fall through to the board config check.
      //
      DebugLevel = mCmosDebugLevel;
      if (DebugLevel == 0) {
        //
        // Read board configuration from MMIO register 0xFDAF0490.
        // This is a platform-specific register that indicates the board type
        // or configuration variant.
        //
        // @note 0x582: mov ecx, [0xFDAF0490] -- read board config register
        // @note 0x588: and cl, 2              -- isolate bit 1
        // @note 0x58b: or cl, 1               -- set bit 0 (always 1)
        // Result: (board_config & 2) | 1
        //
        DebugLevel = (*(volatile UINT32 *)BOARD_CONFIG_MMIO_ADDR & 2) | 1;
      }
    }

    //
    // Calculate the debug mask from the debug level.
    // level - 1 must be <= 0xFD (i.e., level >= 1 and level < 0xFF).
    //
    if ((DebugLevel > 0) && ((DebugLevel - 1) <= 0xFD)) {
      //
      // Level 1 -> mask = 0x80000004 (DEBUG_INIT | DEBUG_INFO)
      // Level >1 -> mask = 0x80000046 (multiple debug flags)
      //
      // @note 0x593: mov r8d, 0x80000046   (level > 1 mask)
      // @note 0x599: cmovz r8d, 0x80000004 (level == 1 mask, zero from sub)
      //
      if (DebugLevel == 1) {
        DebugMask = 0x80000004;
      } else {
        DebugMask = 0x80000046;
      }

      //
      // Check if the requested ErrorLevel is enabled by the mask.
      //
      if ((DebugMask & ErrorLevel) != 0) {
        //
        // Call the DebugLib protocol's DebugPrint function.
        // @note 0x5af: call [r9] -- call protocol interface + 0x00
        //
        ReturnValue = ((DEBUGLIB_PROTOCOL *)DebugProtocol)->DebugPrint (
                       ErrorLevel,
                       Format,
                       VaList
                       );
      }
    }
  }

  return ReturnValue;
}

/**
 * ASSERT assertion failure handler.
 *
 * Resolves the DebugLib protocol via GetDebugProtocol() and calls its
 * assertion failure handler function at offset 0x08 in the protocol interface.
 *
 * The assertion handler takes:
 *   rcx = FileName    (source file name)
 *   rdx = LineNumber  (line in source file)
 *   r8  = Description (assertion description string)
 *
 * @param[in] FileName     Source file name where the assertion occurred.
 * @param[in] LineNumber   Line number of the assertion.
 * @param[in] Description  Description of the failed assertion.
 *
 * @return Result from the DebugLib protocol's DebugAssert function,
 *         or 0 if the protocol is not available.
 *
 * @note 0x5e3: call [result + 8] -- call DebugLib protocol's Assert function
 */
UINTN
DebugAssert (
  IN CONST CHAR8  *FileName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *Description
  )
{
  VOID   *DebugProtocol;
  UINTN  Result;

  DebugProtocol = GetDebugProtocol ();
  Result = 0;

  if (DebugProtocol != NULL) {
    Result = ((DEBUGLIB_PROTOCOL *)DebugProtocol)->DebugAssert (
              FileName,
              LineNumber,
              Description
              );
  }

  return Result;
}

/**
 * Retrieves the DebugLib protocol interface from gBS, caching the result.
 *
 * Allocates a boot services data buffer (pool type = EfiBootServicesData = 0x1F)
 * using gBS->AllocatePool (BootServices + 0x18) and immediately frees it with
 * gBS->FreePool (BootServices + 0x20).
 *
 * This allocation/free cycle serves as a UEFI environment validation check:
 * if the allocation succeeds and the returned buffer address is <= 0x10,
 * it indicates a valid UEFI environment. Otherwise NULL is returned.
 *
 * Then calls gBS->LocateProtocol() (BootServices + 0x140) to obtain the
 * DebugLib protocol interface. The result is cached in mDebugProtocol.
 *
 * @return Pointer to the DebugLib protocol interface, or NULL if unavailable
 *         or if the pool check indicates an invalid UEFI environment.
 *
 * @note 0x4df: call [BootServices + 0x18] = gBS->AllocatePool
 * @note 0x4e2: call [BootServices + 0x20] = gBS->FreePool
 * @note 0x506: call [BootServices + 0x140] = gBS->LocateProtocol
 */
STATIC
VOID *
GetDebugProtocol (
  VOID
  )
{
  VOID        *Buffer;
  EFI_STATUS  Status;

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

  //
  // Allocate a small pool buffer (EfiBootServicesData = 0x1F = 31) and free it.
  // This is a UEFI environment validation check: if the allocation succeeds
  // and the buffer address is within a reasonable range (<= 0x10), proceed.
  // On minimal or non-UEFI environments, the allocation may behave differently.
  //
  Buffer = NULL;
  gBS->AllocatePool (EfiBootServicesData, 0, &Buffer);
  gBS->FreePool (Buffer);

  if ((UINTN)Buffer <= 0x10) {
    //
    // The buffer size check validates we are in a functioning UEFI environment.
    // Locate the DebugLib protocol using its GUID in the .data section.
    //
    Status = gBS->LocateProtocol (
                  &mDebugProtocolGuid,
                  NULL,
                  &mDebugProtocol
                  );
    if (EFI_ERROR (Status)) {
      mDebugProtocol = NULL;
    }
  } else {
    mDebugProtocol = NULL;
  }

  return mDebugProtocol;
}

/**
 * Reads an unaligned 64-bit value from memory.
 *
 * Wraps the BaseLib ReadUnaligned64() function with a NULL pointer check.
 * If the Buffer pointer is NULL, raises an assertion via DebugAssert.
 *
 * @param[in] Buffer  Pointer to the memory to read. Must not be NULL.
 *
 * @return The 64-bit value read from the given address.
 *
 * @note 0x752: if Buffer is NULL, calls DebugAssert at BaseLib\Unaligned.c:192
 * @note 0x769: return *(_QWORD *)Buffer (simple unaligned dereference)
 */
UINT64
ReadUnaligned64 (
  IN CONST VOID  *Buffer
  )
{
  if (Buffer == NULL) {
    DebugAssert (
      "e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
      192,
      "Buffer != ((void *) 0)"
      );
  }

  return *(volatile UINT64 *)Buffer;
}