diff --git a/Kernel/Arch/aarch64/Interrupts.cpp b/Kernel/Arch/aarch64/Interrupts.cpp index b319fb123d..398b17d53b 100644 --- a/Kernel/Arch/aarch64/Interrupts.cpp +++ b/Kernel/Arch/aarch64/Interrupts.cpp @@ -5,20 +5,21 @@ */ #include +#include #include #include #include #include -struct TrapFrame; - namespace Kernel { static Array s_interrupt_handlers; -extern "C" void handle_interrupt(TrapFrame const* const); -extern "C" void handle_interrupt(TrapFrame const* const) +extern "C" void handle_interrupt(TrapFrame&); +extern "C" void handle_interrupt(TrapFrame& trap_frame) { + Processor::current().enter_trap(trap_frame, true); + for (auto& interrupt_controller : InterruptManagement::the().controllers()) { auto pending_interrupts = interrupt_controller->pending_interrupts(); @@ -31,20 +32,18 @@ extern "C" void handle_interrupt(TrapFrame const* const) continue; } - // TODO: Consider not passing the RegisterState into the handle_interrupt() - // function, since no IRQHandler seems to be using the registers. - RegisterState regs {}; - auto* handler = s_interrupt_handlers[irq]; VERIFY(handler); handler->increment_call_count(); - handler->handle_interrupt(regs); + handler->handle_interrupt(*trap_frame.regs); handler->eoi(); irq += 1; pending_interrupts >>= 1; } } + + Processor::current().exit_trap(trap_frame); } // FIXME: Share the code below with Arch/x86_64/Interrupts.cpp diff --git a/Kernel/Arch/aarch64/Processor.cpp b/Kernel/Arch/aarch64/Processor.cpp index 4f9dcbcfa8..23a0cf6f08 100644 --- a/Kernel/Arch/aarch64/Processor.cpp +++ b/Kernel/Arch/aarch64/Processor.cpp @@ -8,8 +8,11 @@ #include #include +#include #include #include +#include +#include extern "C" uintptr_t vector_table_el1; @@ -92,6 +95,72 @@ FlatPtr Processor::init_context(Thread& thread, bool leave_crit) TODO_AARCH64(); } +void Processor::enter_trap(TrapFrame& trap, bool raise_irq) +{ + VERIFY_INTERRUPTS_DISABLED(); + VERIFY(&Processor::current() == this); + // FIXME: Figure out if we need prev_irq_level, see duplicated code in Kernel/Arch/x86/common/Processor.cpp + if (raise_irq) + m_in_irq++; + auto* current_thread = Processor::current_thread(); + if (current_thread) { + auto& current_trap = current_thread->current_trap(); + trap.next_trap = current_trap; + current_trap = &trap; + // FIXME: Determine PreviousMode from TrapFrame when userspace programs can run on aarch64 + auto new_previous_mode = Thread::PreviousMode::KernelMode; + if (current_thread->set_previous_mode(new_previous_mode)) { + current_thread->update_time_scheduled(TimeManagement::scheduler_current_time(), new_previous_mode == Thread::PreviousMode::KernelMode, false); + } + } else { + trap.next_trap = nullptr; + } +} + +void Processor::exit_trap(TrapFrame& trap) +{ + VERIFY_INTERRUPTS_DISABLED(); + VERIFY(&Processor::current() == this); + + // Temporarily enter a critical section. This is to prevent critical + // sections entered and left within e.g. smp_process_pending_messages + // to trigger a context switch while we're executing this function + // See the comment at the end of the function why we don't use + // ScopedCritical here. + m_in_critical = m_in_critical + 1; + + // FIXME: Figure out if we need prev_irq_level, see duplicated code in Kernel/Arch/x86/common/Processor.cpp + m_in_irq = 0; + + auto* current_thread = Processor::current_thread(); + if (current_thread) { + auto& current_trap = current_thread->current_trap(); + current_trap = trap.next_trap; + Thread::PreviousMode new_previous_mode; + if (current_trap) { + VERIFY(current_trap->regs); + // FIXME: Determine PreviousMode from TrapFrame when userspace programs can run on aarch64 + new_previous_mode = Thread::PreviousMode::KernelMode; + } else { + // If we don't have a higher level trap then we're back in user mode. + // Which means that the previous mode prior to being back in user mode was kernel mode + new_previous_mode = Thread::PreviousMode::KernelMode; + } + + if (current_thread->set_previous_mode(new_previous_mode)) + current_thread->update_time_scheduled(TimeManagement::scheduler_current_time(), true, false); + } + + VERIFY_INTERRUPTS_DISABLED(); + + // Leave the critical section without actually enabling interrupts. + // We don't want context switches to happen until we're explicitly + // triggering a switch in check_invoke_scheduler. + m_in_critical = m_in_critical - 1; + if (!m_in_irq && !m_in_critical) + check_invoke_scheduler(); +} + ErrorOr> Processor::capture_stack_trace(Thread& thread, size_t max_frames) { (void)thread; diff --git a/Kernel/Arch/aarch64/Processor.h b/Kernel/Arch/aarch64/Processor.h index 1974798bfd..4b8a30b907 100644 --- a/Kernel/Arch/aarch64/Processor.h +++ b/Kernel/Arch/aarch64/Processor.h @@ -24,6 +24,7 @@ class PageDirectory; class Thread; class Processor; +class TrapFrame; // FIXME This needs to go behind some sort of platform abstraction // it is used between Thread and Processor. @@ -260,6 +261,9 @@ public: FlatPtr init_context(Thread& thread, bool leave_crit); static ErrorOr> capture_stack_trace(Thread& thread, size_t max_frames = 0); + void enter_trap(TrapFrame& trap, bool raise_irq); + void exit_trap(TrapFrame& trap); + private: Thread* m_current_thread; Thread* m_idle_thread;