Newer
Older
AMI-Aptio-BIOS-Reversed / OpromUpdateDxeLightningRidgeEXECB4 / OpromUpdateDxeLightningRidgeEXECB4.c
@Ajax Dong Ajax Dong 2 days ago 21 KB Init
/**
 * @file OpromUpdateDxeLightningRidgeEXECB4.c
 *
 * @brief OpromUpdateDxeLightningRidgeEXECB4 - UEFI DXE driver implementation.
 *        UBA board-type driver for Lightning Ridge EXEC B4 PCIe OpROM update
 *        stub configuration (no OpROM updates supported on this platform).
 *
 * This driver registers a minimal stub OpROM update configuration with the
 * UBA (Unified Board Architecture) framework. Unlike the EXEC B1/B2/B3 variants
 * which provide full callback-based PCIe OpROM configuration tables, the EXEC B4
 * platform registers a single callback that returns EFI_UNSUPPORTED for all
 * operations, indicating that this platform does not support PCIe OpROM updates.
 *
 * ADDRESS RANGE: 0x2C0 - 0x760 (code segment, 0x4A0 bytes)
 * ENTRY POINT:   _ModuleEntryPoint at 0x390
 * TOTAL FUNCTIONS: 8
 *
 * FUNCTION INDEX
 *   _ModuleEntryPoint  (0x390) - Driver entry point
 *   OpromOperationUnsupported (0x48C) - Stub callback returning EFI_UNSUPPORTED
 *   GetDebugLibProtocol (0x498) - Resolve DebugLib/OpROM protocol interface
 *   DebugPrint          (0x518) - Debug output via DebugLib protocol
 *   DebugAssert         (0x5A0) - Assertion failure handler
 *   GetHobList          (0x5E0) - Locate HOB list from system table
 *   IsHobListGuid       (0x6B8) - Compare GUID against HOB list GUID
 *   ReadUnaligned64     (0x728) - Unaligned 64-bit memory read
 */

#include "OpromUpdateDxeLightningRidgeEXECB4.h"

#include <stdarg.h>    // va_list, va_start, va_end
#include <stddef.h>    // NULL

// ============================================================================
// Platform I/O Intrinsics (MSVC __inbyte / __outbyte replacements)
// ============================================================================

#if defined(__GNUC__) || defined(__clang__)

static __inline__
UINT8
__inbyte (
  UINT16  Port
  )
{
  UINT8  Value;
  __asm__ __volatile__ ("inb %1, %0" : "=a" (Value) : "d" (Port));
  return Value;
}

static __inline__
VOID
__outbyte (
  UINT16  Port,
  UINT8   Value
  )
{
  __asm__ __volatile__ ("outb %0, %1" : : "a" (Value), "d" (Port));
}

#endif

// ============================================================================
// Embedded Binary Data (GUIDs and Protocol Interface)
// ============================================================================

///
/// GUID storage block at 0xB40 in .data.
/// Contains GUIDs used by the driver.
///
static CONST UINT8  GuidBlock[0x40] = {
  //
  // [0x00] DEBUG_LIB_PROTOCOL_GUID
  // {36232936-0E76-31C8-A13A-3AF2FC1C3932}
  //
  0x36, 0x29, 0x23, 0x36, 0x76, 0x0E, 0xC8, 0x31,
  0xA1, 0x3A, 0x3A, 0xF2, 0xFC, 0x1C, 0x39, 0x32,
  //
  // [0x10] UBA_LIGHTNING_RIDGE_EXEC_B4_BOARD_TYPE_PROTOCOL_GUID
  // {E03E0D46-5263-4845-B0A4-58D57B3177E2}
  //
  0x46, 0x0D, 0x3E, 0xE0, 0x63, 0x52, 0x45, 0x48,
  0xB0, 0xA4, 0x58, 0xD5, 0x7B, 0x31, 0x77, 0xE2,
  //
  // [0x20] EFI_HOB_LIST_GUID
  // {7739F24C-93D7-11D4-9A3A-0090273FC14D}
  //
  0x4C, 0xF2, 0x39, 0x77, 0xD7, 0x93, 0xD4, 0x11,
  0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D,
  //
  // [0x30] OPROM_UPDATE_PROTOCOL_REGISTRATION_GUID
  // {CD1F9574-DD03-4196-96AD-4965146F9665}
  //
  0x74, 0x95, 0x1F, 0xCD, 0x03, 0xDD, 0x96, 0x41,
  0x96, 0xAD, 0x49, 0x65, 0x14, 0x6F, 0x96, 0x65,
};

///
/// OpROM update stub protocol interface data block (at 0xB80 in .data).
/// This structure serves as the registered protocol interface.
/// It starts with a signature/header ("PSET") followed by a callback pointer.
///
/// Layout (24 bytes):
///   +0x00: 0x0000000154455350 = "PSET" signature + version 1
///   +0x08: Callback pointer to OpromOperationUnsupported (0x48C)
///   +0x10: Reserved / second copy of callback pointer (0x48C)
///
static CONST UINT8  OpromUpdateProtocolData[OPROM_UPDATE_PROTOCOL_DATA_SIZE] = {
  0x50, 0x53, 0x45, 0x54,  // "PSET" signature
  0x01, 0x00, 0x00, 0x00,  // Version = 1
  0x8C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Callback -> sub_48C (0x48C)
  0x8C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Reserved / second copy -> sub_48C
};

// ============================================================================
// Global Variables (.data segment)
// ============================================================================

///
/// Cached pointer to the OpROM update protocol interface.
/// Resolved once by GetDebugLibProtocol() and reused thereafter.
///
static VOID   *gOpromUpdateProtocol = NULL;

///
/// Cached pointer to the HOB (Hand-Off Block) list.
/// Resolved once by GetHobList() and reused thereafter.
///
VOID   *gHobList = NULL;

// ============================================================================
// Stub Callback Implementation
// ============================================================================

/**
 * Stub OpROM operation callback.
 *
 * This is the only callback registered by the EXEC B4 platform.
 * It returns EFI_UNSUPPORTED (0x800000000000000E), indicating that
 * OpROM updates are not supported on this platform variant.
 *
 * Unlike the EXEC B1/B2/B3 variants which provide full configuration
 * tables with 4 callbacks (GetConfigA/B/C, SetPcieSlotNumber), the
 * EXEC B4 platform simply reports "unsupported" for any OpROM update
 * request.
 *
 * @return EFI_UNSUPPORTED  Always returns 0x800000000000000E.
 */
EFI_STATUS
OpromOperationUnsupported (
  VOID
  )
{
  return OPROM_UNSUPPORTED;
}

// ============================================================================
// Protocol Resolution
// ============================================================================

/**
 * Locates the DebugLib protocol interface and initializes the OpROM update
 * stub interface.
 *
 * This function performs the following:
 *   1. Allocates pool memory for the OpROM update protocol interface.
 *   2. Initializes the interface with the stub callback pointer.
 *   3. Locates the DebugLib protocol via gBS->LocateProtocol() using the
 *      DebugLib GUID (36232936-0E76-31C8-A13A-3AF2FC1C3932).
 *   4. Caches the result in gOpromUpdateProtocol.
 *
 * The DebugLib protocol interface is a structure with functions at offsets
 * 0x00 and 0x08 (relative to the interface pointer).
 *   - Offset 0x00: Debug output function
 *   - Offset 0x08: Debug assertion handler
 *
 * If gBS->LocateProtocol() fails, gOpromUpdateProtocol is set to NULL.
 *
 * @return Pointer to the OpROM update protocol interface, or NULL on failure.
 */
VOID *
GetDebugLibProtocol (
  VOID
  )
{
  //
  // Check if protocol was already resolved.
  //
  if (gOpromUpdateProtocol != NULL) {
    return gOpromUpdateProtocol;
  }

  //
  // Allocate pool for the protocol interface.
  // The pool type used corresponds to memory type 31 (implementation-specific
  // allocation type for UBA protocol interfaces).
  // AllocatePool signature: (PoolType, Size, Buffer).
  //
  (*gBS->AllocatePool)(31, sizeof(OPROM_UPDATE_PROTOCOL_STUB_INTERFACE), &gOpromUpdateProtocol);

  //
  // Initialize the protocol interface with the single callback pointer.
  //
  if (gOpromUpdateProtocol != NULL) {
    ((OPROM_UPDATE_PROTOCOL_STUB_INTERFACE *)gOpromUpdateProtocol)->OpromOperation = OpromOperationUnsupported;
  }

  //
  // Locate the DebugLib protocol using gBS->LocateProtocol().
  // If the protocol cannot be located (e.g., not yet installed), set the
  // cached pointer to NULL so the caller can handle gracefully.
  //
  if (EFI_ERROR((*gBS->LocateProtocol)((EFI_GUID *)&GuidBlock[0x00], NULL, &gOpromUpdateProtocol))) {
    gOpromUpdateProtocol = NULL;
  }

  return gOpromUpdateProtocol;
}

// ============================================================================
// Debug Output
// ============================================================================

/**
 * Debug print function.
 *
 * Resolves the DebugLib protocol via GetDebugLibProtocol() and calls its
 * debug output function if the current debug level matches the requested
 * severity mask.
 *
 * Debug level determination:
 *   The platform type is determined by reading CMOS register 0x4B:
 *     1. Read CMOS index 0x4B (preserving bit 7 - NMI disable bit).
 *     2. If the value is > 3, use the value directly.
 *     3. If the value is 0, fall back to MMIO register 0xFDAF0490
 *        (read bit 1, OR with 1).
 *     4. Platform type = (value - 1).
 *        - Type 1: Lightning Ridge EXEC B4 (enables DEBUG_INFO output)
 *        - Other types: Different platform variant
 *
 * Debug output is only emitted when:
 *   - A valid DebugLib protocol interface is available, AND
 *   - The platform type matches, AND
 *   - The ErrorLevel mask matches (DEBUG_INFO = 0x80000000)
 *
 * @param[in] ErrorLevel  Debug severity mask (e.g., DEBUG_INFO = 0x80000000).
 * @param[in] Format      Printf-style format string.
 * @param[in] ...         Variable arguments for the format string.
 *
 * @return Result from the DebugLib output function, or 0 on failure.
 */
UINTN
EFIAPI
DebugPrint (
  IN UINTN       ErrorLevel,
  IN CONST CHAR8 *Format,
  ...
  )
{
  VOID    *Protocol;
  UINTN   Result;
  UINT8   CmosValue;
  UINT8   PlatformType;
  UINTN   ErrorMask;

  Result = 0;

  //
  // Resolve the DebugLib/OpROM protocol interface.
  //
  Protocol = GetDebugLibProtocol ();
  if (Protocol == NULL) {
    return Result;
  }

  //
  // Determine platform type from CMOS register 0x4B.
  // Read the CMOS register using port I/O instructions.
  //
  CmosValue = __inbyte (RTC_INDEX_PORT);
  __outbyte (RTC_INDEX_PORT, (CmosValue & ~DEBUG_CMOS_MASK) | CMOS_DEBUG_LEVEL_REGISTER);
  PlatformType = __inbyte (RTC_DATA_PORT);

  //
  // Validate platform type. If > 3, use as-is.
  // If == 0, fall back to MMIO register at 0xFDAF0490.
  //
  if (PlatformType > 3) {
    // PlatformType is valid as-is
  } else if (PlatformType == 0) {
    PlatformType = (*(volatile UINT8 *)BOARD_CONFIG_MMIO_ADDR & 2) | 1;
  } else {
    // Platform type 1..3 = valid
  }

  //
  // Check if the platform type matches the Lightning Ridge EXEC B4 type.
  // (PlatformType - 1) is computed; if <= 0xFD, the type is valid.
  //
  if ((PlatformType - 1) <= 0xFD) {
    //
    // Build the error mask for this platform:
    // - Type 1 (Lightning Ridge): ErrorMask = 0x80000004
    // - Type 2 (other):            ErrorMask = 0x80000006
    //
    if (PlatformType == OPROM_PLATFORM_TYPE_LIGHTNING_RIDGE) {
      ErrorMask = 0x80000004;
    } else {
      ErrorMask = 0x80000006;
    }

    //
    // If the requested ErrorLevel matches the platform's error mask,
    // call the DebugLib protocol's output function (at offset 0x00).
    //
    if ((ErrorMask & ErrorLevel) != 0) {
      //
      // Invoke the debug output function.
      // Parameters: Protocol, ErrorLevel, Format.
      // Note: The original binary passes a va_list as the 4th argument by
      // directly pointing to the stack location after Format. In the actual
      // UEFI DebugLib implementation, this is the DebugVPrint function.
      //
      ((UINTN (*)(VOID *, UINTN, CONST CHAR8 *))Protocol)(Protocol, ErrorLevel, Format);
    }
  }

  return Result;
}

// ============================================================================
// Assertion Handler
// ============================================================================

/**
 * ASSERT assertion failure handler.
 *
 * Called when a runtime assertion fails. This function is invoked by the
 * ASSERT() macro when its condition evaluates to FALSE.
 *
 * The handler resolves the DebugLib protocol and calls its assertion
 * handler function at offset 0x08 in the protocol interface.
 *
 * @param[in] FileName     Source file name where the assertion failed.
 * @param[in] LineNumber   Line number of the assertion.
 * @param[in] Description  Description of the assertion that failed.
 *
 * @return 0 if the DebugLib protocol is not available, otherwise the
 *         return value from the protocol's assertion handler.
 */
UINTN
DebugAssert (
  IN CONST CHAR8  *FileName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *Description
  )
{
  VOID   *Protocol;
  UINTN  Result;

  Result = 0;

  //
  // Resolve the DebugLib protocol interface.
  //
  Protocol = GetDebugLibProtocol ();
  if (Protocol != NULL) {
    //
    // Call the assertion handler function at offset 0x08 in the
    // protocol interface. The assertion handler is accessed via pointer
    // arithmetic on the raw protocol interface.
    //
    { UINTN (*AssertFn)(VOID *, CONST CHAR8 *, UINTN, CONST CHAR8 *);
      AssertFn = *(UINTN (**)(VOID *, CONST CHAR8 *, UINTN, CONST CHAR8 *))((UINT8 *)Protocol + 8);
      Result = AssertFn (Protocol, FileName, LineNumber, Description);
    }
  }

  return Result;
}

// ============================================================================
// HOB List Management
// ============================================================================

/**
 * Locates the HOB (Hand-Off Block) list from the UEFI System Table's
 * configuration table array.
 *
 * Iterates through the configuration table array looking for a table whose
 * VendorGuid matches EFI_HOB_LIST_GUID. The HOB list contains system
 * initialization information passed from PEI to DXE, including PCI resource
 * allocation data.
 *
 * The function performs the following:
 *   1. Checks the cached gHobList first; if already resolved, returns it.
 *   2. Iterates through SystemTable->ConfigurationTable[] entries.
 *   3. For each entry, calls IsHobListGuid() to check if the VendorGuid matches.
 *   4. When found, caches the table pointer in gHobList.
 *   5. If not found and no configuration tables exist, triggers an assertion
 *      via DebugAssert() with the message "!EFI_ERROR (Status)".
 *   6. If gHobList remains NULL after the search, triggers an assertion
 *      with the message "mHobList != ((void *) 0)".
 *
 * Results are cached globally in gHobList so subsequent calls are fast.
 *
 * @param[in] ImageHandle  The driver image handle (not directly used).
 *
 * @return Pointer to the HOB list, or NULL if the HOB list GUID was not
 *         found in the system configuration table.
 */
VOID *
GetHobList (
  IN EFI_HANDLE  ImageHandle
  )
{
  UINTN                   Index;
  UINTN                   TableCount;
  EFI_CONFIGURATION_TABLE *ConfigTable;

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

  //
  // Initialize and iterate through configuration tables.
  //
  gHobList = NULL;
  TableCount = gST->NumberOfTableEntries;
  ConfigTable = gST->ConfigurationTable;

  if (TableCount > 0) {
    //
    // Walk the configuration table array.
    // Each entry is 24 bytes (sizeof(EFI_CONFIGURATION_TABLE)).
    //
    for (Index = 0; Index < TableCount; Index++) {
      //
      // Check if this table's VendorGuid matches EFI_HOB_LIST_GUID.
      //
      if (IsHobListGuid (NULL, &ConfigTable[Index].VendorGuid)) {
        gHobList = ConfigTable[Index].Table;
        break;
      }
    }
  }

  //
  // If no HOB list was found, trigger assertion failure.
  //
  if (gHobList == NULL) {
    DebugPrint (DEBUG_INFO, "\nASSERT_EFI_ERROR (Status = %r)\n", 0x800000000000000EULL);
    DebugAssert (
      "e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
      54,
      "!EFI_ERROR (Status)"
      );
    DebugAssert (
      "e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
      55,
      "mHobList != ((void *) 0)"
      );
  }

  return gHobList;
}

/**
 * Compares a GUID against the EFI_HOB_LIST_GUID.
 *
 * Performs the comparison as two 64-bit unaligned reads:
 *   Compare first 8 bytes of the GUID against the expected first half
 *   (stored at GuidBlock + 0x20, i.e., the EFI_HOB_LIST_GUID in the block).
 *   Compare second 8 bytes of the GUID against the expected second half
 *   (stored at GuidBlock + 0x28).
 *
 * Both halves must match for the GUID to be considered equal.
 *
 * @param[in] ImageHandle  Unused parameter (for compatibility with entry point
 *                         signature; value is ignored).
 * @param[in] GuidPtr      Pointer to the 16-byte EFI_GUID to compare.
 *
 * @retval TRUE   The GUID matches EFI_HOB_LIST_GUID.
 * @retval FALSE  The GUID does not match.
 */
BOOLEAN
IsHobListGuid (
  IN EFI_HANDLE  ImageHandle,
  IN EFI_GUID    *GuidPtr
  )
{
  UINT64  GuidFirstHalf;
  UINT64  GuidSecondHalf;
  UINT64  ExpectedFirstHalf;
  UINT64  ExpectedSecondHalf;

  //
  // Read the expected GUID halves from the GUID storage block.
  // The EFI_HOB_LIST_GUID is stored at GuidBlock + 0x20.
  //
  ExpectedFirstHalf  = ReadUnaligned64 (&GuidBlock[0x20]);
  ExpectedSecondHalf = ReadUnaligned64 (&GuidBlock[0x28]);

  //
  // Read the target GUID as two 64-bit halves.
  //
  GuidFirstHalf  = ReadUnaligned64 (GuidPtr);
  GuidSecondHalf = ReadUnaligned64 ((UINT8 *)GuidPtr + 8);

  //
  // Both halves must match.
  //
  return (GuidFirstHalf == ExpectedFirstHalf) && (GuidSecondHalf == ExpectedSecondHalf);
}

// ============================================================================
// Utility Functions
// ============================================================================

/**
 * Reads an unaligned 64-bit value from memory.
 *
 * Performs a NULL pointer check. If Buffer is NULL, an assertion is
 * triggered via DebugAssert() with the message "Buffer != ((void *) 0)".
 *
 * On valid input, reads 8 bytes from the given address and returns them
 * as a 64-bit integer. The read is performed as a direct memory access
 * (the platform supports unaligned access).
 *
 * @param[in] Buffer  Pointer to the 8-byte value to read. Must not be NULL.
 *
 * @return The 64-bit value at the given memory address.
 */
UINT64
ReadUnaligned64 (
  IN CONST VOID  *Buffer
  )
{
  //
  // Validate Buffer is not NULL.
  //
  if (Buffer == NULL) {
    DebugAssert (
      "e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
      192,
      "Buffer != ((void *) 0)"
      );
  }

  //
  // Read 8 bytes from the buffer as a 64-bit value.
  // Cast to volatile to prevent compiler optimizations from re-ordering
  // or combining the access.
  //
  return *(CONST UINT64 *)Buffer;
}

// ============================================================================
// Module Entry Point
// ============================================================================

/**
 * Module entry point for OpromUpdateDxeLightningRidgeEXECB4.
 *
 * DXE driver entry point called by the UEFI Boot Manager when this driver
 * image is loaded and dispatched.
 *
 * Entry point flow:
 *   1. Cache global variables: ImageHandle, SystemTable, BootServices,
 *      RuntimeServices (standard UefiBootServicesTableLib initialization).
 *   2. Locate HOB list via GetHobList() to ensure PCI enumeration data
 *      is available.
 *   3. Log debug banner: "UBA:SETUPConfigUpdate-TypeLightningRidgeEXECB4\n"
 *      via DebugPrint().
 *   4. Locate the UBA Lightning Ridge EXEC B4 board-type protocol via
 *      gBS->LocateProtocol() using GUID E03E0D46-5263-4845-B0A4-58D57B3177E2.
 *   5. Call the protocol's registration function (at offset 0x10 within
 *      the protocol interface) to register the OpROM update stub config.
 *   6. The registration function receives:
 *      - The protocol interface
 *      - The registration GUID (CD1F9574-DD03-4196-96AD-4965146F9665)
 *      - The OpROM update stub protocol data block
 *      - Size: 24 bytes (0x18)
 *
 * @param[in] ImageHandle  The firmware-allocated handle for this driver image.
 * @param[in] SystemTable  A pointer to the EFI System Table.
 *
 * @return EFI_SUCCESS           Registration succeeded.
 * @return EFI_INVALID_PARAMETER ImageHandle or SystemTable is NULL.
 * @return EFI_NOT_FOUND         The UBA board-type protocol could not be located.
 * @return Other                 Registration via the board-type protocol failed.
 */
EFI_STATUS
EFIAPI
_ModuleEntryPoint (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS  Status;
  VOID        *UbaProtocol;
  UINT64      RegistrationResult;

  //
  // Cache global pointers.
  //
  gImageHandle = ImageHandle;
  gST          = SystemTable;
  gBS          = SystemTable->BootServices;
  gRT          = SystemTable->RuntimeServices;

  //
  // Validate input parameters.
  //
  if (ImageHandle == NULL) {
    DebugAssert (
      "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      51,
      "gImageHandle != ((void *) 0)"
      );
  }
  if (SystemTable == NULL) {
    DebugAssert (
      "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      57,
      "gST != ((void *) 0)"
      );
  }
  if (SystemTable->BootServices == NULL) {
    DebugAssert (
      "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      63,
      "gBS != ((void *) 0)"
      );
  }
  if (SystemTable->RuntimeServices == NULL) {
    DebugAssert (
      "e:\\hs\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c",
      47,
      "gRT != ((void *) 0)"
      );
  }

  //
  // Locate HOB list (ensures PCI enumeration data is available).
  // Initializes gHobList for use by the UBA framework.
  //
  GetHobList (ImageHandle);

  //
  // Log debug banner indicating this is the OpROM Update driver for
  // the Lightning Ridge EXEC B4 platform.
  //
  DebugPrint (DEBUG_INFO, "UBA:SETUPConfigUpdate-TypeLightningRidgeEXECB4\n");

  //
  // Locate the UBA Lightning Ridge EXEC B4 board-type protocol.
  // The protocol GUID is stored at GuidBlock + 0x10.
  //
  UbaProtocol = NULL;
  Status = (*gBS->LocateProtocol) ((EFI_GUID *)&GuidBlock[0x10], NULL, &UbaProtocol);

  //
  // If the UBA protocol was found, register the OpROM update configuration.
  // The registration function is at offset 0x10 in the protocol interface.
  //
  if (!EFI_ERROR (Status)) {
    Status = ((EFI_STATUS (*)(VOID *, EFI_GUID *, VOID *, UINT32))
              ((UBA_OPROM_UPDATE_BOARD_TYPE_PROTOCOL *)UbaProtocol)->RegisterOpromUpdateConfig) (
               UbaProtocol,
               (EFI_GUID *)&GuidBlock[0x30],  // OPROM_UPDATE_PROTOCOL_REGISTRATION_GUID
               (VOID *)OpromUpdateProtocolData,
               OPROM_UPDATE_PROTOCOL_DATA_SIZE  // 24 bytes
               );

    return Status;
  }

  return Status;
}