tsc: initial implementation of timekeeper source

This commit is contained in:
Matheus
2024-09-29 16:30:08 -03:00
parent 0fff338065
commit c3eef02d50
5 changed files with 83 additions and 4 deletions
+1
View File
@@ -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);
+1
View File
@@ -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);
+76
View File
@@ -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
);
+1 -1
View File
@@ -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;
+4 -3
View File
@@ -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