From 54d48e7d91a86d5228dfad24de29f986198fb3a8 Mon Sep 17 00:00:00 2001 From: Katharina Heidenreich Date: Thu, 2 Jul 2026 23:07:16 +0200 Subject: [PATCH] feat: enhance timer --- kernel/include/apic/timer.h | 50 +++++++++++++++++++++++++++++++--- kernel/include/util/function.h | 7 +++++ kernel/include/util/optional.h | 21 ++++++++++++++ kernel/src/apic/timer.cpp | 48 +++++++++++++++++++++++++++++--- kernel/src/init/init.cpp | 15 ++++++++++ 5 files changed, 133 insertions(+), 8 deletions(-) diff --git a/kernel/include/apic/timer.h b/kernel/include/apic/timer.h index b0cffb0..86602be 100644 --- a/kernel/include/apic/timer.h +++ b/kernel/include/apic/timer.h @@ -1,15 +1,57 @@ #pragma once #include "acpi/madt.h" -#include "util/optional.h" namespace apic { -struct lapic_timer_calibration_t { - uint64_t tsc_frequency_hz; +struct duration_t { + uint64_t timer_count; }; -optional calibrateTimer(const acpi::Madt& madt); +struct timestamp_t { + uint64_t timer_count; +}; + +constexpr duration_t operator+(duration_t left, duration_t right) { + return duration_t{left.timer_count + right.timer_count}; +} + +constexpr duration_t operator-(duration_t left, duration_t right) { + return duration_t{left.timer_count - right.timer_count}; +} + +constexpr duration_t operator*(duration_t duration, uint64_t scalar) { + return duration_t{duration.timer_count * scalar}; +} + +constexpr duration_t operator*(uint64_t scalar, duration_t duration) { + return duration_t{duration.timer_count * scalar}; +} + +constexpr timestamp_t operator+(timestamp_t timestamp, duration_t duration) { + return timestamp_t{timestamp.timer_count + duration.timer_count}; +} + +constexpr timestamp_t operator+(duration_t duration, timestamp_t timestamp) { + return timestamp_t{timestamp.timer_count + duration.timer_count}; +} + +constexpr timestamp_t operator-(timestamp_t timestamp, duration_t duration) { + return timestamp_t{timestamp.timer_count - duration.timer_count}; +} + +constexpr duration_t operator-(timestamp_t left, timestamp_t right) { + return duration_t{left.timer_count - right.timer_count}; +} + +bool calibrateTimer(const acpi::Madt& madt); + +duration_t seconds(uint64_t count); +duration_t milliseconds(uint64_t count); +duration_t microseconds(uint64_t count); +duration_t nanoseconds(uint64_t count); + +timestamp_t now(); // TODO: when dynamic allocation and lists are available // struct Timer {}; diff --git a/kernel/include/util/function.h b/kernel/include/util/function.h index b346920..44c77da 100644 --- a/kernel/include/util/function.h +++ b/kernel/include/util/function.h @@ -23,3 +23,10 @@ auto construct() { return Type{forward(args)...}; }; } + +template +auto constant(V v) { + return [v](auto _) { + return v; + }; +} diff --git a/kernel/include/util/optional.h b/kernel/include/util/optional.h index e69f107..91e1c1d 100644 --- a/kernel/include/util/optional.h +++ b/kernel/include/util/optional.h @@ -183,3 +183,24 @@ public: } } }; + +template +struct as_optional { + using type = optional; +}; +template +struct as_optional> { + using type = optional; +}; +template +using as_optional_t = typename as_optional::type; + +template +auto lift(Func func) { + return [func](const auto&... optionals) -> as_optional_t { + if ((optionals.has_value() && ...)) { + return func(optionals.value()...); + } + return nullopt; + }; +} diff --git a/kernel/src/apic/timer.cpp b/kernel/src/apic/timer.cpp index cbc3d38..bf1df94 100644 --- a/kernel/src/apic/timer.cpp +++ b/kernel/src/apic/timer.cpp @@ -1,7 +1,6 @@ #include "apic/timer.h" #include "util/cpuid.h" -#include "util/function.h" namespace { @@ -11,6 +10,12 @@ constexpr uint32_t processor_frequency_leaf = 0x16; constexpr uint32_t feature_edx_tsc = 1u << 4; +struct lapic_timer_calibration_t { + uint64_t tsc_frequency_hz; +}; + +lapic_timer_calibration_t timer_calibration{}; + bool isTscSupported() { return cpuid(feature_info_leaf) .map([](const cpuid_result_t& features) { @@ -45,11 +50,46 @@ optional tscFrequency() { return tscFrequencyFromCrystalRatio().or_else(tscFrequencyFromProcessorBase); } +apic::duration_t durationFromUnit(uint64_t count, uint64_t units_per_second) { + uint64_t whole_seconds = count / units_per_second; + uint64_t remainder_units = count % units_per_second; + return apic::duration_t{whole_seconds * timer_calibration.tsc_frequency_hz + + remainder_units * timer_calibration.tsc_frequency_hz / units_per_second}; +} + } // namespace -optional apic::calibrateTimer(const acpi::Madt&) { +bool apic::calibrateTimer(const acpi::Madt&) { if (!isTscSupported()) { - return {}; + return false; } - return tscFrequency().map(construct()); + return tscFrequency() + .map([](uint64_t tsc_frequency_hz) { + timer_calibration.tsc_frequency_hz = tsc_frequency_hz; + return true; + }) + .value_or(false); +} + +apic::duration_t apic::seconds(uint64_t count) { + return duration_t{count * timer_calibration.tsc_frequency_hz}; +} + +apic::duration_t apic::milliseconds(uint64_t count) { + return durationFromUnit(count, 1'000); +} + +apic::duration_t apic::microseconds(uint64_t count) { + return durationFromUnit(count, 1'000'000); +} + +apic::duration_t apic::nanoseconds(uint64_t count) { + return durationFromUnit(count, 1'000'000'000); +} + +apic::timestamp_t apic::now() { + uint32_t low = 0; + uint32_t high = 0; + __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); + return timestamp_t{(static_cast(high) << 32) | low}; } diff --git a/kernel/src/init/init.cpp b/kernel/src/init/init.cpp index 2ff7571..f7b891a 100644 --- a/kernel/src/init/init.cpp +++ b/kernel/src/init/init.cpp @@ -1,6 +1,7 @@ #include "init/init.h" #include "acpi/acpi.h" #include "acpi/madt.h" +#include "apic/timer.h" #include "init/multiboot2.h" #include "init/print.h" #include "memory/allocator.h" @@ -200,10 +201,24 @@ static AcpiDiscoveryResult setupAcpi() { return res; } +static void calibrateTimer(optional madt) { + auto success = madt.map(apic::calibrateTimer).value_or(false); + if (!success) { + panic("Could not calibrate timer"); + } +} + [[maybe_unused]] [[noreturn]] __attribute__((used)) void init() { initFromLow(); print("Reached init\n"); step("memory", setupMemory); auto acpi = step("acpi", setupAcpi); + step("timer", partial(calibrateTimer, acpi.madt)); + auto now = apic::now(); + print_hex(now.timer_count); + now = apic::now(); + print_hex(now.timer_count); + now = apic::now(); + print_hex(now.timer_count); halt(); }