diff options
Diffstat (limited to 'arch')
| -rw-r--r-- | arch/x86_64/kapi/cpu.cpp | 49 | ||||
| -rw-r--r-- | arch/x86_64/src/cpu/interrupts.cpp | 17 |
2 files changed, 53 insertions, 13 deletions
diff --git a/arch/x86_64/kapi/cpu.cpp b/arch/x86_64/kapi/cpu.cpp index 8ca3847..b19ba21 100644 --- a/arch/x86_64/kapi/cpu.cpp +++ b/arch/x86_64/kapi/cpu.cpp @@ -4,11 +4,22 @@ #include "arch/cpu/initialization.hpp" +#include <kstd/print> +#include <kstd/vector> + +#include <array> #include <atomic> +#include <cstdint> namespace kapi::cpu { + namespace + { + constexpr auto irq_offset = 32uz; + auto constinit interrupt_handlers = std::array<kstd::vector<interrupt_handler *>, 256 - irq_offset>{}; + } // namespace + auto init() -> void { auto static constinit is_initialized = std::atomic_flag{}; @@ -38,4 +49,42 @@ namespace kapi::cpu asm volatile("cli"); } + auto register_interrupt_handler(std::uint32_t irq_number, interrupt_handler & handler) -> void + { + if (irq_number < irq_offset) + { + system::panic("[x86_64:CPU] IRQ number must be in range [32, 255]."); + } + + interrupt_handlers[irq_number - irq_offset].push_back(&handler); + } + + auto unregister_interrupt_handler(std::uint32_t irq_number, [[maybe_unused]] interrupt_handler & handler) -> void + { + if (irq_number < irq_offset) + { + system::panic("[x86_64:CPU] IRQ number must be in range [32, 255]."); + } + + kstd::println("[x86_64:CPU] TODO: support erasure from vector."); + } + + auto dispatch_interrupt(std::uint32_t irq_number) -> status + { + if (irq_number < irq_offset) + { + return status::unhandled; + } + + for (auto handler : interrupt_handlers[irq_number - irq_offset]) + { + if (handler && handler->handle_interrupt(irq_number) == status::handled) + { + return status::handled; + } + } + + return status::unhandled; + } + } // namespace kapi::cpu diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index e578aa2..1f65336 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -46,7 +46,6 @@ namespace arch::cpu constexpr auto pic_master_irq_start = 0x20; constexpr auto pic_master_irq_end = pic_master_irq_start + 8; constexpr auto pic_slave_irq_start = pic_master_irq_end; - constexpr auto pic_slave_irq_end = pic_slave_irq_start + 8; constexpr auto to_exception_type(exception e) { @@ -96,10 +95,8 @@ namespace arch::cpu } } - auto handle_legacy_interrupt(interrupt_frame * frame) -> void + auto acknowledge_pic_interrupt(interrupt_frame * frame) -> void { - kstd::println("[x86_64:SYS] Ignoring 8259 legacy interrupt {:#04x}", frame->interrupt.number); - if (frame->interrupt.number >= pic_slave_irq_start) { pic_slave_control_port::write(pic_end_of_interrupt); @@ -120,19 +117,13 @@ namespace arch::cpu { kstd::println(kstd::print_sink::stderr, "[x86_64:CPU] Unhandled exception number {:#04x} received with code {:#04x}", number, code); - kapi::cpu::halt(); } - - if ((number >= pic_master_irq_start && number < pic_master_irq_end) || - (number >= pic_slave_irq_start && number < pic_slave_irq_end)) + else if (number >= pic_master_irq_start && kapi::cpu::dispatch_interrupt(number) == kapi::cpu::status::unhandled) { - handle_legacy_interrupt(frame); - return; + kstd::println(kstd::print_sink::stderr, "[x86_64:CPU] Unhandled interrupt {:#04x}", number); } - kstd::println(kstd::print_sink::stderr, "[x86_64:CPU] Unhandled interrupt {:#04x} received with code {:#04x}", - frame->interrupt.number, frame->interrupt.error_code); - kapi::cpu::halt(); + acknowledge_pic_interrupt(frame); } } |
