diff --git a/Kernel/Random.cpp b/Kernel/Random.cpp index 41e053dbb3..8caa275d06 100644 --- a/Kernel/Random.cpp +++ b/Kernel/Random.cpp @@ -71,7 +71,7 @@ UNMAP_AFTER_INIT KernelRng::KernelRng() klog() << "KernelRng: Using HPET as entropy source"; for (size_t i = 0; i < resource().pool_count * resource().reseed_threshold; ++i) { - u64 hpet_time = HPET::the().read_main_counter(); + u64 hpet_time = HPET::the().read_main_counter_unsafe(); this->resource().add_random_event(hpet_time, i % 32); } } else { diff --git a/Kernel/Time/APICTimer.cpp b/Kernel/Time/APICTimer.cpp index 6b68563d5c..fe69eec78a 100644 --- a/Kernel/Time/APICTimer.cpp +++ b/Kernel/Time/APICTimer.cpp @@ -65,28 +65,33 @@ UNMAP_AFTER_INIT bool APICTimer::calibrate(HardwareTimerBase& calibration_source // temporarily replace the timer callbacks const size_t ticks_in_100ms = calibration_source.ticks_per_second() / 10; - Atomic calibration_ticks = 0; + Atomic calibration_ticks = 0; #ifdef APIC_TIMER_MEASURE_CPU_CLOCK volatile u64 start_tsc = 0, end_tsc = 0; #endif + volatile u64 start_reference = 0, end_reference = 0; volatile u32 start_apic_count = 0, end_apic_count = 0; + bool query_reference = calibration_source.can_query_raw(); auto original_source_callback = calibration_source.set_callback([&](const RegisterState&) { u32 current_timer_count = apic.get_timer_current_count(); #ifdef APIC_TIMER_MEASURE_CPU_CLOCK u64 current_tsc = supports_tsc ? read_tsc() : 0; #endif + u64 current_reference = query_reference ? calibration_source.current_raw() : 0; - auto prev_tick = calibration_ticks.fetch_add(1, AK::memory_order_acq_rel); + auto prev_tick = calibration_ticks.fetch_add(1); if (prev_tick == 0) { #ifdef APIC_TIMER_MEASURE_CPU_CLOCK start_tsc = current_tsc; #endif start_apic_count = current_timer_count; - } else if (prev_tick + 1 == ticks_in_100ms) { + start_reference = current_reference; + } else if (prev_tick + 1 == ticks_in_100ms + 1) { #ifdef APIC_TIMER_MEASURE_CPU_CLOCK end_tsc = current_tsc; #endif end_apic_count = current_timer_count; + end_reference = current_reference; } }); @@ -102,7 +107,7 @@ UNMAP_AFTER_INIT bool APICTimer::calibrate(HardwareTimerBase& calibration_source sti(); // Loop for about 100 ms - while (calibration_ticks.load(AK::memory_order_relaxed) < ticks_in_100ms) + while (calibration_ticks.load() <= ticks_in_100ms) ; cli(); @@ -112,25 +117,33 @@ UNMAP_AFTER_INIT bool APICTimer::calibrate(HardwareTimerBase& calibration_source disable_local_timer(); + if (query_reference) { + u64 one_tick_ns = calibration_source.raw_to_ns((end_reference - start_reference) / ticks_in_100ms); + m_frequency = (u32)(1000000000ull / one_tick_ns); + klog() << "APICTimer: Ticks per second: " << m_frequency << " (" << (one_tick_ns / 1000000) << "." << (one_tick_ns % 1000000) << "ms)"; + } else { + // For now, assume the frequency is exactly the same + m_frequency = calibration_source.ticks_per_second(); + klog() << "APICTimer: Ticks per second: " << m_frequency << " (assume same frequency as reference clock)"; + } + auto delta_apic_count = start_apic_count - end_apic_count; // The APIC current count register decrements! m_timer_period = (delta_apic_count * apic.get_timer_divisor()) / ticks_in_100ms; - auto apic_freq = (delta_apic_count * apic.get_timer_divisor()) / apic.get_timer_divisor(); + u64 apic_freq = delta_apic_count * apic.get_timer_divisor() * 10; + klog() << "APICTimer: Bus clock speed: " << (apic_freq / 1000000) << "." << (apic_freq % 1000000) << " MHz"; if (apic_freq < 1000000) { klog() << "APICTimer: Frequency too slow!"; return false; } - klog() << "APICTimer: Bus clock speed: " << (apic_freq / 1000000) << "." << (apic_freq % 1000000) << " MHz"; + #ifdef APIC_TIMER_MEASURE_CPU_CLOCK if (supports_tsc) { - auto delta_tsc = end_tsc - start_tsc; + auto delta_tsc = (end_tsc - start_tsc) * 10; klog() << "APICTimer: CPU clock speed: " << (delta_tsc / 1000000) << "." << (delta_tsc % 1000000) << " MHz"; } #endif - // TODO: measure rather than assuming it matches? - m_frequency = calibration_source.ticks_per_second(); - enable_local_timer(); return true; } diff --git a/Kernel/Time/HPET.cpp b/Kernel/Time/HPET.cpp index f36d407c62..09f944c221 100644 --- a/Kernel/Time/HPET.cpp +++ b/Kernel/Time/HPET.cpp @@ -38,7 +38,7 @@ namespace Kernel { #define ABSOLUTE_MAXIMUM_COUNTER_TICK_PERIOD 0x05F5E100 #define NANOSECOND_PERIOD_TO_HERTZ(x) 1000000000 / x -#define MEGAHERTZ_TO_HERTZ(x) (x / 1000000) +#define HERTZ_TO_MEGAHERTZ(x) (x / 1000000) namespace HPETFlags { enum class Attributes { @@ -220,7 +220,7 @@ void HPET::update_periodic_comparator_value() // way to resume periodic timers properly because we reset the main counter // and we can only write the period into the comparator value... timer.capabilities = timer.capabilities | (u32)HPETFlags::TimerConfiguration::ValueSet; - u64 value = frequency() / comparator.ticks_per_second(); + u64 value = ns_to_raw_counter_ticks(1000000000ull / comparator.ticks_per_second()); dbgln_if(HPET_DEBUG, "HPET: Update periodic comparator {} comparator value to {} main value was: {}", comparator.comparator_number(), value, @@ -250,11 +250,10 @@ void HPET::update_non_periodic_comparator_value(const HPETComparator& comparator VERIFY_INTERRUPTS_DISABLED(); VERIFY(!comparator.is_periodic()); VERIFY(comparator.comparator_number() <= m_comparators.size()); - auto& regs = registers(); - auto& timer = regs.get_timer_by_index(comparator.comparator_number()); + auto& timer = registers().get_timer_by_index(comparator.comparator_number()); u64 value = frequency() / comparator.ticks_per_second(); // NOTE: If the main counter passes this new value before we finish writing it, we will never receive an interrupt! - u64 new_counter_value = read_register_safe64(regs.main_counter_value) + value; + u64 new_counter_value = read_main_counter() + value; timer.comparator_value.high = (u32)(new_counter_value >> 32); timer.comparator_value.low = (u32)new_counter_value; } @@ -262,7 +261,7 @@ void HPET::update_non_periodic_comparator_value(const HPETComparator& comparator u64 HPET::update_time(u64& seconds_since_boot, u32& ticks_this_second, bool query_only) { // Should only be called by the time keeper interrupt handler! - u64 current_value = read_register_safe64(registers().main_counter_value); + u64 current_value = read_main_counter(); u64 delta_ticks = m_main_counter_drift; if (current_value >= m_main_counter_last_read) delta_ticks += current_value - m_main_counter_last_read; @@ -286,12 +285,17 @@ u64 HPET::update_time(u64& seconds_since_boot, u32& ticks_this_second, bool quer return (delta_ticks * 1000000000ull) / ticks_per_second; } -u64 HPET::read_main_counter() const +u64 HPET::read_main_counter_unsafe() const { auto& main_counter = registers().main_counter_value; return ((u64)main_counter.high << 32) | (u64)main_counter.low; } +u64 HPET::read_main_counter() const +{ + return read_register_safe64(registers().main_counter_value); +} + void HPET::enable_periodic_interrupt(const HPETComparator& comparator) { #if HPET_DEBUG @@ -405,10 +409,15 @@ HPETRegistersBlock& HPET::registers() return *(HPETRegistersBlock*)m_hpet_mmio_region->vaddr().offset(m_physical_acpi_hpet_registers.offset_in_page()).as_ptr(); } -u64 HPET::calculate_ticks_in_nanoseconds() const +u64 HPET::raw_counter_ticks_to_ns(u64 raw_ticks) const { // ABSOLUTE_MAXIMUM_COUNTER_TICK_PERIOD == 100 nanoseconds - return ((u64)registers().capabilities.main_counter_tick_period * 100ull) / ABSOLUTE_MAXIMUM_COUNTER_TICK_PERIOD; + return (raw_ticks * (u64)registers().capabilities.main_counter_tick_period * 100ull) / ABSOLUTE_MAXIMUM_COUNTER_TICK_PERIOD; +} + +u64 HPET::ns_to_raw_counter_ticks(u64 ns) const +{ + return (ns * 1000000ull) / (u64)registers().capabilities.main_counter_tick_period; } UNMAP_AFTER_INIT HPET::HPET(PhysicalAddress acpi_hpet) @@ -438,8 +447,8 @@ UNMAP_AFTER_INIT HPET::HPET(PhysicalAddress acpi_hpet) global_disable(); - m_frequency = NANOSECOND_PERIOD_TO_HERTZ(calculate_ticks_in_nanoseconds()); - klog() << "HPET: frequency " << m_frequency << " Hz (" << MEGAHERTZ_TO_HERTZ(m_frequency) << " MHz) resolution: " << calculate_ticks_in_nanoseconds() << "ns"; + m_frequency = NANOSECOND_PERIOD_TO_HERTZ(raw_counter_ticks_to_ns(1)); + klog() << "HPET: frequency " << m_frequency << " Hz (" << HERTZ_TO_MEGAHERTZ(m_frequency) << " MHz) resolution: " << raw_counter_ticks_to_ns(1) << "ns"; VERIFY(regs.capabilities.main_counter_tick_period <= ABSOLUTE_MAXIMUM_COUNTER_TICK_PERIOD); // Reset the counter, just in case... (needs to match m_main_counter_last_read) diff --git a/Kernel/Time/HPET.h b/Kernel/Time/HPET.h index 7cdc15fb74..a2d04dd774 100644 --- a/Kernel/Time/HPET.h +++ b/Kernel/Time/HPET.h @@ -46,6 +46,8 @@ public: static HPET& the(); u64 frequency() const { return m_frequency; } + u64 raw_counter_ticks_to_ns(u64) const; + u64 ns_to_raw_counter_ticks(u64) const; const NonnullRefPtrVector& comparators() const { return m_comparators; } void disable(const HPETComparator&); @@ -60,6 +62,7 @@ public: void disable_periodic_interrupt(const HPETComparator& comparator); u64 update_time(u64& seconds_since_boot, u32& ticks_this_second, bool query_only); + u64 read_main_counter_unsafe() const; u64 read_main_counter() const; Vector capable_interrupt_numbers(u8 comparator_number); @@ -75,7 +78,7 @@ private: bool is_periodic_capable(u8 comparator_number); void set_comparators_to_optimal_interrupt_state(size_t timers_count); - u64 calculate_ticks_in_nanoseconds() const; + u64 nanoseconds_to_raw_ticks() const; PhysicalAddress find_acpi_hpet_registers_block(); explicit HPET(PhysicalAddress acpi_hpet); diff --git a/Kernel/Time/HPETComparator.cpp b/Kernel/Time/HPETComparator.cpp index f47f4dca0d..31060cfa76 100644 --- a/Kernel/Time/HPETComparator.cpp +++ b/Kernel/Time/HPETComparator.cpp @@ -138,4 +138,14 @@ size_t HPETComparator::calculate_nearest_possible_frequency(size_t frequency) co return frequency; } +u64 HPETComparator::current_raw() const +{ + return HPET::the().read_main_counter(); +} + +u64 HPETComparator::raw_to_ns(u64 raw_delta) const +{ + return HPET::the().raw_counter_ticks_to_ns(raw_delta); +} + } diff --git a/Kernel/Time/HPETComparator.h b/Kernel/Time/HPETComparator.h index 771eca1887..233cf977b7 100644 --- a/Kernel/Time/HPETComparator.h +++ b/Kernel/Time/HPETComparator.h @@ -51,6 +51,9 @@ public: virtual void set_periodic() override; virtual void set_non_periodic() override; virtual void disable() override; + virtual bool can_query_raw() const override { return true; } + virtual u64 current_raw() const override; + virtual u64 raw_to_ns(u64) const override; virtual void reset_to_default_ticks_per_second() override; virtual bool try_to_set_frequency(size_t frequency) override; diff --git a/Kernel/Time/HardwareTimer.h b/Kernel/Time/HardwareTimer.h index 71f5f13799..6cbad9168a 100644 --- a/Kernel/Time/HardwareTimer.h +++ b/Kernel/Time/HardwareTimer.h @@ -65,6 +65,9 @@ public: virtual void set_non_periodic() = 0; virtual void disable() = 0; virtual u32 frequency() const = 0; + virtual bool can_query_raw() const { return false; } + virtual u64 current_raw() const { return 0; } + virtual u64 raw_to_ns(u64) const { return 0; } virtual size_t ticks_per_second() const = 0;