diff --git a/kernel/include/kernel/Timer/HPET.h b/kernel/include/kernel/Timer/HPET.h index d6f61f58..57471d6a 100644 --- a/kernel/include/kernel/Timer/HPET.h +++ b/kernel/include/kernel/Timer/HPET.h @@ -19,6 +19,7 @@ namespace Kernel virtual uint64_t ns_since_boot() const override; virtual timespec time_since_boot() const override; + virtual bool pre_scheduler_sleep_needs_lock() const override { return false; } virtual void pre_scheduler_sleep_ns(uint64_t) override; virtual void handle_irq() override; diff --git a/kernel/include/kernel/Timer/PIT.h b/kernel/include/kernel/Timer/PIT.h index 96d99178..2c26ed5f 100644 --- a/kernel/include/kernel/Timer/PIT.h +++ b/kernel/include/kernel/Timer/PIT.h @@ -16,6 +16,7 @@ namespace Kernel virtual uint64_t ns_since_boot() const override; virtual timespec time_since_boot() const override; + virtual bool pre_scheduler_sleep_needs_lock() const override { return true; } virtual void pre_scheduler_sleep_ns(uint64_t) override; virtual void handle_irq() override; diff --git a/kernel/include/kernel/Timer/Timer.h b/kernel/include/kernel/Timer/Timer.h index 65b61343..1a44be2a 100644 --- a/kernel/include/kernel/Timer/Timer.h +++ b/kernel/include/kernel/Timer/Timer.h @@ -17,6 +17,7 @@ namespace Kernel virtual uint64_t ns_since_boot() const = 0; virtual timespec time_since_boot() const = 0; + virtual bool pre_scheduler_sleep_needs_lock() const = 0; virtual void pre_scheduler_sleep_ns(uint64_t) = 0; void dont_invoke_scheduler() { m_should_invoke_scheduler = false; } @@ -39,6 +40,7 @@ namespace Kernel virtual uint64_t ns_since_boot() const override; virtual timespec time_since_boot() const override; + virtual bool pre_scheduler_sleep_needs_lock() const override; virtual void pre_scheduler_sleep_ns(uint64_t) override; void sleep_ms(uint64_t ms) const { return sleep_ns(ms * 1'000'000); } diff --git a/kernel/kernel/APIC.cpp b/kernel/kernel/APIC.cpp index 69bc0c9d..0b11a621 100644 --- a/kernel/kernel/APIC.cpp +++ b/kernel/kernel/APIC.cpp @@ -253,11 +253,11 @@ namespace Kernel const auto send_ipi = [&](uint8_t processor, uint32_t data, uint64_t ud) { + while ((read_from_local_apic(LAPIC_ICR_LO_REG) & ICR_LO_delivery_status_send_pending) == ICR_LO_delivery_status_send_pending) + __builtin_ia32_pause(); write_to_local_apic(LAPIC_ICR_HI_REG, (read_from_local_apic(LAPIC_ICR_HI_REG) & 0x00FFFFFF) | (processor << 24)); write_to_local_apic(LAPIC_ICR_LO_REG, data); udelay(ud); - while ((read_from_local_apic(LAPIC_ICR_LO_REG) & ICR_LO_delivery_status_send_pending) == ICR_LO_delivery_status_send_pending) - __builtin_ia32_pause(); }; dprintln("System has {} processors", m_processors.size()); @@ -402,21 +402,26 @@ namespace Kernel void APIC::initialize_timer() { - { - constexpr uint64_t measuring_duration_ms = 100; + ASSERT(Kernel::Processor::get_interrupt_state() == InterruptState::Disabled); - SpinLockGuard _(s_timer_init_lock); + constexpr uint64_t measuring_duration_ms = 100; - write_to_local_apic(LAPIC_TIMER_LVT, TimerModeOneShot | TimerMask); - write_to_local_apic(LAPIC_TIMER_DIVIDE_REG, DivideBy2); - write_to_local_apic(LAPIC_TIMER_INITIAL_REG, 0xFFFFFFFF); - SystemTimer::get().pre_scheduler_sleep_ns(measuring_duration_ms * 1'000'000); + const bool needs_lock = SystemTimer::get().pre_scheduler_sleep_needs_lock(); + if (needs_lock) + s_timer_init_lock.lock(); - const uint32_t counter = read_from_local_apic(LAPIC_TIMER_CURRENT_REG); - m_lapic_timer_frequency_hz = static_cast(0xFFFFFFFF - counter) * 2 * (1000 / measuring_duration_ms); + write_to_local_apic(LAPIC_TIMER_LVT, TimerModeOneShot | TimerMask); + write_to_local_apic(LAPIC_TIMER_DIVIDE_REG, DivideBy2); + write_to_local_apic(LAPIC_TIMER_INITIAL_REG, 0xFFFFFFFF); + SystemTimer::get().pre_scheduler_sleep_ns(measuring_duration_ms * 1'000'000); - dprintln("CPU {}: lapic timer frequency: {} Hz", Kernel::Processor::current_id(), m_lapic_timer_frequency_hz); - } + const uint32_t counter = read_from_local_apic(LAPIC_TIMER_CURRENT_REG); + m_lapic_timer_frequency_hz = static_cast(0xFFFFFFFF - counter) * 2 * (1000 / measuring_duration_ms); + + if (needs_lock) + s_timer_init_lock.unlock(InterruptState::Disabled); + + dprintln("CPU {}: lapic timer frequency: {} Hz", Kernel::Processor::current_id(), m_lapic_timer_frequency_hz); write_to_local_apic(LAPIC_TIMER_LVT, TimerModePeriodic | (IRQ_VECTOR_BASE + IRQ_TIMER)); write_to_local_apic(LAPIC_TIMER_INITIAL_REG, m_lapic_timer_frequency_hz / 2 / 100); diff --git a/kernel/kernel/Timer/Timer.cpp b/kernel/kernel/Timer/Timer.cpp index d4075bdf..ca9cb056 100644 --- a/kernel/kernel/Timer/Timer.cpp +++ b/kernel/kernel/Timer/Timer.cpp @@ -69,6 +69,11 @@ namespace Kernel return m_timer->time_since_boot(); } + bool SystemTimer::pre_scheduler_sleep_needs_lock() const + { + return m_timer->pre_scheduler_sleep_needs_lock(); + } + void SystemTimer::pre_scheduler_sleep_ns(uint64_t ns) { return m_timer->pre_scheduler_sleep_ns(ns);