Kernel: Handle CLINT interrupts separately from normal interrupts

Since CLINT interrupts are wired directly into the hart, instead of
going through an interrupt controller (the PLIC), trying to handle them
through the normal numbered-interrupt mechanism will just complicate it
for no reason.
Instead we now handle them directly in the trap handler.
This commit is contained in:
Idan Horowitz 2024-04-23 20:26:11 +03:00 committed by Andrew Kaster
commit 0a2d520b15
Notes: sideshowbarker 2024-07-17 02:29:45 +09:00
3 changed files with 34 additions and 29 deletions

View file

@ -13,6 +13,7 @@
#include <Kernel/Arch/PageFault.h>
#include <Kernel/Arch/TrapFrame.h>
#include <Kernel/Arch/riscv64/InterruptManagement.h>
#include <Kernel/Arch/riscv64/Timer.h>
#include <Kernel/Interrupts/GenericInterruptHandler.h>
#include <Kernel/Interrupts/SharedIRQHandler.h>
#include <Kernel/Interrupts/UnhandledInterruptHandler.h>
@ -52,13 +53,11 @@ extern "C" void trap_handler(TrapFrame& trap_frame)
Processor::current().enter_trap(trap_frame, true);
auto interrupt_number = to_underlying(scause) & ~RISCV64::CSR::SCAUSE_INTERRUPT_MASK;
auto* handler = s_interrupt_handlers[interrupt_number];
VERIFY(handler);
handler->increment_call_count();
handler->handle_interrupt(*trap_frame.regs);
handler->eoi();
if (scause == RISCV64::CSR::SCAUSE::SupervisorTimerInterrupt) {
RISCV64::Timer::the().handle_interrupt(*trap_frame.regs);
} else {
TODO_RISCV64();
}
Processor::current().exit_trap(trap_frame);
} else {

View file

@ -5,43 +5,48 @@
*/
#include <AK/Format.h>
#include <AK/NeverDestroyed.h>
#include <Kernel/Arch/riscv64/CPU.h>
#include <Kernel/Arch/riscv64/SBI.h>
#include <Kernel/Arch/riscv64/Timer.h>
namespace Kernel::RISCV64 {
static Timer* s_the;
Timer::Timer()
: HardwareTimer(to_underlying(CSR::SCAUSE::SupervisorTimerInterrupt) & ~CSR::SCAUSE_INTERRUPT_MASK)
{
m_frequency = DeviceTree::get().resolve_property("/cpus/timebase-frequency"sv).value().as<u32>();
m_interrupt_interval = m_frequency / OPTIMAL_TICKS_PER_SECOND_RATE;
set_compare(current_ticks() + m_interrupt_interval);
RISCV64::CSR::set_bits(RISCV64::CSR::Address::SIE, 1 << interrupt_number());
RISCV64::CSR::set_bits(RISCV64::CSR::Address::SIE, 1 << (to_underlying(CSR::SCAUSE::SupervisorTimerInterrupt) & ~CSR::SCAUSE_INTERRUPT_MASK));
}
NonnullLockRefPtr<Timer> Timer::initialize()
{
VERIFY(!s_the);
auto timer = adopt_lock_ref(*new Timer);
timer->register_interrupt_handler();
s_the = timer.ptr();
return timer;
}
Timer& Timer::the()
{
VERIFY(s_the);
return *s_the;
}
u64 Timer::current_ticks()
{
return RISCV64::CSR::read(RISCV64::CSR::Address::TIME);
}
bool Timer::handle_interrupt(RegisterState const& regs)
void Timer::handle_interrupt(RegisterState const& regs)
{
auto result = HardwareTimer::handle_interrupt(regs);
if (m_callback)
m_callback(regs);
set_compare(current_ticks() + m_interrupt_interval);
return result;
}
u64 Timer::update_time(u64& seconds_since_boot, u32& ticks_this_second, bool query_only)
@ -77,12 +82,3 @@ void Timer::set_compare(u64 compare)
}
}
namespace Kernel {
bool HardwareTimer<GenericInterruptHandler>::eoi()
{
return true;
}
}

View file

@ -13,12 +13,14 @@
namespace Kernel::RISCV64 {
class Timer final : public HardwareTimer<GenericInterruptHandler> {
class Timer final : public HardwareTimerBase {
public:
static NonnullLockRefPtr<Timer> initialize();
static Timer& the();
virtual HardwareTimerType timer_type() const override { return HardwareTimerType::RISCVTimer; }
virtual StringView model() const override { return "RISC-V Timer"sv; }
virtual size_t ticks_per_second() const override { return m_frequency; }
virtual bool is_periodic() const override { TODO_RISCV64(); }
virtual bool is_periodic_capable() const override { TODO_RISCV64(); }
@ -31,8 +33,17 @@ public:
virtual bool is_capable_of_frequency(size_t) const override { TODO_RISCV64(); }
virtual size_t calculate_nearest_possible_frequency(size_t) const override { TODO_RISCV64(); }
virtual void will_be_destroyed() override { }
virtual Function<void(RegisterState const&)> set_callback(Function<void(RegisterState const&)> callback) override
{
auto previous_callback = move(m_callback);
m_callback = move(callback);
return previous_callback;
}
// FIXME: Share code with HPET::update_time
u64 update_time(u64& seconds_since_boot, u32& ticks_this_second, bool query_only);
void handle_interrupt(RegisterState const&);
private:
Timer();
@ -40,9 +51,8 @@ private:
static u64 current_ticks();
static void set_compare(u64 compare);
//^ GenericInterruptHandler
virtual bool handle_interrupt(RegisterState const&) override;
Function<void(RegisterState const&)> m_callback;
u64 m_frequency { 0 };
u32 m_interrupt_interval { 0 };
u64 m_main_counter_last_read { 0 };