From 39c178338729e925b81286ffdac6cca58dfb9133 Mon Sep 17 00:00:00 2001 From: Liav A Date: Sat, 19 Dec 2020 08:49:15 +0200 Subject: [PATCH] Kernel: Allow to install a real IRQ handler on a spurious one IRQ 7 and 15 on the PIC architecture are used for spurious interrupts. IRQ 7 could also be used for LPT connection, and IRQ 15 can be used for the secondary IDE channel. Therefore, we need to allow to install a real IRQ handler and check if a real IRQ was asserted. If so, we handle them in the usual way. A note on this fix - unregistering or registering a new IRQ handler after we already registered one in the spurious interrupt handler is not supported yet. --- Kernel/Arch/i386/CPU.cpp | 4 +++ .../Interrupts/SpuriousInterruptHandler.cpp | 25 +++++++++++++++---- Kernel/Interrupts/SpuriousInterruptHandler.h | 1 + 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/Kernel/Arch/i386/CPU.cpp b/Kernel/Arch/i386/CPU.cpp index b863ab2597..4325495aa4 100644 --- a/Kernel/Arch/i386/CPU.cpp +++ b/Kernel/Arch/i386/CPU.cpp @@ -583,6 +583,10 @@ void register_generic_interrupt_handler(u8 interrupt_number, GenericInterruptHan return; } if (!s_interrupt_handler[interrupt_number]->is_shared_handler()) { + if (s_interrupt_handler[interrupt_number]->type() == HandlerType::SpuriousInterruptHandler) { + static_cast(s_interrupt_handler[interrupt_number])->register_handler(handler); + return; + } ASSERT(s_interrupt_handler[interrupt_number]->type() == HandlerType::IRQHandler); auto& previous_handler = *s_interrupt_handler[interrupt_number]; s_interrupt_handler[interrupt_number] = nullptr; diff --git a/Kernel/Interrupts/SpuriousInterruptHandler.cpp b/Kernel/Interrupts/SpuriousInterruptHandler.cpp index 4a886a588f..3b831d9b58 100644 --- a/Kernel/Interrupts/SpuriousInterruptHandler.cpp +++ b/Kernel/Interrupts/SpuriousInterruptHandler.cpp @@ -34,17 +34,25 @@ void SpuriousInterruptHandler::initialize(u8 interrupt_number) new SpuriousInterruptHandler(interrupt_number); } -void SpuriousInterruptHandler::register_handler(GenericInterruptHandler&) +void SpuriousInterruptHandler::register_handler(GenericInterruptHandler& handler) { + ASSERT(!m_real_handler); + m_real_handler = &handler; } void SpuriousInterruptHandler::unregister_handler(GenericInterruptHandler&) { + TODO(); } bool SpuriousInterruptHandler::eoi() { - // FIXME: Actually check if IRQ7 or IRQ15 are spurious, and if not, call EOI with the correct interrupt number. - m_responsible_irq_controller->eoi(*this); + // Actually check if IRQ7 or IRQ15 are spurious, and if not, call EOI with the correct interrupt number. + if (m_real_irq) { + m_responsible_irq_controller->eoi(*this); + m_real_irq = false; // return to default state! + return true; + } + m_responsible_irq_controller->spurious_eoi(*this); return false; } @@ -58,9 +66,15 @@ SpuriousInterruptHandler::~SpuriousInterruptHandler() { } -void SpuriousInterruptHandler::handle_interrupt(const RegisterState&) +void SpuriousInterruptHandler::handle_interrupt(const RegisterState& state) { - // FIXME: Actually check if IRQ7 or IRQ15 are spurious, and if not, call the real handler to handle the IRQ. + // Actually check if IRQ7 or IRQ15 are spurious, and if not, call the real handler to handle the IRQ. + if (m_responsible_irq_controller->get_isr() & (1 << 15)) { + m_real_irq = true; // remember that we had a real IRQ, when EOI later! + m_real_handler->increment_invoking_counter(); + m_real_handler->handle_interrupt(state); + return; + } klog() << "Spurious Interrupt, vector " << interrupt_number(); } @@ -74,6 +88,7 @@ void SpuriousInterruptHandler::enable_interrupt_vector() void SpuriousInterruptHandler::disable_interrupt_vector() { + ASSERT(!m_real_irq); // this flag should not be set when we call this method if (!m_enabled) return; m_enabled = false; diff --git a/Kernel/Interrupts/SpuriousInterruptHandler.h b/Kernel/Interrupts/SpuriousInterruptHandler.h index 82e4a624b9..7c6f4f04ad 100644 --- a/Kernel/Interrupts/SpuriousInterruptHandler.h +++ b/Kernel/Interrupts/SpuriousInterruptHandler.h @@ -58,6 +58,7 @@ private: void disable_interrupt_vector(); explicit SpuriousInterruptHandler(u8 interrupt_number); bool m_enabled; + bool m_real_irq { false }; RefPtr m_responsible_irq_controller; OwnPtr m_real_handler; };