31#define CALIBRATE_US 50000
35static const char *
names[] = {
"pit",
"hpet",
"tsc"};
49 asm volatile(
"rdtsc" :
"=a"(lo),
"=d"(hi));
56 asm volatile(
"cpuid" :
"=a"(*a),
"=b"(*b),
"=c"(*c),
"=d"(*d) :
"a"(leaf),
"c"(0));
65 cpuid(0x80000000, &a, &b, &c, &d);
70 cpuid(0x80000007, &a, &b, &c, &d);
71 return !!(d & (1 << 8));
78 uint64_t ah = a >> 32, al = a & 0xffffffff;
79 uint64_t bh = b >> 32, bl = b & 0xffffffff;
81 return ((ah * bh) << 32) + ah * bl + al * bh + ((al * bl) >> 32);
160 ns = (h1 - h0) * period / 1000000ULL;
171 return t1 > t0 ? (ns << 32) / (t1 - t0) : 0;
185 printk(
"clock: timer ticks, %d ns\n", period_ns);
202 const char *want =
NULL;
210 if (want && forced < 0)
211 printk(
"clock: clock=%s: not tsc, hpet or pit\n", want);
216 printk(
"clock: no HPET\n");
227 printk(
"clock: the TSC isn't invariant (its rate may change)\n");
233 printk(
"clock: tsc, %ld MHz (calibrated against the %s)\n", mhz, by);
static const char * names[]
static void cpuid(uint32_t leaf, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
Runs CPUID for leaf.
void x86_clock_ticks(uint32_t period_ns)
Says how often the timer ticks, from now on: with neither TSC nor HPET, the ticks are the clock.
static uint64_t mul_shift32(uint64_t a, uint64_t b)
Computes (a * b) >> 32 in 32-bit halves, without needing the 128-bit product.
static uint64_t rdtsc(void)
Reads the TSC.
static uint64_t counter(void)
Reads the counter the clock uses.
const char * x86_clock_source(void)
Returns the name of the clock's counter.
void x86_clock_init(void)
Chooses the clock's counter and calibrates it, at boot, before the timer ticks.
void x86_clock_tick(void)
Counts a tick of the timer, and moves the clock's base on to now.
static int tsc_invariant(void)
Returns whether the TSC counts at a constant rate (CPUID 0x80000007, EDX bit 8).
static uint64_t tsc_calibrate(int hpet, const char **by)
Calibrates the TSC: counts it over CALIBRATE_US, timed by the HPET or the PIT, and returns its mult (...
static uint64_t since(uint64_t c)
Returns the counts since the base, from the counter's value c.
static uint64_t base_count
static uint32_t tick_period
int kargs_get(const char *key, const char **value)
Looks up an argument of the kernel's command line.
int x86_clock_precise(void)
Says whether the clock counts finer than the ticks.
int x86_hpet_init(void)
Finds the HPET and starts its counter.
uint64_t x86_hpet_read(void)
Reads the HPET's 64-bit counter.
uint32_t x86_hpet_read32(void)
Reads the low half of the HPET's counter only: a single read, which matters because each read is slow...
uint64_t x86_hpet_period_fs(void)
Returns the HPET counter's period.
void x86_pit_delay(uint32_t us)
Waits us microseconds, at most 54 ms, busy.
int printk(const char *fmt,...)
Writes a kernel message, to the message buffer and the consoles.
unsigned long long int uint64_t
uint64_t arch_rtime_ns(void)
Reads the monotonic clock, which starts at boot.
uint64_t arch_rtime_us(void)
Reads the monotonic clock, in microseconds.
uint64_t arch_rtime_ms(void)
Reads the monotonic clock, in milliseconds.