mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 04:57:45 +00:00
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. :^)
This commit is contained in:
parent
c959344c00
commit
3cf8d3361e
2 changed files with 114 additions and 8 deletions
|
@ -5,27 +5,132 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Kernel/Arch/Interrupts.h>
|
#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 {
|
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)
|
||||||
{
|
{
|
||||||
VERIFY_NOT_REACHED();
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void register_generic_interrupt_handler(u8, GenericInterruptHandler&)
|
// 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)
|
||||||
{
|
{
|
||||||
VERIFY_NOT_REACHED();
|
auto*& handler_slot = s_interrupt_handlers[interrupt_number];
|
||||||
|
VERIFY(handler_slot != nullptr);
|
||||||
|
return *handler_slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unregister_generic_interrupt_handler(u8, GenericInterruptHandler&)
|
static void revert_to_unused_handler(u8 interrupt_number)
|
||||||
{
|
{
|
||||||
|
auto handler = new UnhandledInterruptHandler(interrupt_number);
|
||||||
|
handler->register_interrupt_handler();
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_generic_interrupt_handler(u8 interrupt_number, GenericInterruptHandler& handler)
|
||||||
|
{
|
||||||
|
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_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 interrupt_number, GenericInterruptHandler& handler)
|
||||||
|
{
|
||||||
|
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()
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.extern exception_common
|
.extern exception_common
|
||||||
|
.extern handle_interrupt
|
||||||
|
|
||||||
//
|
//
|
||||||
// Save all register states to the current stack
|
// Save all register states to the current stack
|
||||||
|
@ -161,7 +162,7 @@ synchronous_current_elsp_el0:
|
||||||
|
|
||||||
irq_current_elsp_el0:
|
irq_current_elsp_el0:
|
||||||
save_current_context
|
save_current_context
|
||||||
bl exception_common
|
bl handle_interrupt
|
||||||
restore_previous_context
|
restore_previous_context
|
||||||
eret
|
eret
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue