Kernel: Set up and calibrate APIC timer, and enable timer on all CPUs

This enables the APIC timer on all CPUs, which means Scheduler::timer_tick
is now called on all CPUs independently. We still don't do anything on
the APs as it instantly crashes due to a number of other problems.
This commit is contained in:
Tom 2020-10-25 09:13:47 -06:00 committed by Andreas Kling
parent 9d347352a1
commit fe615e601a
Notes: sideshowbarker 2024-07-19 01:43:30 +09:00
14 changed files with 478 additions and 70 deletions

View file

@ -169,9 +169,9 @@ set(KERNEL_SOURCES
Tasks/SyncTask.cpp
Thread.cpp
ThreadTracer.cpp
Time/APICTimer.cpp
Time/HPET.cpp
Time/HPETComparator.cpp
Time/HardwareTimer.cpp
Time/PIT.cpp
Time/RTC.cpp
Time/TimeManagement.cpp

View file

@ -36,6 +36,7 @@
#include <Kernel/Interrupts/APIC.h>
#include <Kernel/Interrupts/SpuriousInterruptHandler.h>
#include <Kernel/Thread.h>
#include <Kernel/Time/APICTimer.h>
#include <Kernel/VM/MemoryManager.h>
#include <Kernel/VM/PageDirectory.h>
#include <Kernel/VM/TypedMapping.h>
@ -43,6 +44,7 @@
//#define APIC_DEBUG
//#define APIC_SMP_DEBUG
#define IRQ_APIC_TIMER (0xfc - IRQ_VECTOR_BASE)
#define IRQ_APIC_IPI (0xfd - IRQ_VECTOR_BASE)
#define IRQ_APIC_ERR (0xfe - IRQ_VECTOR_BASE)
#define IRQ_APIC_SPURIOUS (0xff - IRQ_VECTOR_BASE)
@ -66,6 +68,9 @@
#define APIC_REG_LVT_LINT0 0x350
#define APIC_REG_LVT_LINT1 0x360
#define APIC_REG_LVT_ERR 0x370
#define APIC_REG_TIMER_INITIAL_COUNT 0x380
#define APIC_REG_TIMER_CURRENT_COUNT 0x390
#define APIC_REG_TIMER_CONFIGURATION 0x3e0
namespace Kernel {
@ -197,9 +202,13 @@ void APIC::write_icr(const ICRReg& icr)
write_register(APIC_REG_ICR_LOW, icr.low());
}
#define APIC_LVT_TIMER_ONESHOT 0
#define APIC_LVT_TIMER_PERIODIC (1 << 17)
#define APIC_LVT_TIMER_TSCDEADLINE (1 << 18)
#define APIC_LVT_MASKED (1 << 16)
#define APIC_LVT_TRIGGER_LEVEL (1 << 14)
#define APIC_LVT(iv, dm) ((iv & 0xff) | ((dm & 0x7) << 8))
#define APIC_LVT(iv, dm) (((iv)&0xff) | (((dm)&0x7) << 8))
extern "C" void apic_ap_start(void);
extern "C" u16 apic_ap_start_size;
@ -519,6 +528,83 @@ void APIC::send_ipi(u32 cpu)
write_icr(ICRReg(IRQ_APIC_IPI + IRQ_VECTOR_BASE, ICRReg::Fixed, ICRReg::Logical, ICRReg::Assert, ICRReg::TriggerMode::Edge, ICRReg::NoShorthand, 1u << cpu));
}
APICTimer* APIC::initialize_timers(HardwareTimerBase& calibration_timer)
{
if (!m_apic_base)
return nullptr;
// We should only initialize and calibrate the APIC timer once on the BSP!
ASSERT(Processor::current().id() == 0);
ASSERT(!m_apic_timer);
m_apic_timer = APICTimer::initialize(IRQ_APIC_TIMER, calibration_timer);
return m_apic_timer;
}
void APIC::setup_local_timer(u32 ticks, TimerMode timer_mode, bool enable)
{
u32 flags = 0;
switch (timer_mode) {
case TimerMode::OneShot:
flags |= APIC_LVT_TIMER_ONESHOT;
break;
case TimerMode::Periodic:
flags |= APIC_LVT_TIMER_PERIODIC;
break;
case TimerMode::TSCDeadline:
flags |= APIC_LVT_TIMER_TSCDEADLINE;
break;
}
if (!enable)
flags |= APIC_LVT_MASKED;
write_register(APIC_REG_LVT_TIMER, APIC_LVT(IRQ_APIC_TIMER + IRQ_VECTOR_BASE, 0) | flags);
u32 config = read_register(APIC_REG_TIMER_CONFIGURATION);
config &= ~0xf; // clear divisor (bits 0-3)
switch (get_timer_divisor()) {
case 1:
config |= (1 << 3) | 3;
break;
case 2:
break;
case 4:
config |= 1;
break;
case 8:
config |= 2;
break;
case 16:
config |= 3;
break;
case 32:
config |= (1 << 3);
break;
case 64:
config |= (1 << 3) | 1;
break;
case 128:
config |= (1 << 3) | 2;
break;
default:
ASSERT_NOT_REACHED();
}
config |= 3; // divide by 16
write_register(APIC_REG_TIMER_CONFIGURATION, config);
if (timer_mode == TimerMode::Periodic)
write_register(APIC_REG_TIMER_INITIAL_COUNT, ticks / get_timer_divisor());
}
u32 APIC::get_timer_current_count()
{
return read_register(APIC_REG_TIMER_CURRENT_COUNT);
}
u32 APIC::get_timer_divisor()
{
return 16;
}
void APICIPIInterruptHandler::handle_interrupt(const RegisterState&)
{
#ifdef APIC_SMP_DEBUG
@ -546,4 +632,10 @@ bool APICErrInterruptHandler::eoi()
return true;
}
bool HardwareTimer<GenericInterruptHandler>::eoi()
{
APIC::the().eoi();
return true;
}
}

View file

@ -27,10 +27,13 @@
#pragma once
#include <AK/Types.h>
#include <Kernel/Time/HardwareTimer.h>
#include <Kernel/VM/MemoryManager.h>
namespace Kernel {
class APICTimer;
struct LocalAPIC {
u32 apic_id;
};
@ -52,6 +55,17 @@ public:
Thread* get_idle_thread(u32 cpu) const;
u32 enabled_processor_count() const { return m_processor_enabled_cnt; }
APICTimer* initialize_timers(HardwareTimerBase&);
APICTimer* get_timer() const { return m_apic_timer; }
enum class TimerMode {
OneShot,
Periodic,
TSCDeadline
};
void setup_local_timer(u32, TimerMode, bool);
u32 get_timer_current_count();
u32 get_timer_divisor();
private:
class ICRReg {
u32 m_low { 0 };
@ -102,6 +116,7 @@ private:
AK::Atomic<u8> m_apic_ap_continue { 0 };
u32 m_processor_cnt { 0 };
u32 m_processor_enabled_cnt { 0 };
APICTimer* m_apic_timer { nullptr };
static PhysicalAddress get_base();
static void set_base(const PhysicalAddress& base);

View file

@ -65,6 +65,8 @@ protected:
void change_interrupt_number(u8 number);
GenericInterruptHandler(u8 interrupt_number, bool disable_remap = false);
void disable_remap() { m_disable_remap = true; }
private:
size_t m_invoking_count { 0 };
u8 m_interrupt_number { 0 };

View file

@ -777,15 +777,19 @@ void Scheduler::timer_tick(const RegisterState& regs)
ASSERT_INTERRUPTS_DISABLED();
ASSERT(Processor::current().in_irq());
if (Processor::current().id() > 0)
return;
auto current_thread = Processor::current().current_thread();
if (!current_thread)
return;
++g_uptime;
bool is_bsp = Processor::current().id() == 0;
if (!is_bsp)
return; // TODO: This prevents scheduling on other CPUs!
if (is_bsp) {
// TODO: We should probably move this out of the scheduler
++g_uptime;
g_timeofday = TimeManagement::now_as_timeval();
g_timeofday = TimeManagement::now_as_timeval();
}
if (current_thread->process().is_profiling()) {
SmapDisabler disabler;
@ -799,7 +803,8 @@ void Scheduler::timer_tick(const RegisterState& regs)
}
}
TimerQueue::the().fire();
if (is_bsp)
TimerQueue::the().fire();
if (current_thread->tick())
return;

183
Kernel/Time/APICTimer.cpp Normal file
View file

@ -0,0 +1,183 @@
/*
* Copyright (c) 2020, the SerenityOS developers
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <Kernel/Arch/i386/CPU.h>
#include <Kernel/IO.h>
#include <Kernel/Interrupts/APIC.h>
#include <Kernel/Scheduler.h>
#include <Kernel/Thread.h>
#include <Kernel/Time/APICTimer.h>
#include <Kernel/Time/TimeManagement.h>
namespace Kernel {
#define APIC_TIMER_MEASURE_CPU_CLOCK
APICTimer* APICTimer::initialize(u8 interrupt_number, HardwareTimerBase& calibration_source)
{
auto* timer = new APICTimer(interrupt_number, nullptr);
if (!timer->calibrate(calibration_source)) {
delete timer;
return nullptr;
}
return timer;
}
APICTimer::APICTimer(u8 interrupt_number, Function<void(const RegisterState&)> callback)
: HardwareTimer<GenericInterruptHandler>(interrupt_number, move(callback))
{
disable_remap();
}
bool APICTimer::calibrate(HardwareTimerBase& calibration_source)
{
ASSERT_INTERRUPTS_DISABLED();
klog() << "APICTimer: Using " << calibration_source.model() << " as calibration source";
auto& apic = APIC::the();
#ifdef APIC_TIMER_MEASURE_CPU_CLOCK
bool supports_tsc = Processor::current().has_feature(CPUFeature::TSC);
#endif
// temporarily replace the timer callbacks
const size_t ticks_in_100ms = calibration_source.ticks_per_second() / 10;
Atomic<size_t> calibration_ticks = 0;
#ifdef APIC_TIMER_MEASURE_CPU_CLOCK
volatile u64 start_tsc = 0, end_tsc = 0;
#endif
volatile u32 start_apic_count = 0, end_apic_count = 0;
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
auto prev_tick = calibration_ticks.fetch_add(1, AK::memory_order_acq_rel);
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) {
#ifdef APIC_TIMER_MEASURE_CPU_CLOCK
end_tsc = current_tsc;
#endif
end_apic_count = current_timer_count;
}
});
// Setup a counter that should be much longer than our calibration time.
// We don't want the APIC timer to actually fire. We do however want the
// calbibration_source timer to fire so that we can read the current
// tick count from the APIC timer
auto original_callback = set_callback([&](const RegisterState&) {
klog() << "APICTimer: Timer fired during calibration!";
ASSERT_NOT_REACHED(); // TODO: How should we handle this?
});
apic.setup_local_timer(0xffffffff, APIC::TimerMode::Periodic, true);
sti();
// Loop for about 100 ms
while (calibration_ticks.load(AK::memory_order_relaxed) < ticks_in_100ms)
;
cli();
// Restore timer callbacks
calibration_source.set_callback(move(original_source_callback));
set_callback(move(original_callback));
disable_local_timer();
auto delta_apic_count = end_apic_count - start_apic_count;
m_timer_period = (delta_apic_count * apic.get_timer_divisor()) / ticks_in_100ms;
auto apic_freq = (delta_apic_count * 16) / apic.get_timer_divisor();
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;
klog() << "APICTimer: CPU clock speed: " << (delta_tsc / 1000000) << "." << (delta_tsc % 1000000) << " MHz";
}
#endif
enable_local_timer();
return true;
}
void APICTimer::enable_local_timer()
{
APIC::the().setup_local_timer(m_timer_period, m_timer_mode, true);
}
void APICTimer::disable_local_timer()
{
APIC::the().setup_local_timer(0, APIC::TimerMode::OneShot, false);
}
size_t APICTimer::ticks_per_second() const
{
return m_frequency;
}
void APICTimer::set_periodic()
{
// FIXME: Implement it...
ASSERT_NOT_REACHED();
}
void APICTimer::set_non_periodic()
{
// FIXME: Implement it...
ASSERT_NOT_REACHED();
}
void APICTimer::reset_to_default_ticks_per_second()
{
}
bool APICTimer::try_to_set_frequency(size_t frequency)
{
(void)frequency;
return true;
}
bool APICTimer::is_capable_of_frequency(size_t frequency) const
{
(void)frequency;
return false;
}
size_t APICTimer::calculate_nearest_possible_frequency(size_t frequency) const
{
(void)frequency;
return 0;
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
* Copyright (c) 2020, the SerenityOS developers
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -24,35 +24,42 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <AK/NonnullRefPtr.h>
#include <AK/Types.h>
#include <Kernel/Interrupts/GenericInterruptHandler.h>
#include <Kernel/Time/HardwareTimer.h>
#include <Kernel/Time/TimeManagement.h>
namespace Kernel {
HardwareTimer::HardwareTimer(u8 irq_number, Function<void(const RegisterState&)> callback)
: IRQHandler(irq_number)
, m_callback(move(callback))
{
}
class APICTimer final : public HardwareTimer<GenericInterruptHandler> {
public:
static APICTimer* initialize(u8, HardwareTimerBase&);
virtual HardwareTimerType timer_type() const override { return HardwareTimerType::LocalAPICTimer; }
virtual const char* model() const override { return "LocalAPIC"; }
virtual size_t ticks_per_second() const override;
void HardwareTimer::handle_irq(const RegisterState& regs)
{
if (m_callback)
m_callback(regs);
}
virtual bool is_periodic() const override { return m_timer_mode == APIC::TimerMode::Periodic; }
virtual bool is_periodic_capable() const override { return true; }
virtual void set_periodic() override;
virtual void set_non_periodic() override;
const char* HardwareTimer::purpose() const
{
if (TimeManagement::the().is_system_timer(*this))
return "System Timer";
return model();
}
virtual void reset_to_default_ticks_per_second() override;
virtual bool try_to_set_frequency(size_t frequency) override;
virtual bool is_capable_of_frequency(size_t frequency) const override;
virtual size_t calculate_nearest_possible_frequency(size_t frequency) const override;
void HardwareTimer::set_callback(Function<void(const RegisterState&)> callback)
{
disable_irq();
m_callback = move(callback);
enable_irq();
}
void enable_local_timer();
void disable_local_timer();
private:
explicit APICTimer(u8, Function<void(const RegisterState&)>);
bool calibrate(HardwareTimerBase&);
u32 m_timer_period { 0 };
APIC::TimerMode m_timer_mode { APIC::TimerMode::Periodic };
};
}

View file

@ -32,7 +32,7 @@
#include <Kernel/Time/HardwareTimer.h>
namespace Kernel {
class HPETComparator final : public HardwareTimer {
class HPETComparator final : public HardwareTimer<IRQHandler> {
friend class HPET;
public:

View file

@ -35,37 +35,114 @@
namespace Kernel {
enum class HardwareTimerType {
i8253 = 0x1, /* PIT */
RTC = 0x2, /* Real Time Clock */
HighPrecisionEventTimer = 0x3 /* also known as IA-PC HPET */
i8253 = 0x1, /* PIT */
RTC = 0x2, /* Real Time Clock */
HighPrecisionEventTimer = 0x3, /* also known as IA-PC HPET */
LocalAPICTimer = 0x4 /* Local APIC */
};
class HardwareTimer
: public RefCounted<HardwareTimer>
, public IRQHandler {
template<typename InterruptHandlerType>
class HardwareTimer;
class HardwareTimerBase
: public RefCounted<HardwareTimerBase> {
public:
virtual HardwareTimerType timer_type() const = 0;
virtual ~HardwareTimerBase() { }
virtual const char* model() const = 0;
virtual const char* purpose() const override;
void set_callback(Function<void(const RegisterState&)>);
virtual size_t ticks_per_second() const = 0;
virtual HardwareTimerType timer_type() const = 0;
virtual Function<void(const RegisterState&)> set_callback(Function<void(const RegisterState&)>) = 0;
virtual bool is_periodic() const = 0;
virtual bool is_periodic_capable() const = 0;
virtual void set_periodic() = 0;
virtual void set_non_periodic() = 0;
virtual size_t ticks_per_second() const = 0;
virtual void reset_to_default_ticks_per_second() = 0;
virtual bool try_to_set_frequency(size_t frequency) = 0;
virtual bool is_capable_of_frequency(size_t frequency) const = 0;
virtual size_t calculate_nearest_possible_frequency(size_t frequency) const = 0;
};
template<>
class HardwareTimer<IRQHandler>
: public HardwareTimerBase
, public IRQHandler {
public:
virtual const char* purpose() const override
{
if (TimeManagement::the().is_system_timer(*this))
return "System Timer";
return model();
}
virtual Function<void(const RegisterState&)> set_callback(Function<void(const RegisterState&)> callback) override
{
disable_irq();
auto previous_callback = move(m_callback);
m_callback = move(callback);
enable_irq();
return previous_callback;
}
protected:
HardwareTimer(u8 irq_number, Function<void(const RegisterState&)> = nullptr);
//^IRQHandler
virtual void handle_irq(const RegisterState&) override;
HardwareTimer(u8 irq_number, Function<void(const RegisterState&)> callback = nullptr)
: IRQHandler(irq_number)
, m_callback(move(callback))
{
}
virtual void handle_irq(const RegisterState& regs) override
{
if (m_callback)
m_callback(regs);
}
u64 m_frequency { OPTIMAL_TICKS_PER_SECOND_RATE };
private:
Function<void(const RegisterState&)> m_callback;
};
template<>
class HardwareTimer<GenericInterruptHandler>
: public HardwareTimerBase
, public GenericInterruptHandler {
public:
virtual const char* purpose() const override
{
return model();
}
virtual Function<void(const RegisterState&)> set_callback(Function<void(const RegisterState&)> callback) override
{
auto previous_callback = move(m_callback);
m_callback = move(callback);
return previous_callback;
}
virtual size_t sharing_devices_count() const override { return 0; }
virtual bool is_shared_handler() const override { return false; }
virtual bool is_sharing_with_others() const { return false; }
virtual HandlerType type() const override { return HandlerType::IRQHandler; }
virtual const char* controller() const override { return nullptr; }
virtual bool eoi() override;
protected:
HardwareTimer(u8 irq_number, Function<void(const RegisterState&)> callback = nullptr)
: GenericInterruptHandler(irq_number)
, m_callback(move(callback))
{
}
virtual void handle_interrupt(const RegisterState& regs) override
{
if (m_callback)
m_callback(regs);
}
u64 m_frequency { OPTIMAL_TICKS_PER_SECOND_RATE };
private:

View file

@ -52,7 +52,7 @@ namespace Kernel {
#define BASE_FREQUENCY 1193182
class PIT final : public HardwareTimer {
class PIT final : public HardwareTimer<IRQHandler> {
public:
static NonnullRefPtr<PIT> initialize(Function<void(const RegisterState&)>);
virtual HardwareTimerType timer_type() const override { return HardwareTimerType::i8253; }

View file

@ -31,7 +31,7 @@
#include <Kernel/Time/HardwareTimer.h>
namespace Kernel {
class RealTimeClock final : public HardwareTimer {
class RealTimeClock final : public HardwareTimer<IRQHandler> {
public:
static NonnullRefPtr<RealTimeClock> create(Function<void(const RegisterState&)> callback);
virtual HardwareTimerType timer_type() const override { return HardwareTimerType::RTC; }

View file

@ -28,7 +28,9 @@
#include <AK/Time.h>
#include <Kernel/ACPI/Parser.h>
#include <Kernel/CommandLine.h>
#include <Kernel/Interrupts/APIC.h>
#include <Kernel/Scheduler.h>
#include <Kernel/Time/APICTimer.h>
#include <Kernel/Time/HPET.h>
#include <Kernel/Time/HPETComparator.h>
#include <Kernel/Time/HardwareTimer.h>
@ -48,7 +50,7 @@ TimeManagement& TimeManagement::the()
return *s_the;
}
bool TimeManagement::is_system_timer(const HardwareTimer& timer) const
bool TimeManagement::is_system_timer(const HardwareTimerBase& timer) const
{
return &timer == m_system_timer.ptr();
}
@ -69,11 +71,36 @@ timespec TimeManagement::epoch_time() const
return ts;
}
void TimeManagement::initialize()
void TimeManagement::initialize(u32 cpu)
{
ASSERT(!s_the.is_initialized());
s_the.ensure_instance();
if (cpu == 0) {
ASSERT(!s_the.is_initialized());
s_the.ensure_instance();
// Initialize the APIC timers after the other timers as the
// initialization needs to briefly enable interrupts, which then
// would trigger a deadlock trying to get the s_the instance while
// creating it.
if (auto* apic_timer = APIC::the().initialize_timers(*s_the->m_system_timer)) {
klog() << "Time: Using APIC timer as system timer";
s_the->set_system_timer(*apic_timer);
}
} else {
ASSERT(s_the.is_initialized());
if (auto* apic_timer = APIC::the().get_timer()) {
klog() << "Time: Enable APIC timer on CPU #" << cpu;
apic_timer->enable_local_timer();
}
}
}
void TimeManagement::set_system_timer(HardwareTimerBase& timer)
{
auto original_callback = m_system_timer->set_callback(nullptr);
timer.set_callback(move(original_callback));
m_system_timer = timer;
}
time_t TimeManagement::seconds_since_boot() const
{
return m_seconds_since_boot;
@ -112,11 +139,9 @@ TimeManagement::TimeManagement()
if (!probe_and_set_non_legacy_hardware_timers())
if (!probe_and_set_legacy_hardware_timers())
ASSERT_NOT_REACHED();
return;
} else if (!probe_and_set_legacy_hardware_timers()) {
ASSERT_NOT_REACHED();
}
if (probe_and_set_legacy_hardware_timers())
return;
ASSERT_NOT_REACHED();
}
timeval TimeManagement::now_as_timeval()
@ -127,11 +152,11 @@ timeval TimeManagement::now_as_timeval()
return tv;
}
Vector<HardwareTimer*> TimeManagement::scan_and_initialize_periodic_timers()
Vector<HardwareTimerBase*> TimeManagement::scan_and_initialize_periodic_timers()
{
bool should_enable = is_hpet_periodic_mode_allowed();
dbg() << "Time: Scanning for periodic timers";
Vector<HardwareTimer*> timers;
Vector<HardwareTimerBase*> timers;
for (auto& hardware_timer : m_hardware_timers) {
if (hardware_timer.is_periodic_capable()) {
timers.append(&hardware_timer);
@ -142,10 +167,10 @@ Vector<HardwareTimer*> TimeManagement::scan_and_initialize_periodic_timers()
return timers;
}
Vector<HardwareTimer*> TimeManagement::scan_for_non_periodic_timers()
Vector<HardwareTimerBase*> TimeManagement::scan_for_non_periodic_timers()
{
dbg() << "Time: Scanning for non-periodic timers";
Vector<HardwareTimer*> timers;
Vector<HardwareTimerBase*> timers;
for (auto& hardware_timer : m_hardware_timers) {
if (!hardware_timer.is_periodic_capable())
timers.append(&hardware_timer);

View file

@ -35,7 +35,7 @@ namespace Kernel {
#define OPTIMAL_TICKS_PER_SECOND_RATE 1000
class HardwareTimer;
class HardwareTimerBase;
class TimeManagement {
AK_MAKE_ETERNAL;
@ -43,7 +43,7 @@ class TimeManagement {
public:
TimeManagement();
static bool initialized();
static void initialize();
static void initialize(u32 cpu);
static TimeManagement& the();
timespec epoch_time() const;
@ -53,7 +53,7 @@ public:
time_t ticks_this_second() const;
time_t boot_time() const;
bool is_system_timer(const HardwareTimer&) const;
bool is_system_timer(const HardwareTimerBase&) const;
static void update_time(const RegisterState&);
void increment_time_since_boot(const RegisterState&);
@ -65,15 +65,16 @@ public:
private:
bool probe_and_set_legacy_hardware_timers();
bool probe_and_set_non_legacy_hardware_timers();
Vector<HardwareTimer*> scan_and_initialize_periodic_timers();
Vector<HardwareTimer*> scan_for_non_periodic_timers();
NonnullRefPtrVector<HardwareTimer> m_hardware_timers;
Vector<HardwareTimerBase*> scan_and_initialize_periodic_timers();
Vector<HardwareTimerBase*> scan_for_non_periodic_timers();
NonnullRefPtrVector<HardwareTimerBase> m_hardware_timers;
void set_system_timer(HardwareTimerBase&);
u32 m_ticks_this_second { 0 };
u32 m_seconds_since_boot { 0 };
timespec m_epoch_time { 0, 0 };
RefPtr<HardwareTimer> m_system_timer;
RefPtr<HardwareTimer> m_time_keeper_timer;
RefPtr<HardwareTimerBase> m_system_timer;
RefPtr<HardwareTimerBase> m_time_keeper_timer;
};
}

View file

@ -149,7 +149,7 @@ extern "C" [[noreturn]] void init()
__stack_chk_guard = get_fast_random<u32>();
TimeManagement::initialize();
TimeManagement::initialize(0);
NullDevice::initialize();
if (!get_serial_debug())
@ -208,6 +208,7 @@ extern "C" void init_finished(u32 cpu)
// TODO: we can reuse the boot stack, maybe for kmalloc()?
} else {
APIC::the().init_finished(cpu);
TimeManagement::initialize(cpu);
}
}