Kernel: Make TSC based timer monotonic

Prior to this I was just blindly rebasing the current TSC stats every
once in a while. Now I check for drift and scale the multiplier
accordingly to keep the timer from drifting
This commit is contained in:
2026-06-26 01:32:04 +03:00
parent ac0ef53e87
commit 59ec05c898
8 changed files with 172 additions and 75 deletions

View File

@@ -18,9 +18,8 @@ namespace Kernel::API
struct
{
uint8_t shift;
uint64_t mult;
uint64_t realtime_seconds;
uint64_t realtime_s;
uint32_t realtime_ns;
} gettime_shared;
struct
@@ -28,6 +27,8 @@ namespace Kernel::API
struct
{
uint32_t seq;
uint32_t mult;
int8_t shift;
uint64_t last_ns;
uint64_t last_tsc;
} gettime_local;

View File

@@ -82,5 +82,6 @@ namespace CPUID
bool has_pat();
bool has_1gib_pages();
bool has_invariant_tsc();
uint64_t get_tsc_frequency();
}

View File

@@ -124,7 +124,7 @@ namespace Kernel
static void yield();
static Scheduler& scheduler() { return *read_gs_sized<Scheduler*>(offsetof(Processor, m_scheduler)); }
static void initialize_tsc(uint8_t shift, uint64_t mult, uint64_t realtime_seconds);
static void initialize_tsc(uint64_t realtime_seconds);
static void update_tsc();
static uint64_t ns_since_boot_tsc();

View File

@@ -30,6 +30,13 @@ namespace Kernel
class SystemTimer : public Timer
{
public:
struct TSCInfo
{
int8_t shift;
uint32_t mult;
};
public:
static void initialize();
static SystemTimer& get();
@@ -49,8 +56,10 @@ namespace Kernel
void dont_invoke_scheduler() { m_timer->m_should_invoke_scheduler = false; }
void update_tsc() const;
uint64_t ns_since_boot_no_tsc() const;
void update_tsc();
TSCInfo tsc_info() const;
uint64_t ns_since_boot_no_tsc() const { return m_timer->ns_since_boot(); }
timespec real_time() const;
@@ -59,14 +68,29 @@ namespace Kernel
void initialize_timers();
uint64_t get_tsc_frequency() const;
void initialize_invariant_tsc();
private:
enum class TSCType
{
None,
Invariant,
};
uint64_t m_boot_time { 0 };
BAN::UniqPtr<RTC> m_rtc;
BAN::UniqPtr<Timer> m_timer;
bool m_has_invariant_tsc { false };
mutable uint32_t m_timer_ticks { 0 };
TSCType m_tsc_type = TSCType::None;
union {
struct {
int8_t shift;
uint32_t mult;
} invariant;
} m_tsc_info;
uint64_t m_tsc_update_ns { 0 };
};
}