/** @file
Metronome.h -- Header for the UEFI Metronome Arch Protocol driver.
This driver installs the gEfiMetronomeArchProtocolGuid onto the handle
created by _ModuleEntryPoint, providing the platform with a calibrated
microsecond-level delay service. The protocol uses the PIT (8254) channel
1 and the RTC CMOS status register (port 0x70/0x71) to implement a busy-wait
loop with TSC-based microsecond granularity.
Derived from the HR650X BIOS Metronome.efi (MdeModulePkg/Universal/Metronome).
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __METRONOME_H__
#define __
#include "../uefi_headers/Uefi.h"
METRONOME_H__
//
// External UEFI types -- the caller is expected to include UefiBaseType.h,
// UefiSpec.h, and Protocol/Metronome.h from the EDK II tree before this file.
//
typedef unsigned long long UINT64;
typedef long long INT64;
typedef unsigned int UINT32;
typedef int INT32;
typedef unsigned short UINT16;
typedef short INT16;
typedef unsigned char UINT8;
typedef char INT8;
typedef UINT8 BOOLEAN;
typedef UINT64 EFI_STATUS;
typedef void * EFI_HANDLE;
typedef void * EFI_EVENT;
typedef UINT16 EFI_TPL;
//
// EFI_SUCCESS and common error codes.
//
#define EFI_SUCCESS 0
#define EFI_ERROR(a) ((INT64)(a) < 0)
#define EFI_ERR(a) (0x8000000000000000ULL | (a))
//
// EFI Metronome Arch Protocol GUID (from MdePkg)
// {2C1E6E47-7A7D-41A5-8A19-5C480BCE5B95}
//
#define EFI_METRONOME_ARCH_PROTOCOL_GUID \
{ 0x2C1E6E47, 0x7A7D, 0x41A5, \
{ 0x8A, 0x19, 0x5C, 0x48, 0x0B, 0xCE, 0x5B, 0x95 } }
//
// EFI Metronome Arch Protocol signature.
//
#define EFI_METRONOME_ARCH_PROTOCOL_REVISION 0x00010000
//
// PCD GUID for PcdMetronomeInternal (platform-specific)
//
#define PCD_METRONOME_INTERNAL_GUID \
{ 0x6B9EBD9C, 0xFE23, 0x47C8, \
{ 0x92, 0x26, 0x24, 0x63, 0x28, 0x4F, 0xD1, 0xAA } }
///
/// The metronome protocol entry point.
///
typedef
EFI_STATUS
(EFIAPI *EFI_METRONOME_WAIT)(
IN UINT32 Microseconds
);
///
/// EFI_METRONOME_ARCH_PROTOCOL
///
typedef struct {
UINT64 Revision;
EFI_METRONOME_WAIT Wait;
} EFI_METRONOME_ARCH_PROTOCOL;
//
// 8254 PIT constants (used in MicrosecondDelay).
//
#define PIT_PORT_COUNTER0 0x40
#define PIT_PORT_COUNTER1 0x41
#define PIT_PORT_COUNTER2 0x42
#define PIT_PORT_CONTROL 0x43
#define PIT_CONTROL_COUNTER2 0xB6 // Counter 2, mode 3, 16-bit binary
#define PIT_FREQUENCY 3579545 // 3.579545 MHz (OSC / 12 on typical PC)
//
// RTC CMOS constants (used for NMI / status).
//
#define RTC_PORT_CMOS_ADDR 0x70
#define RTC_PORT_CMOS_DATA 0x71
#define RTC_REGISTER_D 0x0D // Status Register D (bit 7 = RTC power)
#define RTC_NMI_ENABLE_BIT 0x80 // OR with CMOS addr to enable NMI
//
// I/O port used for PCI Express config space access.
//
#define PCI_EXPRESS_BASE_ADDRESS 0xF0000000ULL
//
// Local constants.
//
#define MICROSECONDS_PER_SECOND 1000000ULL
#define NANO_100_PER_SECOND 10000000ULL
#define RDTSC_WAIT_MASK 0x3FFFFF
#define RDTSC_WAIT_SHIFT 22
//
// Forward declarations.
//
EFI_STATUS
EFIAPI
MetronomeWait (
IN UINT32 Microseconds
);
//
// Library internal helpers (named after their EDK II origin).
//
/**
Reads the Time-Stamp Counter.
@return Current TSC value.
**/
UINT64
__rdtsc_w (
VOID
);
/**
Reads the current EFLAGS (caller's flags).
@return EFLAGS value.
**/
UINT64
__getcallerseflags_w (
VOID
);
/**
Issues a CPU PAUSE (rep; nop) -- yields to hyper-thread sibling.
@return None.
**/
VOID
_mm_pause_w (
VOID
);
/**
Enables interrupts (STI).
@return None.
**/
VOID
_enable_w (
VOID
);
/**
Disables interrupts (CLI).
@return None.
**/
VOID
_disable_w (
VOID
);
/**
Reads a 32-bit value from an I/O port (port must be 4-byte aligned).
@param[in] Port I/O port number (must be aligned to 4).
@return The 32-bit value read.
**/
UINT32
IoRead32 (
IN UINT16 Port
);
/**
Reads an unaligned 64-bit value from memory.
@param[in] Buffer Pointer to the unaligned 64-bit value.
@return The 64-bit value read.
**/
UINT64
ReadUnaligned64 (
IN CONST VOID *Buffer
);
/**
Translates a PCI Express address (MMIO) by adding the base address.
@param[in] Address PCI Express register offset (< 0x10000000).
@return The full MMIO address.
**/
UINT64
PciExpressGetAddress (
IN UINT64 Address
);
/**
Programmes the legacy PIC (8259) to a known state via I/O port 0x4D0 / 0x4D1.
Writes 0x0500 (little-endian) to the port pointed to by Address.
@param[in] Address Pointer to the I/O port (must be WORD-aligned).
@return The value written (0x0500).
**/
UINT16
IoWrite16 (
IN UINT16 *Address
);
/**
Returns the singleton pointer to the gPcdMetronomeInternal PPI/Protocol.
On first call, locates the protocol via BootServices->LocateProtocol.
Caches the result in mPcd.
@return Pointer to the PCD protocol interface, or NULL on failure.
**/
VOID *
GetPcdProtocol (
VOID
);
/**
Returns the singleton pointer to the DebugLib protocol/PPI.
On first call, locates the protocol (if the image size is <= 16 pages).
Caches the result in mDebugLib.
@return Pointer to the Debug protocol interface, or NULL on failure.
**/
VOID *
GetDebugLib (
VOID
);
/**
Internal ASSERT + debug-log helper.
Formats a message via the DebugLib protocol and then calls DebugAssert().
@param[in] FileName Source file name string.
@param[in] LineNumber Line number of the assertion.
@param[in] Description The assertion expression string.
**/
VOID
InternalAssert (
IN UINT64 FileName,
IN UINT64 LineNumber,
IN UINT64 Description
);
/**
Internal ASSERT_EFI_ERROR helper.
If (Status & ERROR_MASK), calls DebugAssert and DebugPrint.
@param[in] Status The EFI_STATUS to check.
@param[in] Format Format string for the debug message.
@param[in] ... Variable arguments.
@return The (char) result of the DebugLib chain.
**/
UINT8
InternalAssertEfiError (
IN UINT64 Status,
IN CONST CHAR8 *Format,
...
);
/**
Locates the first HOB that matches the requested GUID type.
Walks the HOB list (from SystemTable->BootServices->Hob.Start).
@param[in] HobStart Pointer to the start of the HOB list.
@return Pointer to the matching HOB structure, or NULL.
**/
VOID *
GetNextGuidHob (
IN CONST VOID *HobStart
);
/**
Returns a cached pointer to the HOB list (mHobList).
Lazily initialized from SystemTable->BootServices->Hob on first call.
@return Pointer to the start of the HOB list.
**/
VOID *
GetHobList (
VOID
);
/**
Busy-waits for the specified number of microseconds using the
PIT channel 2 and TSC.
Internal implementation shared by the Metronome protocol.
@param[in] Microseconds Number of microseconds to wait (must be >= 10).
**/
VOID
MicrosecondDelay (
IN UINT32 Microseconds
);
//
// Global variables exposed by the driver.
//
extern EFI_HANDLE gImageHandle;
extern UINT64 gSystemTable;
extern UINT64 gBootServices;
extern UINT64 gRuntimeServices;
#endif /* __METRONOME_H__ */