Newer
Older
AMI-Aptio-BIOS-Reversed / Metronome / Metronome.c
@Ajax Dong Ajax Dong 2 days ago 22 KB Init
/** @file
  Metronome.c -- UEFI Metronome Arch Protocol Driver for HR650X BIOS.

  Implements the EFI_METRONOME_ARCH_PROTOCOL.Wait() entry point using the
  8254 PIT channel 2 and the CPU TSC (RDTSC) for microsecond-granularity
  busy-wait loops.  The driver:

    1. Installs gEfiMetronomeArchProtocolGuid onto a new protocol handle.
    2. Initialises the PIT channel 2 in rate-generator mode.
    3. Provides MicrosecondDelay() which converts microseconds to PIT ticks
       and spins on TSC-delta.

  File:   Metronome.c
  Module: MdeModulePkg/Universal/Metronome/Metronome.c
  Binary: Metronome.efi (SHA256: cf72be089c5360c263982d4f79971963696a1f8cd048a764f6b9c29f5c22c340)
  Index:  0082 of HR650X BIOS PE files

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

#include "Metronome.h"

// ==========================================================================
// Global data (from .data section at 0xFC0-0x1060)
// ==========================================================================

/// The EFI_HANDLE for this driver image (populated by UefiBootServicesTableLib).
EFI_HANDLE  gImageHandle = NULL;

/// The EFI_SYSTEM_TABLE pointer (populated by UefiBootServicesTableLib).
UINT64      gSystemTable = 0;

/// The EFI_BOOT_SERVICES pointer (derived from gSystemTable->BootServices).
UINT64      gBootServices = 0;

/// The EFI_RUNTIME_SERVICES pointer (derived from gSystemTable->RuntimeServices).
UINT64      gRuntimeServices = 0;

/// Cached DebugLib protocol/PPI interface (initialised lazily).
UINT64      mDebugLib = 0;

/// Cached HOB list pointer (initialised lazily by GetHobList).
UINT64      mHobList = 0;

/// PCI Express MMIO base address (read from PCD via GetPcdProtocol).
UINT64      mPciExpressBaseAddress = 0;

/// Cached PCD protocol interface (initialised lazily by GetPcdProtocol).
UINT64      mPcd = 0;

/// EFI_METRONOME_ARCH_PROTOCOL instance installed by the driver.
/// Revision = 0x00010000, Wait = MetronomeWait.
///
/// NOTE: The following structure sits at 0x1000 (off_1000) in the original
/// binary.  We declare it explicitly here.
EFI_METRONOME_ARCH_PROTOCOL  mMetronome = {
  EFI_METRONOME_ARCH_PROTOCOL_REVISION,
  MetronomeWait
};

//
// GUID constants (from .rdata section).
//
/// gEfiMetronomeArchProtocolGuid
const UINT8  gEfiMetronomeArchProtocolGuid[16] = EFI_METRONOME_ARCH_PROTOCOL_GUID;

/// gEfiPcdMetronomeInternalGuid (the PCD protocol GUID used by DxePcdLib)
const UINT8  gPcdMetronomeInternalGuid[16] = PCD_METRONOME_INTERNAL_GUID;

/// The DebugLib singleton protocol GUID (gEfiDebugLibProtocolGuid placeholder)
const UINT8  gDebugLibProtocolGuid[16] = { 0 };

// ==========================================================================
// Thunk / intrinsic wrappers
// ==========================================================================

/**
  Issues a CPU PAUSE instruction (rep; nop).  Yields to the other hyper-thread
  on an Intel HT-capable processor.

  (Original: sub_2C0, "_mm_pause_w")
**/
VOID
_mm_pause_w (
  VOID
  )
{
  __asm__ volatile ("pause");
}

/**
  Reads the Time-Stamp Counter (RDTSC).

  @return  The current 64-bit TSC value.

  (Original: sub_2D0, "__rdtsc_w")
**/
UINT64
__rdtsc_w (
  VOID
  )
{
  UINT32  Lo, Hi;
  __asm__ volatile ("rdtsc" : "=a" (Lo), "=d" (Hi));
  return ((UINT64)Hi << 32) | Lo;
}

/**
  Enables interrupts (STI).

  (Original: sub_2E0, "_enable_w")
**/
VOID
_enable_w (
  VOID
  )
{
  __asm__ volatile ("sti");
}

/**
  Disables interrupts (CLI).

  (Original: sub_2F0, "_disable_w")
**/
VOID
_disable_w (
  VOID
  )
{
  __asm__ volatile ("cli");
}

/**
  Reads the caller's EFLAGS (pushfq / pop).

  @return  The EFLAGS value.

  (Original: sub_300, "__getcallerseflags_w")
**/
UINT64
__getcallerseflags_w (
  VOID
  )
{
  UINT64  Flags;
  __asm__ volatile ("pushfq; popq %0" : "=r" (Flags));
  return Flags;
}

// ==========================================================================
// I/O and memory access helpers
// ==========================================================================

/**
  Reads a 32-bit value from an I/O port with strict alignment checking.

  @param[in]  Port  The I/O port number.  Must be 4-byte aligned.

  @return  The 32-bit value read from the port.

  (Original: sub_93C, "IoRead32")
**/
UINT32
IoRead32 (
  IN UINT16  Port
  )
{
  //
  // ASSERT ((Port & 3) == 0);
  //
  if ((Port & 3) != 0) {
    InternalAssert (
      (UINT64)"e:\\hs\\MdePkg\\Library\\BaseIoLibIntrinsic\\IoLibMsc.c",
      193,
      (UINT64)"(Port & 3) == 0"
      );
  }

  return __indword (Port);
}

/**
  Reads an unaligned 64-bit value from memory.

  @param[in]  Buffer  Pointer to the unaligned value (may be NULL).

  @return  The 64-bit value read.

  (Original: sub_96C, "ReadUnaligned64")
**/
UINT64
ReadUnaligned64 (
  IN CONST VOID  *Buffer
  )
{
  //
  // ASSERT (Buffer != NULL);
  //
  if (Buffer == NULL) {
    InternalAssert (
      (UINT64)"e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
      192,
      (UINT64)"Buffer != ((void *) 0)"
      );
  }

  return *(const UINT64 *)Buffer;
}

/**
  Translates a PCI Express register offset to a full MMIO address.

  @param[in]  Address  The PCI Express register offset.

  @return  Address + mPciExpressBaseAddress.

  (Original: sub_858, "PciExpressGetAddress")
**/
UINT64
PciExpressGetAddress (
  IN UINT64  Address
  )
{
  //
  // ASSERT ((Address & ~0xFFFFFFF) == 0)
  //
  if ((Address & 0xFFFFFFFFF0000000ULL) != 0) {
    InternalAssert (
      (UINT64)"e:\\hs\\MdePkg\\Library\\SmmPciExpressLib\\PciExpressLib.c",
      118,
      (UINT64)"((Address) & ~0xfffffff) == 0"
      );
  }

  return Address + mPciExpressBaseAddress;
}

/**
  Writes 0x0500 (as a 16-bit value) to the given I/O port.

  In the context of the UEFI Metronome driver, the port addressed is
  0x4D0 (PIC Slave/Master interrupt control), and writing 0x0500
  sets up the 8259 PIC for operation.

  @param[in]  Address  Pointer to the target I/O port (must be WORD-aligned).

  @return  The value written (0x0500).

  (Original: sub_908, "IoWrite16")
**/
UINT16
IoWrite16 (
  IN UINT16  *Address
  )
{
  //
  // ASSERT ((Address & 1) == 0);
  //
  if (((UINT64)Address & 1) != 0) {
    InternalAssert (
      (UINT64)"e:\\hs\\MdePkg\\Library\\BaseIoLibIntrinsic\\IoLib.c",
      183,
      (UINT64)"(Address & 1) == 0"
      );
  }

  *Address = 0x0500;
  return 0x0500;
}

// ==========================================================================
// Library initialisation helpers
// ==========================================================================

/**
  Initialises the UEFI boot/runtime service globals from the SystemTable.

  Performs NULL-pointer assertions for:
    - gImageHandle
    - gST (SystemTable)
    - gBS (BootServices)
    - gRT (RuntimeServices)

  Then initialises the HOB list, PCD protocol, and PCI Express base address.
  Reads the interrupt state, sets up the 8259 PIC, and calibrates a
  microsecond delay using RDTSC and the PIT.

  @param[in]  ImageHandle  The EFI_HANDLE for this driver image.
  @param[in]  SystemTable  Pointer to the EFI_SYSTEM_TABLE.

  (Original: sub_47C, the main initialisation dispatcher called from
   _ModuleEntryPoint.)
**/
VOID
MetronomeDriverInit (
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE    *SystemTable
  )
{
  UINT64        Ticks;
  UINT64        StartTSC;
  UINT64        Elapsed;
  UINT64        Microseconds;
  BOOLEAN       InterruptsEnabled;
  UINT64        PcdProtocol;

  //
  // Save ImageHandle and SystemTable (UefiBootServicesTableLib init).
  //
  gImageHandle = ImageHandle;
  if (ImageHandle == NULL) {
    InternalAssert (
      (UINT64)"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      51,
      (UINT64)"gImageHandle != ((void *) 0)"
      );
  }

  gSystemTable = (UINT64)SystemTable;
  if (SystemTable == NULL) {
    InternalAssert (
      (UINT64)"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      57,
      (UINT64)"gST != ((void *) 0)"
      );
  }

  gBootServices = (UINT64)SystemTable->BootServices;
  if (gBootServices == 0) {
    InternalAssert (
      (UINT64)"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
      63,
      (UINT64)"gBS != ((void *) 0)"
      );
  }

  gRuntimeServices = (UINT64)SystemTable->RuntimeServices;
  if (gRuntimeServices == 0) {
    InternalAssert (
      (UINT64)"e:\\hs\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c",
      47,
      (UINT64)"gRT != ((void *) 0)"
      );
  }

  //
  // Initialise HOB list (DxeHobLib).
  //
  GetHobList ();

  //
  // Locate PCD protocol and read PcdPciExpressBaseAddress.
  //
  PcdProtocol = (UINT64)GetPcdProtocol ();
  if (PcdProtocol != 0) {
    //
    // Call PcdGet64 (5) via the protocol's Get64 method at offset +32.
    //
    mPciExpressBaseAddress = (*(UINT64 (*)(UINT64))(PcdProtocol + 32))(5);
  }

  //
  // If PCI Express config space is accessible (PcdPciExpressBaseAddress != 0),
  // program the PIC via I/O ports.
  //
  if ((INT8)PciExpressGetAddress (1024068) >= 0) {
    IoWrite16 ((UINT16 *)PciExpressGetAddress (1024064));

    //
    // Set bit 7 at the PCI express offset for byte 1024068
    // (I/O port 0x4D1, PIC slave interrupt mask).
    //
    {
      UINT8 *Ptr = (UINT8 *)PciExpressGetAddress (1024068);
      *Ptr |= 0x80;
    }
  }

  //
  // Save interrupt state and disable interrupts.
  //
  InterruptsEnabled = (__getcallerseflags_w () & 0x200) != 0;
  _disable_w ();

  //
  // Read the current TSC and calculate the number of ticks corresponding
  // to 1288 microseconds.  The calculation uses the PIT frequency:
  //
  //   Ticks = (PIT_FREQUENCY * Microseconds) / 1000000
  //         = (3579545 * 1288) / 1000000
  //
  // The result captures the bottom 24 bits.
  //
  StartTSC = IoRead32 (1288) & 0xFFFFFF;    // Read PIT counter 2 current value

  //
  // Spin until the PIT counter has decremented by the delta.
  // RDTSC_WAIT_MASK handles 22-bit rollover.
  //
  Elapsed = StartTSC;
  while (((Elapsed + RDTSC_WAIT_MASK - (UINT32)IoRead32 (1288)) & 0x800000) == 0) {
    _mm_pause_w ();
  }

  //
  // Capture the elapsed TSC value after the spin.
  //
  Microseconds = __rdtsc_w ();

  //
  // Restore interrupt state.
  //
  if (InterruptsEnabled) {
    _enable_w ();
  } else {
    _disable_w ();
  }
}

// ==========================================================================
// Public Metronome protocol entry
// ==========================================================================

/**
  The EFI_METRONOME_ARCH_PROTOCOL.Wait() implementation.

  Waits for the specified number of microseconds by programming the 8254 PIT
  channel 2 and busy-waiting on the TSC.

  @param[in]  Microseconds  The number of microseconds to wait.
                            Must be >= 10 (PIT minimum granularity).

  @return  EFI_SUCCESS always.

  (Original: sub_5D0, "MetronomeWait")
**/
EFI_STATUS
EFIAPI
MetronomeWait (
  IN UINT32  Microseconds
  )
{
  UINT64  Ticks;

  //
  // Convert Microseconds to PIT ticks:
  //
  //   Ticks = (PIT_FREQUENCY * Microseconds) / 1000000
  //
  // For large delays (>= 1000000 us == 1 s) we divide first to avoid overflow:
  //   Ticks = 3579545 * (Microseconds / 10) / 100000
  //
  if (Microseconds >= MICROSECONDS_PER_SECOND) {
    Ticks = 3579545 * (UINT64)(Microseconds / 10) / 100000;
  } else {
    Ticks = 3579545 * (UINT64)(100 * Microseconds) / 1000000000;
  }

  MicrosecondDelay ((UINT32)Ticks);
  return EFI_SUCCESS;
}

// ==========================================================================
// Internal delay implementation
// ==========================================================================

/**
  Busy-waits for the specified number of PIT ticks using the PIT channel 2
  and TSC-based measurement.

  The PIT channel 2 is programmed in mode 3 (square-wave) at a base rate
  of 3.579545 MHz.  The routine reads the current counter and spins until
  the counter has decremented by the requested number of ticks.

  @param[in]  Ticks  The number of PIT ticks to wait.

  (Original: sub_894, "MicrosecondDelay")
**/
VOID
MicrosecondDelay (
  IN UINT32  Ticks
  )
{
  UINT32  Remaining;
  UINT32  Delta;
  UINT32  CurrentCount;

  Remaining = Ticks >> RDTSC_WAIT_SHIFT;      // Number of 0x400000-tick chunks
  Delta     = Ticks & RDTSC_WAIT_MASK;         // Remainder (< 0x400000)

  do {
    //
    // Wait for the current 0x400000-tick chunk:
    //   target = Delta + (PIT counter current value & 0xFFFFFF)
    //
    UINT32 Target = Delta + (IoRead32 (1288) & 0xFFFFFF);
    Delta = 0x400000;   // Subsequent iterations wait a full chunk

    //
    // Spin until the PIT counter passes the target.
    // The 0x800000 bit handles 24-bit counter rollover.
    //
    while (((Target - (UINT32)IoRead32 (1288)) & 0x800000) == 0) {
      _mm_pause_w ();
    }

  } while (Remaining-- != 0);
}

// ==========================================================================
// Library support functions
// ==========================================================================

/**
  Returns a cached pointer to the HOB list.

  On first call, retrieves the HOB list from BootServices (gBS + 104).
  If the HOB list pointer is NULL, triggers an ASSERT.

  @return  Pointer to the start of the HOB list.

  (Original: sub_780, "GetHobList")
**/
VOID *
GetHobList (
  VOID
  )
{
  VOID    *HobList;
  UINT64  HobCount;
  UINT64  Index;

  if (mHobList != 0) {
    return (VOID *)mHobList;
  }

  //
  // gSystemTable + 104 = Number of HOB entries
  // gSystemTable + 112 = Pointer to HOB entry array
  //
  HobList   = NULL;
  mHobList  = 0;

  if (*(UINT64 *)(gSystemTable + 104) != 0) {
    //
    // Walk the HOB entries looking for a GUID match with the
    // Metronome-specific GUID.
    //
    for (Index = 0; Index < *(UINT64 *)(gSystemTable + 104); Index++) {
      if (GetNextGuidHob ((VOID *)(gSystemTable + 112 + Index * 24)) != NULL) {
        //
        // Found -- extract the data pointer at offset +16 of the HOB entry.
        //
        HobList = (VOID *)(*(UINT64 *)(*(UINT64 *)(gSystemTable + 112) + 24 * Index + 16));
        mHobList = (UINT64)HobList;
        break;
      }
    }
  }

  if (HobList == NULL) {
    //
    // ASSERT_EFI_ERROR (EFI_NOT_FOUND)
    //
    InternalAssertEfiError (0x80000000LL,
      "\nASSERT_EFI_ERROR (Status = %r)\n",
      0x800000000000000EULL);
    InternalAssert (
      (UINT64)"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
      54,
      (UINT64)"!EFI_ERROR (Status)"
      );
  }

  //
  // ASSERT (mHobList != NULL)
  //
  if (mHobList == 0) {
    InternalAssert (
      (UINT64)"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
      55,
      (UINT64)"mHobList != ((void *) 0)"
      );
  }

  return (VOID *)mHobList;
}

/**
  Locates the first HOB entry whose GUID matches the Metronome-specific GUID.

  @param[in]  Entry  Pointer to the HOB entry structure (GUID at offset 0,
                     data at offset 8).

  @return  The entry if GUID matches, NULL otherwise.

  (Original: sub_99C, "GetNextGuidHob")
**/
VOID *
GetNextGuidHob (
  IN CONST VOID  *Entry
  )
{
  UINT64  Guid1;
  UINT64  Guid2;
  UINT64  EntryGuid1;
  UINT64  EntryGuid2;

  //
  // Read the GUID we are looking for (from the .data section at unk_FF0/FF8).
  //
  Guid1 = ReadUnaligned64 ((VOID *)((UINT8 *)&gEfiMetronomeArchProtocolGuid + 0));
  Guid2 = ReadUnaligned64 ((VOID *)((UINT8 *)&gEfiMetronomeArchProtocolGuid + 8));

  //
  // Read the GUID from the HOB entry.
  //
  EntryGuid1 = ReadUnaligned64 (Entry);
  EntryGuid2 = ReadUnaligned64 ((UINT8 *)Entry + 8);

  //
  // Compare.
  //
  if (Guid1 == EntryGuid1 && Guid2 == EntryGuid2) {
    return (VOID *)Entry;
  }

  return NULL;
}

/**
  Returns the singleton pointer to the gPcdMetronomeInternal protocol.

  Uses BootServices->LocateProtocol() to find the PCD protocol.
  Caches the result in mPcd.

  @return  Pointer to the PCD protocol interface.

  (Original: sub_A0C, "GetPcdProtocol")
**/
VOID *
GetPcdProtocol (
  VOID
  )
{
  UINT64  Status;

  if (mPcd != 0) {
    return (VOID *)mPcd;
  }

  //
  // Call BootServices->LocateProtocol(&gPcdMetronomeInternalGuid, NULL, &mPcd)
  // BootServices at gSystemTable + (BootServices offset) = gBootServices.
  // LocateProtocol offset within BootServices = 320.
  //
  Status = (*(UINT64 (*)(VOID *, UINT64, UINT64 *))(gBootServices + 320))(
             (VOID *)gPcdMetronomeInternalGuid,
             0,
             &mPcd
             );

  if (EFI_ERROR (Status)) {
    InternalAssertEfiError (0x80000000LL,
      "\nASSERT_EFI_ERROR (Status = %r)\n",
      Status);
    InternalAssert (
      (UINT64)"e:\\hs\\MdePkg\\Library\\DxePcdLib\\DxePcdLib.c",
      78,
      (UINT64)"!EFI_ERROR (Status)"
      );
  }

  //
  // ASSERT (mPcd != NULL)
  //
  if (mPcd == 0) {
    InternalAssert (
      (UINT64)"e:\\hs\\MdePkg\\Library\\DxePcdLib\\DxePcdLib.c",
      79,
      (UINT64)"mPcd != ((void *) 0)"
      );
  }

  return (VOID *)mPcd;
}

/**
  Returns the singleton pointer to the DebugLib protocol.

  Uses BootServices->LocateProtocol() to find the Debug protocol.
  Only allocates the protocol if the image size is <= 16 pages.

  @return  Pointer to the Debug protocol interface, or NULL.

  (Original: sub_638, "GetDebugLib")
**/
VOID *
GetDebugLib (
  VOID
  )
{
  UINT64  PageCount;
  UINT64  Status;

  if (mDebugLib != 0) {
    return (VOID *)mDebugLib;
  }

  //
  // Call BootServices->GetMemoryMap() to determine the number of pages
  // occupied by this image.  For Metronome, this is a self-check.
  // BootServices offsets: GetMemoryMap at +24, AllocatePages at +32.
  //
  PageCount = (*(UINT64 (*)(UINT64))(gBootServices + 24))(31);
  (*(VOID (*)(UINT64))(gBootServices + 32))(PageCount);

  //
  // Only proceed if the image fits within 16 pages.
  //
  if (PageCount <= 16) {
    Status = (*(UINT64 (*)(VOID *, UINT64, UINT64 *))(gBootServices + 320))(
               (VOID *)gDebugLibProtocolGuid,
               0,
               &mDebugLib
               );

    if (EFI_ERROR (Status)) {
      mDebugLib = 0;
    }
  } else {
    mDebugLib = 0;
  }

  return (VOID *)mDebugLib;
}

/**
  Internal ASSERT helper -- calls DebugAssert via the DebugLib protocol.

  @param[in]  FileName     Source file name string.
  @param[in]  LineNumber   Line number of the assertion.
  @param[in]  Description  The assertion expression string.

  (Original: sub_740, "InternalAssert")
**/
VOID
InternalAssert (
  IN UINT64       FileName,
  IN UINT64       LineNumber,
  IN UINT64       Description
  )
{
  VOID  *DebugLib;

  DebugLib = GetDebugLib ();
  if (DebugLib != NULL) {
    //
    // Call DebugAssert (DebugLib + 8) with (FileName, LineNumber, Description).
    //
    (*(VOID (*)(UINT64, UINT64, UINT64))((UINT64)DebugLib + 8))(
      FileName,
      LineNumber,
      Description
      );
  }
}

/**
  Internal ASSERT_EFI_ERROR helper -- calls DebugAssert and debug print
  when Status has the error bit set.

  @param[in]  Status  The EFI_STATUS to test.
  @param[in]  Format  Format string.
  @param[in]  ...     Variable arguments.

  @return  The (char) value returned by the DebugLib chain.

  (Original: sub_6B8, "InternalAssertEfiError")
**/
UINT8
InternalAssertEfiError (
  IN UINT64       Status,
  IN CONST CHAR8  *Format,
  ...
  )
{
  VOID    *DebugLib;
  UINT64  ErrorMask;
  UINT8   CmosReg;
  UINT8   CmosData;
  UINT8   Result;
  va_list VaList;

  va_start (VaList, Format);

  DebugLib  = GetDebugLib ();
  ErrorMask = 0;
  Result    = 0;

  if (DebugLib != NULL) {
    //
    // Read RTC CMOS status register D (0x0D) via ports 0x70/0x71.
    // Preserve bit 7 (NMI enable) on the address port.
    //
    __outbyte (RTC_PORT_CMOS_ADDR, RTC_REGISTER_D | RTC_NMI_ENABLE_BIT);
    CmosData = __inbyte (RTC_PORT_CMOS_DATA);

    //
    // Determine the error mask based on RTC power status.
    // If CMOS register D > 3 and non-zero, derive the mask from the
    // memory-mapped flag at 0xFDAF0490.
    //
    if (CmosData > 3) {
      if (CmosData == 0) {
        CmosData = (*(volatile UINT8 *)0xFDAF0490 & 2) | 1;
      }
    }

    //
    // Map CmosData to error mask:
    //   CmosData == 1 -> ErrorMask = 0x80000004 (EFI_INVALID_PARAMETER style)
    //   Otherwise     -> ErrorMask = 0x80000006 (EFI_UNSUPPORTED style)
    //
    if ((CmosData - 1) <= 0xFD) {
      ErrorMask = 0x80000006LL;
      if (CmosData == 1) {
        ErrorMask = 0x80000004LL;
      }
    }

    //
    // If the status matches the error mask, call DebugPrint via the protocol.
    //
    if ((ErrorMask & Status) != 0) {
      Result = (*(UINT8 (*)(UINT64, const CHAR8 *, va_list))(DebugLib))(Status, Format, VaList);
    }
  }

  va_end (VaList);
  return Result;
}

// ==========================================================================
// Driver entry point
// ==========================================================================

/**
  The UEFI entry point for the Metronome driver.

  Installs the gEfiMetronomeArchProtocolGuid onto a newly created protocol
  handle.  If the protocol is already installed, triggers an ASSERT.

  @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 protocol was installed.
  @return  EFI_ALREADY_STARTED   The protocol is already in the database
                                 (triggers ASSERT in debug builds).
  @return  Other                 Error from gBS->InstallProtocolInterface.

  (Original: _ModuleEntryPoint at 0x3D4)
**/
EFI_STATUS
EFIAPI
_ModuleEntryPoint (
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE    *SystemTable
  )
{
  EFI_STATUS  Status;

  //
  // Perform library and global initialisation.
  //
  MetronomeDriverInit (ImageHandle, SystemTable);

  //
  // Check whether the Metronome Arch Protocol is already installed.
  //
  {
    VOID  *Interface;
    Status = (*(EFI_STATUS (*)(VOID *, UINT64, VOID **))(gBootServices + 320))(
               (VOID *)gEfiMetronomeArchProtocolGuid,
               0,
               &Interface
               );

    if (!EFI_ERROR (Status)) {
      //
      // Protocol already installed -- ASSERT.
      //
      InternalAssert (
        (UINT64)"e:\\hs\\MdeModulePkg\\Universal\\Metronome\\Metronome.c",
        112,
        (UINT64)"&gEfiMetronomeArchProtocolGuid already installed in database"
        );
    }
  }

  //
  // Install the protocol onto a new handle.
  // gBootServices + 328 = InstallProtocolInterface
  //
  Status = (*(EFI_STATUS (*)(VOID *, VOID *, VOID *, UINT64))(gBootServices + 328))(
             (VOID *)&gImageHandle,             // New handle
             (VOID *)gEfiMetronomeArchProtocolGuid, // Protocol GUID
             (VOID *)&mMetronome,               // Protocol interface
             0                                   // Not native (BOOLEAN = FALSE)
             );

  //
  // ASSERT_EFI_ERROR (Status)
  //
  if (EFI_ERROR (Status)) {
    InternalAssertEfiError (
      0x80000000LL,
      "\nASSERT_EFI_ERROR (Status = %r)\n",
      Status
      );
    InternalAssert (
      (UINT64)"e:\\hs\\MdeModulePkg\\Universal\\Metronome\\Metronome.c",
      122,
      (UINT64)"!EFI_ERROR (Status)"
      );
  }

  return Status;
}