From 88c5992e0bbaef2e19974b99f26a05a36710700e Mon Sep 17 00:00:00 2001 From: Liav A Date: Fri, 28 Jan 2022 18:18:14 +0200 Subject: [PATCH] Kernel/Interrupts: Initialize two spurious handlers when PIC is disabled Even if the PIC was disabled it can still generate noise (spurious IRQs) so we need to register two handlers for handling such cases. Also, we declare interrupt service routine offset 0x20 to 0x2f as reserved, so when the PIC is disabled, we can handle spurious IRQs from the PIC at separate handlers. --- Kernel/Arch/x86/ISRStubs.h | 48 +++++++++++ Kernel/Arch/x86/Interrupts.h | 1 + Kernel/Arch/x86/common/Interrupts.cpp | 86 +++++++++++++++++-- Kernel/Interrupts/InterruptManagement.cpp | 11 +++ Kernel/Interrupts/InterruptManagement.h | 1 + Kernel/Interrupts/PIC.h | 1 + .../Interrupts/SpuriousInterruptHandler.cpp | 22 +++++ Kernel/Interrupts/SpuriousInterruptHandler.h | 4 + 8 files changed, 169 insertions(+), 5 deletions(-) diff --git a/Kernel/Arch/x86/ISRStubs.h b/Kernel/Arch/x86/ISRStubs.h index 9f9d4ea39a..1108d8556a 100644 --- a/Kernel/Arch/x86/ISRStubs.h +++ b/Kernel/Arch/x86/ISRStubs.h @@ -11,6 +11,54 @@ #include VALIDATE_IS_X86() +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(32) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(33) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(34) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(35) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(36) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(37) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(38) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(39) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(40) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(41) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(42) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(43) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(44) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(45) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(46) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(47) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(48) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(49) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(50) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(51) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(52) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(53) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(54) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(55) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(56) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(57) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(58) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(59) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(60) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(61) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(62) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(63) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(64) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(65) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(66) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(67) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(68) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(69) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(70) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(71) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(72) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(73) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(74) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(75) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(76) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(77) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(78) +GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(79) GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(80) GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(81) GENERATE_GENERIC_INTERRUPT_HANDLER_ASM_ENTRY(82) diff --git a/Kernel/Arch/x86/Interrupts.h b/Kernel/Arch/x86/Interrupts.h index 6fafca5365..ef3fe2c85a 100644 --- a/Kernel/Arch/x86/Interrupts.h +++ b/Kernel/Arch/x86/Interrupts.h @@ -44,6 +44,7 @@ void register_interrupt_handler(u8 number, void (*handler)()); void register_user_callable_interrupt_handler(u8 number, void (*handler)()); GenericInterruptHandler& get_interrupt_handler(u8 interrupt_number); void register_generic_interrupt_handler(u8 number, GenericInterruptHandler&); +void register_disabled_interrupt_handler(u8 number, GenericInterruptHandler& handler); void unregister_generic_interrupt_handler(u8 number, GenericInterruptHandler&); void idt_init(); diff --git a/Kernel/Arch/x86/common/Interrupts.cpp b/Kernel/Arch/x86/common/Interrupts.cpp index d2af2608f3..7a0cf0e404 100644 --- a/Kernel/Arch/x86/common/Interrupts.cpp +++ b/Kernel/Arch/x86/common/Interrupts.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -42,6 +43,7 @@ READONLY_AFTER_INIT static DescriptorTablePointer s_idtr; READONLY_AFTER_INIT static IDTEntry s_idt[256]; static GenericInterruptHandler* s_interrupt_handler[GENERIC_INTERRUPT_HANDLERS_COUNT]; +static GenericInterruptHandler* s_disabled_interrupt_handler[2]; static EntropySource s_entropy_source_interrupts { EntropySource::Static::Interrupts }; @@ -496,10 +498,24 @@ void handle_interrupt(TrapFrame* trap) { clac(); auto& regs = *trap->regs; - VERIFY(regs.isr_number >= IRQ_VECTOR_BASE && regs.isr_number <= (IRQ_VECTOR_BASE + GENERIC_INTERRUPT_HANDLERS_COUNT)); - u8 irq = (u8)(regs.isr_number - 0x50); - s_entropy_source_interrupts.add_random_event(irq); - auto* handler = s_interrupt_handler[irq]; + + GenericInterruptHandler* handler = nullptr; + // Note: we declare interrupt service routine offset 0x20 to 0x2f as + // reserved for when the PIC is disabled, so we can still route spurious + // IRQs to a different interrupt handlers at different location. + if (regs.isr_number >= pic_disabled_vector_base && regs.isr_number <= pic_disabled_vector_end) { + u8 irq = (u8)(regs.isr_number - pic_disabled_vector_base); + if (irq == 7) { + handler = s_disabled_interrupt_handler[0]; + } else if (irq == 15) { + handler = s_disabled_interrupt_handler[1]; + } + } else { + VERIFY(regs.isr_number >= IRQ_VECTOR_BASE && regs.isr_number <= (IRQ_VECTOR_BASE + GENERIC_INTERRUPT_HANDLERS_COUNT)); + u8 irq = (u8)(regs.isr_number - IRQ_VECTOR_BASE); + s_entropy_source_interrupts.add_random_event(irq); + handler = s_interrupt_handler[irq]; + } VERIFY(handler); handler->increment_invoking_counter(); handler->handle_interrupt(regs); @@ -529,6 +545,18 @@ static void revert_to_unused_handler(u8 interrupt_number) handler->register_interrupt_handler(); } +void register_disabled_interrupt_handler(u8 number, GenericInterruptHandler& handler) +{ + if (number == 15) { + s_disabled_interrupt_handler[0] = &handler; + return; + } else if (number == 7) { + s_disabled_interrupt_handler[1] = &handler; + return; + } + VERIFY_NOT_REACHED(); +} + void register_generic_interrupt_handler(u8 interrupt_number, GenericInterruptHandler& handler) { VERIFY(interrupt_number < GENERIC_INTERRUPT_HANDLERS_COUNT); @@ -637,10 +665,58 @@ UNMAP_AFTER_INIT void idt_init() register_interrupt_handler(0x0f, _exception15); register_interrupt_handler(0x10, _exception16); - for (u8 i = 0x11; i < 0x50; i++) + for (u8 i = 0x11; i < 0x20; i++) register_interrupt_handler(i, unimp_trap); dbgln("Initializing unhandled interrupt handlers"); + register_interrupt_handler(0x20, interrupt_32_asm_entry); + register_interrupt_handler(0x21, interrupt_33_asm_entry); + register_interrupt_handler(0x22, interrupt_34_asm_entry); + register_interrupt_handler(0x23, interrupt_35_asm_entry); + register_interrupt_handler(0x24, interrupt_36_asm_entry); + register_interrupt_handler(0x25, interrupt_37_asm_entry); + register_interrupt_handler(0x26, interrupt_38_asm_entry); + register_interrupt_handler(0x27, interrupt_39_asm_entry); + register_interrupt_handler(0x28, interrupt_40_asm_entry); + register_interrupt_handler(0x29, interrupt_41_asm_entry); + register_interrupt_handler(0x2a, interrupt_42_asm_entry); + register_interrupt_handler(0x2b, interrupt_43_asm_entry); + register_interrupt_handler(0x2c, interrupt_44_asm_entry); + register_interrupt_handler(0x2d, interrupt_45_asm_entry); + register_interrupt_handler(0x2e, interrupt_46_asm_entry); + register_interrupt_handler(0x2f, interrupt_47_asm_entry); + register_interrupt_handler(0x30, interrupt_48_asm_entry); + register_interrupt_handler(0x31, interrupt_49_asm_entry); + register_interrupt_handler(0x32, interrupt_50_asm_entry); + register_interrupt_handler(0x33, interrupt_51_asm_entry); + register_interrupt_handler(0x34, interrupt_52_asm_entry); + register_interrupt_handler(0x35, interrupt_53_asm_entry); + register_interrupt_handler(0x36, interrupt_54_asm_entry); + register_interrupt_handler(0x37, interrupt_55_asm_entry); + register_interrupt_handler(0x38, interrupt_56_asm_entry); + register_interrupt_handler(0x39, interrupt_57_asm_entry); + register_interrupt_handler(0x3a, interrupt_58_asm_entry); + register_interrupt_handler(0x3b, interrupt_59_asm_entry); + register_interrupt_handler(0x3c, interrupt_60_asm_entry); + register_interrupt_handler(0x3d, interrupt_61_asm_entry); + register_interrupt_handler(0x3e, interrupt_62_asm_entry); + register_interrupt_handler(0x3f, interrupt_63_asm_entry); + register_interrupt_handler(0x40, interrupt_64_asm_entry); + register_interrupt_handler(0x41, interrupt_65_asm_entry); + register_interrupt_handler(0x42, interrupt_66_asm_entry); + register_interrupt_handler(0x43, interrupt_67_asm_entry); + register_interrupt_handler(0x44, interrupt_68_asm_entry); + register_interrupt_handler(0x45, interrupt_69_asm_entry); + register_interrupt_handler(0x46, interrupt_70_asm_entry); + register_interrupt_handler(0x47, interrupt_71_asm_entry); + register_interrupt_handler(0x48, interrupt_72_asm_entry); + register_interrupt_handler(0x49, interrupt_73_asm_entry); + register_interrupt_handler(0x4a, interrupt_74_asm_entry); + register_interrupt_handler(0x4b, interrupt_75_asm_entry); + register_interrupt_handler(0x4c, interrupt_76_asm_entry); + register_interrupt_handler(0x4d, interrupt_77_asm_entry); + register_interrupt_handler(0x4e, interrupt_78_asm_entry); + register_interrupt_handler(0x4f, interrupt_79_asm_entry); register_interrupt_handler(0x50, interrupt_80_asm_entry); register_interrupt_handler(0x51, interrupt_81_asm_entry); register_interrupt_handler(0x52, interrupt_82_asm_entry); diff --git a/Kernel/Interrupts/InterruptManagement.cpp b/Kernel/Interrupts/InterruptManagement.cpp index 56cf188706..3d2b3aecee 100644 --- a/Kernel/Interrupts/InterruptManagement.cpp +++ b/Kernel/Interrupts/InterruptManagement.cpp @@ -98,6 +98,15 @@ u8 InterruptManagement::get_irq_vector(u8 mapped_interrupt_vector) return mapped_interrupt_vector; } +RefPtr InterruptManagement::get_responsible_irq_controller(IRQControllerType controller_type, u8 interrupt_vector) +{ + for (auto& irq_controller : m_interrupt_controllers) { + if (irq_controller->gsi_base() <= interrupt_vector && irq_controller->type() == controller_type) + return irq_controller; + } + VERIFY_NOT_REACHED(); +} + RefPtr InterruptManagement::get_responsible_irq_controller(u8 interrupt_vector) { if (m_interrupt_controllers.size() == 1 && m_interrupt_controllers[0]->type() == IRQControllerType::i8259) { @@ -173,6 +182,8 @@ UNMAP_AFTER_INIT void InterruptManagement::switch_to_ioapic_mode() if (irq_controller->type() == IRQControllerType::i8259) { irq_controller->hard_disable(); dbgln("Interrupts: Detected {} - Disabled", irq_controller->model()); + SpuriousInterruptHandler::initialize_for_disabled_master_pic(); + SpuriousInterruptHandler::initialize_for_disabled_slave_pic(); } else { dbgln("Interrupts: Detected {}", irq_controller->model()); } diff --git a/Kernel/Interrupts/InterruptManagement.h b/Kernel/Interrupts/InterruptManagement.h index c567e33bb2..b17bbabd8d 100644 --- a/Kernel/Interrupts/InterruptManagement.h +++ b/Kernel/Interrupts/InterruptManagement.h @@ -54,6 +54,7 @@ public: bool smp_enabled() const { return m_smp_enabled; } RefPtr get_responsible_irq_controller(u8 interrupt_vector); + RefPtr get_responsible_irq_controller(IRQControllerType controller_type, u8 interrupt_vector); const Vector& isa_overrides() const { return m_isa_interrupt_overrides; } diff --git a/Kernel/Interrupts/PIC.h b/Kernel/Interrupts/PIC.h index 03ca59bf21..933d7aa28d 100644 --- a/Kernel/Interrupts/PIC.h +++ b/Kernel/Interrupts/PIC.h @@ -12,6 +12,7 @@ namespace Kernel { static constexpr size_t pic_disabled_vector_base = 0x20; +static constexpr size_t pic_disabled_vector_end = 0x2f; class PIC final : public IRQController { public: diff --git a/Kernel/Interrupts/SpuriousInterruptHandler.cpp b/Kernel/Interrupts/SpuriousInterruptHandler.cpp index be46acda39..b43f9fa574 100644 --- a/Kernel/Interrupts/SpuriousInterruptHandler.cpp +++ b/Kernel/Interrupts/SpuriousInterruptHandler.cpp @@ -4,7 +4,9 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include +#include #include #include @@ -16,6 +18,20 @@ UNMAP_AFTER_INIT void SpuriousInterruptHandler::initialize(u8 interrupt_number) handler->register_interrupt_handler(); } +void SpuriousInterruptHandler::initialize_for_disabled_master_pic() +{ + auto* handler = new SpuriousInterruptHandler(7); + register_disabled_interrupt_handler(7, *handler); + handler->enable_interrupt_vector_for_disabled_pic(); +} + +void SpuriousInterruptHandler::initialize_for_disabled_slave_pic() +{ + auto* handler = new SpuriousInterruptHandler(15); + register_disabled_interrupt_handler(15, *handler); + handler->enable_interrupt_vector_for_disabled_pic(); +} + void SpuriousInterruptHandler::register_handler(GenericInterruptHandler& handler) { VERIFY(!m_real_handler); @@ -70,6 +86,12 @@ bool SpuriousInterruptHandler::handle_interrupt(const RegisterState& state) return true; } +void SpuriousInterruptHandler::enable_interrupt_vector_for_disabled_pic() +{ + m_enabled = true; + m_responsible_irq_controller = InterruptManagement::the().get_responsible_irq_controller(IRQControllerType::i8259, interrupt_number()); +} + void SpuriousInterruptHandler::enable_interrupt_vector() { if (m_enabled) diff --git a/Kernel/Interrupts/SpuriousInterruptHandler.h b/Kernel/Interrupts/SpuriousInterruptHandler.h index e215228714..9a7aafa55e 100644 --- a/Kernel/Interrupts/SpuriousInterruptHandler.h +++ b/Kernel/Interrupts/SpuriousInterruptHandler.h @@ -16,6 +16,8 @@ namespace Kernel { class SpuriousInterruptHandler final : public GenericInterruptHandler { public: static void initialize(u8 interrupt_number); + static void initialize_for_disabled_master_pic(); + static void initialize_for_disabled_slave_pic(); virtual ~SpuriousInterruptHandler(); virtual bool handle_interrupt(const RegisterState& regs) override; @@ -32,6 +34,8 @@ public: virtual StringView purpose() const override; virtual StringView controller() const override; + void enable_interrupt_vector_for_disabled_pic(); + private: void enable_interrupt_vector(); void disable_interrupt_vector();