mirror of
https://github.com/ipxe/ipxe
synced 2026-01-14 01:49:16 +03:00
[time] Allow timer to be selected at runtime
Allow the active timer (providing udelay() and currticks()) to be selected at runtime based on probing during the INIT_EARLY stage of initialisation. TICKS_PER_SEC is now a fixed compile-time constant for all builds, and is independent of the underlying clock tick rate. We choose the value 1024 to allow multiplications and divisions on seconds to be converted to bit shifts. TICKS_PER_MS is defined as 1, allowing multiplications and divisions on milliseconds to be omitted entirely. The 2% inaccuracy in this definition is negligible when using the standard BIOS timer (running at around 18.2Hz). TIMER_RDTSC now checks for a constant TSC before claiming to be a usable timer. (This timer can be tested in KVM via the command-line option "-cpu host,+invtsc".) Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -7,6 +7,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define BDA_EBDA 0x000e
|
||||
#define BDA_EQUIPMENT_WORD 0x0010
|
||||
#define BDA_FBMS 0x0013
|
||||
#define BDA_TICKS 0x006c
|
||||
#define BDA_MIDNIGHT 0x0070
|
||||
#define BDA_REBOOT 0x0072
|
||||
#define BDA_REBOOT_WARM 0x1234
|
||||
#define BDA_NUM_DRIVES 0x0075
|
||||
|
||||
@@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define ERRFILE_rtc_entropy ( ERRFILE_ARCH | ERRFILE_CORE | 0x000f0000 )
|
||||
#define ERRFILE_acpipwr ( ERRFILE_ARCH | ERRFILE_CORE | 0x00100000 )
|
||||
#define ERRFILE_cpuid ( ERRFILE_ARCH | ERRFILE_CORE | 0x00110000 )
|
||||
#define ERRFILE_rdtsc_timer ( ERRFILE_ARCH | ERRFILE_CORE | 0x00120000 )
|
||||
|
||||
#define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
|
||||
#define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
#ifndef _BITS_TIMER_H
|
||||
#define _BITS_TIMER_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* x86-specific timer API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/bios_timer.h>
|
||||
#include <ipxe/rdtsc_timer.h>
|
||||
|
||||
#endif /* _BITS_TIMER_H */
|
||||
@@ -1,44 +0,0 @@
|
||||
#ifndef _IPXE_BIOS_TIMER_H
|
||||
#define _IPXE_BIOS_TIMER_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* BIOS timer
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#ifdef TIMER_PCBIOS
|
||||
#define TIMER_PREFIX_pcbios
|
||||
#else
|
||||
#define TIMER_PREFIX_pcbios __pcbios_
|
||||
#endif
|
||||
|
||||
#include <ipxe/pit8254.h>
|
||||
|
||||
/**
|
||||
* Delay for a fixed number of microseconds
|
||||
*
|
||||
* @v usecs Number of microseconds for which to delay
|
||||
*/
|
||||
static inline __always_inline void
|
||||
TIMER_INLINE ( pcbios, udelay ) ( unsigned long usecs ) {
|
||||
/* BIOS timer is not high-resolution enough for udelay(), so
|
||||
* we use the 8254 Programmable Interval Timer.
|
||||
*/
|
||||
pit8254_udelay ( usecs );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of ticks per second
|
||||
*
|
||||
* @ret ticks_per_sec Number of ticks per second
|
||||
*/
|
||||
static inline __always_inline unsigned long
|
||||
TIMER_INLINE ( pcbios, ticks_per_sec ) ( void ) {
|
||||
/* BIOS timer ticks over at 18.2 ticks per second */
|
||||
return 18;
|
||||
}
|
||||
|
||||
#endif /* _IPXE_BIOS_TIMER_H */
|
||||
@@ -57,6 +57,12 @@ struct x86_features {
|
||||
/** Get CPU model */
|
||||
#define CPUID_MODEL 0x80000002UL
|
||||
|
||||
/** Get APM information */
|
||||
#define CPUID_APM 0x80000007UL
|
||||
|
||||
/** Invariant TSC */
|
||||
#define CPUID_APM_EDX_TSC_INVARIANT 0x00000100UL
|
||||
|
||||
/**
|
||||
* Issue CPUID instruction
|
||||
*
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
#ifndef _IPXE_RDTSC_TIMER_H
|
||||
#define _IPXE_RDTSC_TIMER_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* RDTSC timer
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#ifdef TIMER_RDTSC
|
||||
#define TIMER_PREFIX_rdtsc
|
||||
#else
|
||||
#define TIMER_PREFIX_rdtsc __rdtsc_
|
||||
#endif
|
||||
|
||||
/**
|
||||
* RDTSC values can easily overflow an unsigned long. We discard the
|
||||
* low-order bits in order to obtain sensibly-scaled values.
|
||||
*/
|
||||
#define TSC_SHIFT 8
|
||||
|
||||
/**
|
||||
* Get current system time in ticks
|
||||
*
|
||||
* @ret ticks Current time, in ticks
|
||||
*/
|
||||
static inline __always_inline unsigned long
|
||||
TIMER_INLINE ( rdtsc, currticks ) ( void ) {
|
||||
unsigned long ticks;
|
||||
|
||||
__asm__ __volatile__ ( "rdtsc\n\t"
|
||||
"shrdl %1, %%edx, %%eax\n\t"
|
||||
: "=a" ( ticks ) : "i" ( TSC_SHIFT ) : "edx" );
|
||||
return ticks;
|
||||
}
|
||||
|
||||
#endif /* _IPXE_RDTSC_TIMER_H */
|
||||
Reference in New Issue
Block a user