mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
tsc: initial implementation of timekeeper source
This commit is contained in:
@@ -152,6 +152,7 @@ static timekeeper_source_info_t *hpet_init(void) {
|
||||
|
||||
}
|
||||
|
||||
// ran in at least IPL_DPC
|
||||
time_t hpet_ticks(timekeeper_source_info_t *) {
|
||||
if (hpet_private.type == TYPE_64BIT) {
|
||||
return read64(HPET_REG_COUNTER);
|
||||
|
||||
@@ -60,6 +60,7 @@ static timekeeper_source_info_t *kvm_timer_init(void) {
|
||||
return timekeeper_source_info;
|
||||
}
|
||||
|
||||
// ran in at least IPL_DPC
|
||||
static time_t kvm_timer_ticks(timekeeper_source_info_t *timekeeper_source_info) {
|
||||
volatile kvm_timer_info_t *kvm_timer_info = MAKE_HHDM(timekeeper_source_info->private);
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
#include <kernel/timekeeper.h>
|
||||
#include <arch/tsc.h>
|
||||
#include <arch/cpuid.h>
|
||||
#include <logging.h>
|
||||
#include <kernel/alloc.h>
|
||||
|
||||
static bool tsc_probe(void) {
|
||||
cpuid_results_t cpuid_results;
|
||||
|
||||
uint32_t max_extended_leaf = cpuid_extended_max_leaf();
|
||||
if (max_extended_leaf < 0x80000007)
|
||||
return false;
|
||||
|
||||
cpuid(0x80000007, &cpuid_results);
|
||||
return cpuid_results.edx & (1 << 8);
|
||||
}
|
||||
|
||||
static timekeeper_source_info_t *tsc_init(void) {
|
||||
__assert(tsc_probe());
|
||||
|
||||
timekeeper_source_info_t *timekeeper_source_info = alloc(sizeof(timekeeper_source_info_t));
|
||||
__assert(timekeeper_source_info);
|
||||
|
||||
timekeeper_source_info->private = current_cpu();
|
||||
|
||||
bool need_calibration = false;
|
||||
if (cpuid_base_max_leaf() >= 0x15) {
|
||||
cpuid_results_t cpuid_results;
|
||||
cpuid(0x15, &cpuid_results);
|
||||
|
||||
if (cpuid_results.eax == 0 || cpuid_results.ebx == 0 || cpuid_results.ecx == 0) {
|
||||
need_calibration = true;
|
||||
goto calibrate;
|
||||
}
|
||||
|
||||
uint64_t core_frequency = cpuid_results.ecx;
|
||||
uint64_t core_numerator = cpuid_results.ebx;
|
||||
uint64_t core_denominator = cpuid_results.eax;
|
||||
|
||||
uint64_t tsc_frequency = core_frequency * core_numerator / core_denominator;
|
||||
timekeeper_source_info->ticks_per_us = tsc_frequency / 1000000;
|
||||
}
|
||||
|
||||
calibrate:
|
||||
if (need_calibration) {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
long old_ipl = interrupt_raiseipl(IPL_TIMER - 1);
|
||||
time_t ticks_start = rdtsc_serialized();
|
||||
|
||||
timekeeper_wait_us(50000);
|
||||
time_t ticks_end = rdtsc_serialized();
|
||||
|
||||
interrupt_loweripl(old_ipl);
|
||||
|
||||
timekeeper_source_info->ticks_per_us = (ticks_end - ticks_start) / 50000;
|
||||
}
|
||||
}
|
||||
|
||||
return timekeeper_source_info;
|
||||
}
|
||||
|
||||
// ran in at least IPL_DPC
|
||||
static time_t tsc_ticks(timekeeper_source_info_t *timekeeper_source_info) {
|
||||
__assert(timekeeper_source_info->private == current_cpu());
|
||||
|
||||
return rdtsc_serialized();
|
||||
}
|
||||
|
||||
TIMEKEEPER_SOURCE(kvmtimer_source,
|
||||
.name = "Invariant TSC",
|
||||
.priority = 990,
|
||||
.probe = tsc_probe,
|
||||
.init = tsc_init,
|
||||
.ticks = tsc_ticks,
|
||||
.flags = 0
|
||||
);
|
||||
@@ -47,7 +47,7 @@ static inline time_t timespec_us(timespec_t a) {
|
||||
static inline timespec_t timespec_from_us(time_t us) {
|
||||
timespec_t ts = {
|
||||
.s = us / 1000000,
|
||||
.ns = (us % 1000000) * 100
|
||||
.ns = (us * 1000) % 1000000000
|
||||
};
|
||||
|
||||
return ts;
|
||||
|
||||
@@ -18,6 +18,7 @@ typedef struct {
|
||||
#define CPUID_VENDOR_INTEL "GenuineIntel"
|
||||
|
||||
#define CPUID_LEAF_0x80000001_EDX_SYSCALL (1 << 11)
|
||||
#define CPUID_LEAF_1_EDX_TSC (1 << 4)
|
||||
#define CPUID_LEAF_1_EDX_HTT (1 << 28)
|
||||
|
||||
static inline void cpuid_with_ecx(uint32_t leaf, uint32_t ecx, cpuid_results_t *cpuid_results) {
|
||||
@@ -90,9 +91,9 @@ static inline bool cpuid_leaf_0x4_available(void) {
|
||||
if (cpuid_base_max_leaf() < 0x4)
|
||||
return false;
|
||||
|
||||
unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
|
||||
__get_cpuid_count(0x4, 0, &eax, &ebx, &ecx, &edx);
|
||||
return eax != 0;
|
||||
cpuid_results_t cpuid_results;
|
||||
cpuid_with_ecx(0x4, 0, &cpuid_results);
|
||||
return cpuid_results.eax != 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user