diff options
author | Timon Kruiper <timonkruiper@gmail.com> | 2022-05-30 10:14:46 +0200 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-06-02 13:14:12 +0100 |
commit | 3cf8d3361e347da561f7a67dffa988969cc08914 (patch) | |
tree | eaae9eba38cf9646dfb717857a4fc0afccc58f00 /Kernel | |
parent | c959344c00e1b68d95cf57e5ed7b05259359d99b (diff) | |
download | serenity-3cf8d3361e347da561f7a67dffa988969cc08914.zip |
Kernel: Add support for handling interrupts on aarch64
There is currently some code duplication between the aarch64
implementation and the x86 one, but this initial implementation works
for now. :^)
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/Arch/aarch64/Interrupts.cpp | 119 | ||||
-rw-r--r-- | Kernel/Arch/aarch64/vector_table.S | 3 |
2 files changed, 114 insertions, 8 deletions
diff --git a/Kernel/Arch/aarch64/Interrupts.cpp b/Kernel/Arch/aarch64/Interrupts.cpp index 5a69b1a0c3..a14db353f5 100644 --- a/Kernel/Arch/aarch64/Interrupts.cpp +++ b/Kernel/Arch/aarch64/Interrupts.cpp @@ -5,27 +5,132 @@ */ #include <Kernel/Arch/Interrupts.h> +#include <Kernel/Arch/aarch64/InterruptManagement.h> +#include <Kernel/Interrupts/GenericInterruptHandler.h> +#include <Kernel/Interrupts/SharedIRQHandler.h> +#include <Kernel/Interrupts/UnhandledInterruptHandler.h> + +struct TrapFrame; namespace Kernel { -GenericInterruptHandler& get_interrupt_handler(u8) +static Array<GenericInterruptHandler*, 64> s_interrupt_handlers; + +extern "C" void handle_interrupt(TrapFrame const* const); +extern "C" void handle_interrupt(TrapFrame const* const) +{ + for (auto& interrupt_controller : InterruptManagement::the().controllers()) { + auto pending_interrupts = interrupt_controller->pending_interrupts(); + + // TODO: Add these interrupts as a source of entropy for randomness. + u8 irq = 0; + while (pending_interrupts) { + if ((pending_interrupts & 0b1) != 0b1) { + irq += 1; + pending_interrupts >>= 1; + 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_invoking_counter(); + handler->handle_interrupt(regs); + handler->eoi(); + + irq += 1; + pending_interrupts >>= 1; + } + } +} + +// FIXME: Share the code below with Arch/x86/common/Interrupts.cpp +// While refactoring, the interrupt handlers can also be moved into the InterruptManagement class. +GenericInterruptHandler& get_interrupt_handler(u8 interrupt_number) +{ + auto*& handler_slot = s_interrupt_handlers[interrupt_number]; + VERIFY(handler_slot != nullptr); + return *handler_slot; +} + +static void revert_to_unused_handler(u8 interrupt_number) { - VERIFY_NOT_REACHED(); + auto handler = new UnhandledInterruptHandler(interrupt_number); + handler->register_interrupt_handler(); } -void register_generic_interrupt_handler(u8, GenericInterruptHandler&) +void register_generic_interrupt_handler(u8 interrupt_number, GenericInterruptHandler& handler) { - VERIFY_NOT_REACHED(); + auto*& handler_slot = s_interrupt_handlers[interrupt_number]; + if (handler_slot != nullptr) { + if (handler_slot->type() == HandlerType::UnhandledInterruptHandler) { + if (handler_slot) { + auto* unhandled_handler = static_cast<UnhandledInterruptHandler*>(handler_slot); + unhandled_handler->unregister_interrupt_handler(); + delete unhandled_handler; + } + handler_slot = &handler; + return; + } + if (handler_slot->is_shared_handler() && !handler_slot->is_sharing_with_others()) { + VERIFY(handler_slot->type() == HandlerType::SharedIRQHandler); + static_cast<SharedIRQHandler*>(handler_slot)->register_handler(handler); + return; + } + if (!handler_slot->is_shared_handler()) { + if (handler_slot->type() == HandlerType::SpuriousInterruptHandler) { + // FIXME: Add support for spurious interrupts on aarch64 + VERIFY_NOT_REACHED(); + } + VERIFY(handler_slot->type() == HandlerType::IRQHandler); + auto& previous_handler = *handler_slot; + handler_slot = nullptr; + SharedIRQHandler::initialize(interrupt_number); + VERIFY(handler_slot); + static_cast<SharedIRQHandler*>(handler_slot)->register_handler(previous_handler); + static_cast<SharedIRQHandler*>(handler_slot)->register_handler(handler); + return; + } + VERIFY_NOT_REACHED(); + } else { + handler_slot = &handler; + } } -void unregister_generic_interrupt_handler(u8, GenericInterruptHandler&) +void unregister_generic_interrupt_handler(u8 interrupt_number, GenericInterruptHandler& handler) { - VERIFY_NOT_REACHED(); + auto*& handler_slot = s_interrupt_handlers[interrupt_number]; + VERIFY(handler_slot != nullptr); + if (handler_slot->type() == HandlerType::UnhandledInterruptHandler) { + return; + } + if (handler_slot->is_shared_handler() && !handler_slot->is_sharing_with_others()) { + VERIFY(handler_slot->type() == HandlerType::SharedIRQHandler); + auto* shared_handler = static_cast<SharedIRQHandler*>(handler_slot); + shared_handler->unregister_handler(handler); + if (!shared_handler->sharing_devices_count()) { + handler_slot = nullptr; + revert_to_unused_handler(interrupt_number); + } + return; + } + if (!handler_slot->is_shared_handler()) { + VERIFY(handler_slot->type() == HandlerType::IRQHandler); + handler_slot = nullptr; + revert_to_unused_handler(interrupt_number); + return; + } } void initialize_interrupts() { - VERIFY_NOT_REACHED(); + for (u8 i = 0; i < s_interrupt_handlers.size(); ++i) { + auto* handler = new UnhandledInterruptHandler(i); + handler->register_interrupt_handler(); + } } } diff --git a/Kernel/Arch/aarch64/vector_table.S b/Kernel/Arch/aarch64/vector_table.S index dde2f602c0..13e6b7d400 100644 --- a/Kernel/Arch/aarch64/vector_table.S +++ b/Kernel/Arch/aarch64/vector_table.S @@ -26,6 +26,7 @@ .endm .extern exception_common +.extern handle_interrupt // // Save all register states to the current stack @@ -161,7 +162,7 @@ synchronous_current_elsp_el0: irq_current_elsp_el0: save_current_context - bl exception_common + bl handle_interrupt restore_previous_context eret |