/** @file
TimestampDxe -- UEFI Timer Stamp DXE Driver
This DXE driver implements the EFI_TIMESTAMP_PROTOCOL for UEFI. It calibrates the
x86 Time-Stamp Counter (TSC) frequency by measuring TSC ticks against a known
hardware counter accessible via I/O port 0x508, then publishes the timestamp
protocol for use by other UEFI components.
The driver performs TSC frequency calibration at initialization by executing a
timed wait loop using an I/O-mapped counter at port 0x508 (a PCH timer counter,
likely the TCO timer or a custom LPC-decoded counter). It measures elapsed TSC
ticks over a fixed count of the reference counter (357 increments), then
multiplies by 10000 to obtain the TSC frequency in Hz.
UEFI Phase: DXE (Driver Execution Environment)
Protocol Produced: gEfiTimestampProtocolGuid
Dependencies: gEfiPcdProtocolGuid, gEfiHobListGuid (via System Table config table)
Source (from debug strings): MdeModulePkg/Universal/TimestampDxe/TimestampDxe.c
Build environment: e:\hs\ (presumably EDK2 build tree)
Hardware-specific behavior:
- Uses I/O port 0x508 for reference counter (24-bit free-running counter)
- Uses RTC CMOS index 0x4B for platform identification (debug routing)
- Writes to fixed physical address 0xFDAF0490 as fallback for platform detection
- May access RTC through PCIe Enhanced Configuration Access Mechanism (ECAM)
by writing to PCIe config space at PcdPciExpressBaseAddress
Copyright (c) HR650X BIOS Decompilation Project
**/
#ifndef __TIMESTAMP_DXE_H__
#define __TIMESTAMP_DXE_H__
#include "../uefi_headers/Uefi.h"
//
// ---------------------------------------------------------------------------
// Protocol GUIDs
// ---------------------------------------------------------------------------
///
/// {AFBFDE41-2E6E-4262-BA65-62B9236E5495}
/// EFI Timestamp Protocol GUID (from UEFI Specification)
/// Defined in MdePkg/Protocol/Timestamp.h
///
#define EFI_TIMESTAMP_PROTOCOL_GUID \
{ 0xAFBFDE41, 0x2E6E, 0x4262, { 0xBA, 0x65, 0x62, 0xB9, 0x23, 0x6E, 0x54, 0x95 } }
///
/// {7739F24C-93D7-11D4-9A3A-0090273FC14D}
/// EFI HOB List GUID -- used to locate the HOB list via System Table
/// ConfigurationTable.
///
#define EFI_HOB_LIST_GUID \
{ 0x7739F24C, 0x93D7, 0x11D4, { 0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } }
///
/// {11B34006-D85B-4D0A-A290-D5A571310EF7}
/// gEfiPcdProtocolGuid -- used to access PCD (Platform Configuration Database)
/// services. Required for retrieving PcdPciExpressBaseAddress and PCD values
/// for PCIe ECAM access.
///
#define EFI_PCD_PROTOCOL_GUID \
{ 0x11B34006, 0xD85B, 0x4D0A, { 0xA2, 0x90, 0xD5, 0xA5, 0x71, 0x31, 0x0E, 0xF7 } }
///
/// {36232936-0E76-31C8-A13A-3AF2FC1C3932}
/// Debug/Report Status Code Protocol GUID -- used to locate the debug
/// output protocol for assertion messages and debug prints.
/// NOTE: This GUID has been verified against the binary constants but is NOT
/// a standard UEFI spec GUID; it may be platform-specific or from an
/// EDK2-internal protocol definition (possibly gEfiStatusCodeRuntimeProtocolGuid
/// in a modified form, or a custom debug protocol).
///
#define EFI_DEBUG_PROTOCOL_GUID \
{ 0x36232936, 0x0E76, 0x31C8, { 0xA1, 0x3A, 0x3A, 0xF2, 0xFC, 0x1C, 0x39, 0x32 } }
//
// ---------------------------------------------------------------------------
// Protocol Structures
// ---------------------------------------------------------------------------
/**
Retrieves the current value of the time-stamp counter.
Returns the raw TSC value (from RDTSC instruction) minus the base timestamp
saved at driver initialization. This gives the number of TSC ticks elapsed
since the driver was loaded.
@param[out] Timestamp Pointer to a UINT64 that receives the timestamp value.
If NULL, the function returns immediately.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_INVALID_PARAMETER Timestamp is NULL.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_TIMESTAMP_GET)(
OUT UINT64 *Timestamp
);
//
// EFI_TIMESTAMP_PROTOCOL
//
// NOTE: This driver's implementation installs the protocol interface as a
// simple function table containing two function pointers only:
// [0] = GetTimestamp
// [1] = GetProperties
//
// The Frequency and EndTime fields are maintained as module-global variables
// rather than being embedded in the protocol structure. This deviates from
// the standard EDK2 EFI_TIMESTAMP_PROTOCOL definition which places Frequency
// and EndTime inline. Consumers should use GetProperties() to retrieve these
// values.
//
typedef struct {
EFI_TIMESTAMP_GET GetTimestamp; // Offset 0x00: Get current TSC value
EFI_TIMESTAMP_GET GetProperties; // Offset 0x08: Get timestamp properties
} EFI_TIMESTAMP_PROTOCOL;
//
// ---------------------------------------------------------------------------
// Module Global State (stored in .data segment)
// ---------------------------------------------------------------------------
///
/// EFI System Table passed by DXE core. Saved at entry.
///
extern EFI_SYSTEM_TABLE *gSystemTable;
///
/// EFI Boot Services pointer. Derived from gSystemTable->BootServices.
///
extern EFI_BOOT_SERVICES *gBootServices;
///
/// EFI Runtime Services pointer. Derived from gSystemTable->RuntimeServices.
///
extern EFI_RUNTIME_SERVICES *gRuntimeServices;
///
/// EFI Image Handle passed by DXE core at entry.
///
extern EFI_HANDLE gImageHandle;
///
/// Pointer to the debug/report protocol interface. NULL until located.
/// Used by DebugPrint() and DebugAssert() wrappers.
///
extern VOID *gDebugProtocol;
///
/// Cached pointer to the HOB list, located via System Table ConfigurationTable
/// by matching gEfiHobListGuid. NULL until located.
///
extern VOID *mHobList;
///
/// Cached PCD protocol interface. Located via gBS->LocateProtocol().
///
extern VOID *mPcdProtocol;
///
/// PCI Express Configuration Space Base Address (MMIO base for ECAM).
/// Retrieved via PCD protocol Get32(Token=5).
///
extern UINT64 mPciExpressBaseAddress;
///
/// TSC frequency in Hz, computed during driver initialization.
/// Derived by measuring TSC ticks over a calibrated I/O port delay.
///
extern UINT64 mTimestampFrequencyHz;
//
// ---------------------------------------------------------------------------
// Module Data for EFI_TIMESTAMP_PROTOCOL Implementation
// ---------------------------------------------------------------------------
///
/// Base TSC value captured at driver initialization. Subtracted from raw TSC
/// in GetTimestamp() to produce elapsed ticks since boot.
///
extern UINT64 mBaseTimeStamp;
///
/// Maximum timestamp value before wrap (EndTime). Set to MAX_UINT64 (all 1s).
///
extern UINT64 mEndTime;
///
/// Exported frequency value (copy of mTimestampFrequencyHz), accessible via
/// GetProperties().
///
extern UINT64 mFrequency;
//
// ---------------------------------------------------------------------------
// Hardware Constants
// ---------------------------------------------------------------------------
///
/// I/O port for the reference timer counter used in TSC frequency calibration.
/// This is a 32-bit I/O port read, masked to 24 bits by the calibration code.
/// Likely the PCH TCO timer counter or a custom LPC-decoded free-running counter.
///
#define TIMESTAMP_CALIBRATION_PORT 0x508
///
/// Number of reference counter ticks to wait during calibration.
/// The calibration loop waits for the counter at TIMESTAMP_CALIBRATION_PORT
/// to increment by this many units, then measures the elapsed TSC ticks and
/// multiplies by 10000 to derive the TSC frequency in Hz.
///
#define TIMESTAMP_CALIBRATION_DELTA 357
///
/// Multiplier applied to measured TSC ticks to compute frequency in Hz.
/// If the calibration wait duration is exactly 100 microseconds, then
/// TSC_ticks * 10000 = TSC ticks per second = TSC frequency in Hz.
///
#define TIMESTAMP_TICK_TO_HZ_MULTIPLIER 10000
///
/// RTC CMOS Index register (I/O port 0x70)
///
#define RTC_INDEX_PORT 0x70
///
/// RTC CMOS Data register (I/O port 0x71)
///
#define RTC_DATA_PORT 0x71
///
/// CMOS offset 0x4B: Platform identifier byte.
/// Used to determine debug output routing.
///
#define RTC_CMOS_PLATFORM_ID 0x4B
///
/// Fixed physical memory address for platform identification fallback.
/// On Intel PCH platforms, this is in the PMC register space.
/// Bit 1 indicates platform type (0 = mobile/desktop, 1 = server).
///
#define PLATFORM_ID_MMIO_ADDR 0xFDAF0490ULL
//
// ---------------------------------------------------------------------------
// EFI Status Code Types used by debug functions
// ---------------------------------------------------------------------------
#define EFI_STATUS_CODE_TYPE_DEBUG 0x80000004
#define EFI_STATUS_CODE_TYPE_ERROR 0x80000006
//
// ---------------------------------------------------------------------------
// Function Declarations
// ---------------------------------------------------------------------------
/**
Main entry point for the TimestampDxe driver.
Initializes module globals (ImageHandle, SystemTable, BootServices,
RuntimeServices), gets the HOB list and PCD protocol, calibrates TSC
frequency by measuring against a hardware reference counter at I/O port 0x508,
writes the calibration result to mTimestampFrequencyHz, and then installs
the EFI_TIMESTAMP_PROTOCOL on a new handle.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The entry point executed successfully. Protocol
was installed (or ASSERT on failure).
@retval EFI_INVALID_PARAMETER BootServices or RuntimeServices were NULL.
@return Status from InstallMultipleProtocolInterfaces.
Errors trigger ASSERT.
**/
EFI_STATUS
EFIAPI
TimestampDxeEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
);
/**
Returns the current timestamp value.
Computes elapsed TSC ticks since driver initialization by subtracting the
saved base TSC value from the current RDTSC value.
@param[out] Timestamp Pointer to receive the timestamp value in TSC ticks.
@retval EFI_SUCCESS Timestamp value returned.
**/
EFI_STATUS
EFIAPI
TimestampGetTimestamp (
OUT UINT64 *Timestamp
);
/**
Returns the properties of the timestamp counter.
Fills in the Frequency (TSC Hz) and EndTime (maximum counter value) of the
timestamp counter.
@param[out] Timestamp Pointer to a buffer where properties are written.
The buffer is expected to be at least 16 bytes and
receives:
- Offset 0x00: Frequency in Hz (UINT64)
- Offset 0x08: EndTime / max value (UINT64, always
MAX_UINT64 for TSC)
@retval EFI_SUCCESS Properties returned.
@retval EFI_INVALID_PARAMETER Timestamp pointer is NULL.
**/
EFI_STATUS
EFIAPI
TimestampGetProperties (
OUT UINT64 *Timestamp
);
//
// ---------------------------------------------------------------------------
// Library/Helper Functions (linked from BaseLib, BaseMemoryLib, DxePcdLib,
// DxeHobLib, UefiBootServicesTableLib, UefiRuntimeServicesTableLib)
// ---------------------------------------------------------------------------
/**
Reads the current TSC value using the RDTSC instruction.
@return 64-bit TSC value.
**/
UINT64
EFIAPI
AsmReadTsc (
void
);
/**
Reads CPU EFLAGS of the caller.
@return EFLAGS register value.
**/
UINTN
EFIAPI
AsmReadEflags (
void
);
/**
Disables interrupts (CLI).
**/
VOID
EFIAPI
AsmDisableInterrupts (
void
);
/**
Enables interrupts (STI).
**/
VOID
EFIAPI
AsmEnableInterrupts (
void
);
/**
Executes the PAUSE instruction (hint to the processor for spin-wait loops).
**/
VOID
EFIAPI
AsmPause (
void
);
/**
Reads a 32-bit value from an I/O port.
@param[in] Port I/O port address.
@return Value read from the I/O port.
**/
UINT32
EFIAPI
IoRead32 (
IN UINTN Port
);
/**
Writes a 16-bit value to a memory-mapped I/O address.
@param[in] Address MMIO address.
@param[in] Value Value to write.
**/
VOID
EFIAPI
MmioWrite16 (
IN UINTN Address,
IN UINT16 Value
);
/**
Reads an 8-bit value from an I/O port.
@param[in] Port I/O port address.
@return Value read from the I/O port.
**/
UINT8
EFIAPI
IoRead8 (
IN UINTN Port
);
/**
Writes an 8-bit value to an I/O port.
@param[in] Port I/O port address.
@param[in] Value Value to write.
**/
VOID
EFIAPI
IoWrite8 (
IN UINTN Port,
IN UINT8 Value
);
/**
Copies a block of memory (may handle overlapping buffers).
@param[out] Destination Pointer to destination buffer.
@param[in] Source Pointer to source buffer.
@param[in] Length Number of bytes to copy.
@return Pointer to destination buffer.
**/
VOID *
EFIAPI
CopyMem (
OUT VOID *Destination,
IN CONST VOID *Source,
IN UINTN Length
);
/**
Reads a UINT64 value from an unaligned pointer.
@param[in] Buffer Pointer to read from.
@return 64-bit value read.
**/
UINT64
EFIAPI
ReadUnaligned64 (
IN CONST VOID *Buffer
);
/**
Locates a protocol interface by GUID.
Wrapper around gBS->LocateProtocol().
@param[in] ProtocolGuid GUID of the protocol to locate.
@param[in] Registration Optional registration key (NULL for first locate).
@param[out] Interface Receives the protocol interface pointer.
@retval EFI_SUCCESS Protocol located successfully.
**/
EFI_STATUS
EFIAPI
LocateProtocol (
IN EFI_GUID *ProtocolGuid,
IN VOID *Registration OPTIONAL,
OUT VOID **Interface
);
/**
Debug print function. Routes to the debug/report protocol.
@param[in] ErrorLevel Severity of the message (e.g., DEBUG_INFO).
@param[in] Format Format string.
@param[in] ... Variable arguments for the format string.
**/
VOID
EFIAPI
DebugPrint (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
);
/**
Assertion handler. Routes to the debug/report protocol.
@param[in] FileName Source file name.
@param[in] LineNumber Line number of the assertion.
@param[in] Description Assert description string.
**/
VOID
EFIAPI
DebugAssert (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
);
/**
Returns the HOB list pointer by searching the EFI System Table's
ConfigurationTable for gEfiHobListGuid.
Results are cached in mHobList after the first successful lookup.
Asserts if the HOB list GUID is not found.
@return Pointer to the start of the HOB list (EFI_HOB_LIST).
**/
VOID *
EFIAPI
GetHobList (
void
);
/**
Gets the PCD protocol interface pointer.
Locates gEfiPcdProtocolGuid via gBS->LocateProtocol(). Caches the result
in mPcdProtocol. Asserts on failure.
@return Pointer to the PCD protocol interface.
**/
VOID *
EFIAPI
GetPcdProtocol (
void
);
/**
Reads a 32-bit PCD value by token number.
@param[in] TokenNumber The PCD token number.
@return The 32-bit PCD value.
**/
UINT32
EFIAPI
PcdGet32 (
IN UINTN TokenNumber
);
#endif // __TIMESTAMP_DXE_H__