diff --git a/Kernel/Interrupts/APIC.cpp b/Kernel/Interrupts/APIC.cpp index 0bc34d3507..6eaac95583 100644 --- a/Kernel/Interrupts/APIC.cpp +++ b/Kernel/Interrupts/APIC.cpp @@ -157,6 +157,11 @@ void eoi() write_register(APIC_REG_EOI, 0x0); } +u8 spurious_interrupt_vector() +{ + return IRQ_APIC_SPURIOUS; +} + bool init() { // FIXME: Use the ACPI MADT table diff --git a/Kernel/Interrupts/APIC.h b/Kernel/Interrupts/APIC.h index 42fddb55be..4db0bf57d8 100644 --- a/Kernel/Interrupts/APIC.h +++ b/Kernel/Interrupts/APIC.h @@ -36,7 +36,7 @@ void enable_bsp(); void eoi(); bool init(); void enable(u32 cpu); - +u8 spurious_interrupt_vector(); } } diff --git a/Kernel/Interrupts/IOAPIC.cpp b/Kernel/Interrupts/IOAPIC.cpp index 3d26f42a21..b6f4e3513b 100644 --- a/Kernel/Interrupts/IOAPIC.cpp +++ b/Kernel/Interrupts/IOAPIC.cpp @@ -48,11 +48,11 @@ IOAPIC::IOAPIC(ioapic_mmio_regs& regs, u32 gsi_base) , m_gsi_base(gsi_base) , m_id((read_register(0x0) >> 24) & 0xFF) , m_version(read_register(0x1) & 0xFF) - , m_redirection_entries((read_register(0x1) >> 16) + 1) + , m_redirection_entries_count((read_register(0x1) >> 16) + 1) { InterruptDisabler disabler; klog() << "IOAPIC ID: 0x" << String::format("%x", m_id); - klog() << "IOAPIC Version: 0x" << String::format("%x", m_version) << ", Redirection Entries count - " << m_redirection_entries; + klog() << "IOAPIC Version: 0x" << String::format("%x", m_version) << ", Redirection Entries count - " << m_redirection_entries_count; klog() << "IOAPIC Arbitration ID 0x" << String::format("%x", read_register(0x2)); mask_all_redirection_entries(); } @@ -99,7 +99,7 @@ void IOAPIC::map_interrupt_redirection(u8 interrupt_vector) trigger_level_mode = true; break; } - configure_redirection_entry(redirection_override->gsi(), InterruptManagement::acquire_mapped_interrupt_number(redirection_override->source()) + IRQ_VECTOR_BASE, DeliveryMode::Normal, false, active_low, trigger_level_mode, true, 0); + configure_redirection_entry(redirection_override->gsi() - gsi_base(), InterruptManagement::acquire_mapped_interrupt_number(redirection_override->source()) + IRQ_VECTOR_BASE, DeliveryMode::Normal, false, active_low, trigger_level_mode, true, 0); return; } isa_identity_map(interrupt_vector); @@ -117,11 +117,21 @@ void IOAPIC::map_pci_interrupts() configure_redirection_entry(11, 11 + IRQ_VECTOR_BASE, DeliveryMode::Normal, false, false, true, true, 0); } +void IOAPIC::spurious_eoi(const GenericInterruptHandler& handler) const +{ + InterruptDisabler disabler; + ASSERT(handler.type() == HandlerType::SpuriousInterruptHandler); + ASSERT(handler.interrupt_number() == APIC::spurious_interrupt_vector()); + klog() << "IOAPIC::spurious_eoi - Spurious Interrupt occurred"; +} + void IOAPIC::map_isa_interrupts() { InterruptDisabler disabler; for (auto redirection_override : InterruptManagement::the().isa_overrides()) { ASSERT(!redirection_override.is_null()); + if ((redirection_override->gsi() < gsi_base()) || (redirection_override->gsi() >= (gsi_base() + m_redirection_entries_count))) + continue; bool active_low; // See ACPI spec Version 6.2, page 205 to learn more about Interrupt Overriding Flags. switch ((redirection_override->flags() & 0b11)) { @@ -153,14 +163,14 @@ void IOAPIC::map_isa_interrupts() trigger_level_mode = true; break; } - configure_redirection_entry(redirection_override->gsi(), InterruptManagement::acquire_mapped_interrupt_number(redirection_override->source()) + IRQ_VECTOR_BASE, 0, false, active_low, trigger_level_mode, true, 0); + configure_redirection_entry(redirection_override->gsi() - gsi_base(), InterruptManagement::acquire_mapped_interrupt_number(redirection_override->source()) + IRQ_VECTOR_BASE, 0, false, active_low, trigger_level_mode, true, 0); } } void IOAPIC::reset_all_redirection_entries() const { InterruptDisabler disabler; - for (size_t index = 0; index < m_redirection_entries; index++) + for (size_t index = 0; index < m_redirection_entries_count; index++) reset_redirection_entry(index); } @@ -180,7 +190,7 @@ void IOAPIC::reset_redirection_entry(int index) const void IOAPIC::configure_redirection_entry(int index, u8 interrupt_vector, u8 delivery_mode, bool logical_destination, bool active_low, bool trigger_level_mode, bool masked, u8 destination) const { InterruptDisabler disabler; - ASSERT((u32)index < m_redirection_entries); + ASSERT((u32)index < m_redirection_entries_count); u32 redirection_entry1 = interrupt_vector | (delivery_mode & 0b111) << 8 | logical_destination << 11 | active_low << 13 | trigger_level_mode << 15 | masked << 16; u32 redirection_entry2 = destination << 24; write_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET, redirection_entry1); @@ -196,26 +206,26 @@ void IOAPIC::configure_redirection_entry(int index, u8 interrupt_vector, u8 deli void IOAPIC::mask_all_redirection_entries() const { InterruptDisabler disabler; - for (size_t index = 0; index < m_redirection_entries; index++) + for (size_t index = 0; index < m_redirection_entries_count; index++) mask_redirection_entry(index); } void IOAPIC::mask_redirection_entry(u8 index) const { - ASSERT((u32)index < m_redirection_entries); + ASSERT((u32)index < m_redirection_entries_count); u32 redirection_entry = read_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET) | (1 << 16); write_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET, redirection_entry); } bool IOAPIC::is_redirection_entry_masked(u8 index) const { - ASSERT((u32)index < m_redirection_entries); + ASSERT((u32)index < m_redirection_entries_count); return (read_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET) & (1 << 16)) != 0; } void IOAPIC::unmask_redirection_entry(u8 index) const { - ASSERT((u32)index < m_redirection_entries); + ASSERT((u32)index < m_redirection_entries_count); u32 redirection_entry = read_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET); write_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET, redirection_entry & ~(1 << 16)); } @@ -228,24 +238,26 @@ bool IOAPIC::is_vector_enabled(u8 interrupt_vector) const u8 IOAPIC::read_redirection_entry_vector(u8 index) const { - ASSERT((u32)index < m_redirection_entries); + ASSERT((u32)index < m_redirection_entries_count); return (read_register((index << 1) + IOAPIC_REDIRECTION_ENTRY_OFFSET) & 0xFF); } int IOAPIC::find_redirection_entry_by_vector(u8 vector) const { InterruptDisabler disabler; - for (size_t index = 0; index < m_redirection_entries; index++) { + for (size_t index = 0; index < m_redirection_entries_count; index++) { if (read_redirection_entry_vector(index) == (InterruptManagement::acquire_mapped_interrupt_number(vector) + IRQ_VECTOR_BASE)) return index; } return -1; } -void IOAPIC::disable(u8 interrupt_vector) +void IOAPIC::disable(const GenericInterruptHandler& handler) { InterruptDisabler disabler; ASSERT(!is_hard_disabled()); + u8 interrupt_vector = handler.interrupt_number(); + ASSERT(interrupt_vector >= gsi_base() && interrupt_vector < interrupt_vectors_count()); int index = find_redirection_entry_by_vector(interrupt_vector); if (index == (-1)) { map_interrupt_redirection(interrupt_vector); @@ -255,10 +267,12 @@ void IOAPIC::disable(u8 interrupt_vector) mask_redirection_entry(index); } -void IOAPIC::enable(u8 interrupt_vector) +void IOAPIC::enable(const GenericInterruptHandler& handler) { InterruptDisabler disabler; ASSERT(!is_hard_disabled()); + u8 interrupt_vector = handler.interrupt_number(); + ASSERT(interrupt_vector >= gsi_base() && interrupt_vector < interrupt_vectors_count()); int index = find_redirection_entry_by_vector(interrupt_vector); if (index == (-1)) { map_interrupt_redirection(interrupt_vector); @@ -268,10 +282,12 @@ void IOAPIC::enable(u8 interrupt_vector) unmask_redirection_entry(index); } -void IOAPIC::eoi(u8) const +void IOAPIC::eoi(const GenericInterruptHandler& handler) const { InterruptDisabler disabler; ASSERT(!is_hard_disabled()); + ASSERT(handler.interrupt_number() >= gsi_base() && handler.interrupt_number() < interrupt_vectors_count()); + ASSERT(handler.type() != HandlerType::SpuriousInterruptHandler); APIC::eoi(); } diff --git a/Kernel/Interrupts/IOAPIC.h b/Kernel/Interrupts/IOAPIC.h index d7d629ecce..36acf4e25e 100644 --- a/Kernel/Interrupts/IOAPIC.h +++ b/Kernel/Interrupts/IOAPIC.h @@ -42,14 +42,16 @@ class PCIInterruptOverrideMetadata; class IOAPIC final : public IRQController { public: IOAPIC(ioapic_mmio_regs& regs, u32 gsi_base); - virtual void enable(u8 number) override; - virtual void disable(u8 number) override; + virtual void enable(const GenericInterruptHandler&) override; + virtual void disable(const GenericInterruptHandler&) override; virtual void hard_disable() override; - virtual void eoi(u8 number) const override; + virtual void eoi(const GenericInterruptHandler&) const override; + virtual void spurious_eoi(const GenericInterruptHandler&) const override; virtual bool is_vector_enabled(u8 number) const override; virtual u16 get_isr() const override; virtual u16 get_irr() const override; - virtual u32 get_gsi_base() const override { return m_gsi_base; } + virtual u32 gsi_base() const override { return m_gsi_base; } + virtual size_t interrupt_vectors_count() const { return m_redirection_entries_count; } virtual const char* model() const override { return "IOAPIC"; }; virtual IRQControllerType type() const override { return IRQControllerType::i82093AA; } @@ -80,6 +82,6 @@ private: u32 m_gsi_base; u8 m_id; u8 m_version; - u32 m_redirection_entries; + size_t m_redirection_entries_count; }; } diff --git a/Kernel/Interrupts/IRQController.h b/Kernel/Interrupts/IRQController.h index f27c5bd0f9..2a99df4ab4 100644 --- a/Kernel/Interrupts/IRQController.h +++ b/Kernel/Interrupts/IRQController.h @@ -41,14 +41,16 @@ class IRQController : public RefCounted { public: virtual ~IRQController() {} - virtual void enable(u8 number) = 0; - virtual void disable(u8 number) = 0; + virtual void enable(const GenericInterruptHandler&) = 0; + virtual void disable(const GenericInterruptHandler&) = 0; virtual void hard_disable() { m_hard_disabled = true; } virtual bool is_vector_enabled(u8 number) const = 0; bool is_enabled() const { return m_enabled && !m_hard_disabled; } bool is_hard_disabled() const { return m_hard_disabled; } - virtual void eoi(u8 number) const = 0; - virtual u32 get_gsi_base() const = 0; + virtual void eoi(const GenericInterruptHandler&) const = 0; + virtual void spurious_eoi(const GenericInterruptHandler&) const = 0; + virtual size_t interrupt_vectors_count() const = 0; + virtual u32 gsi_base() const = 0; virtual u16 get_isr() const = 0; virtual u16 get_irr() const = 0; virtual const char* model() const = 0; diff --git a/Kernel/Interrupts/IRQHandler.cpp b/Kernel/Interrupts/IRQHandler.cpp index 05439b1ff5..4201f65340 100644 --- a/Kernel/Interrupts/IRQHandler.cpp +++ b/Kernel/Interrupts/IRQHandler.cpp @@ -49,7 +49,7 @@ bool IRQHandler::eoi() #endif if (!m_shared_with_others) { ASSERT(!m_responsible_irq_controller.is_null()); - m_responsible_irq_controller->eoi(interrupt_number()); + m_responsible_irq_controller->eoi(*this); return true; } return false; @@ -61,7 +61,7 @@ void IRQHandler::enable_irq() dbg() << "Enable IRQ " << interrupt_number(); #endif if (!m_shared_with_others) - m_responsible_irq_controller->enable(interrupt_number()); + m_responsible_irq_controller->enable(*this); else m_enabled = true; } @@ -72,7 +72,7 @@ void IRQHandler::disable_irq() dbg() << "Disable IRQ " << interrupt_number(); #endif if (!m_shared_with_others) - m_responsible_irq_controller->disable(interrupt_number()); + m_responsible_irq_controller->disable(*this); else m_enabled = false; } diff --git a/Kernel/Interrupts/InterruptManagement.cpp b/Kernel/Interrupts/InterruptManagement.cpp index eb539b3de0..905551457a 100644 --- a/Kernel/Interrupts/InterruptManagement.cpp +++ b/Kernel/Interrupts/InterruptManagement.cpp @@ -114,7 +114,7 @@ RefPtr InterruptManagement::get_responsible_irq_controller(u8 int return m_interrupt_controllers[0]; } for (auto irq_controller : m_interrupt_controllers) { - if (irq_controller->get_gsi_base() <= interrupt_vector) + if (irq_controller->gsi_base() <= interrupt_vector) if (!irq_controller->is_hard_disabled()) return irq_controller; } diff --git a/Kernel/Interrupts/PIC.cpp b/Kernel/Interrupts/PIC.cpp index 5c92a64b94..e5f1ca20fe 100644 --- a/Kernel/Interrupts/PIC.cpp +++ b/Kernel/Interrupts/PIC.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -58,10 +59,12 @@ bool inline static is_all_masked(u8 reg) return reg == 0xFF; } -void PIC::disable(u8 irq) +void PIC::disable(const GenericInterruptHandler& handler) { InterruptDisabler disabler; ASSERT(!is_hard_disabled()); + ASSERT(handler.interrupt_number() >= gsi_base() && handler.interrupt_number() < interrupt_vectors_count()); + u8 irq = handler.interrupt_number(); u8 imr; if (irq >= 8) { imr = IO::in8(PIC1_CMD); @@ -82,6 +85,13 @@ PIC::PIC() initialize(); } +void PIC::spurious_eoi(const GenericInterruptHandler& handler) const +{ + ASSERT(handler.type() == HandlerType::SpuriousInterruptHandler); + if (handler.interrupt_number() == 15) + eoi_interrupt(7); +} + bool PIC::is_vector_enabled(u8 irq) const { u8 imr; @@ -95,7 +105,15 @@ bool PIC::is_vector_enabled(u8 irq) const return imr != 0; } -void PIC::enable(u8 irq) +void PIC::enable(const GenericInterruptHandler& handler) +{ + InterruptDisabler disabler; + ASSERT(!is_hard_disabled()); + ASSERT(handler.interrupt_number() >= gsi_base() && handler.interrupt_number() < interrupt_vectors_count()); + enable_vector(handler.interrupt_number()); +} + +void PIC::enable_vector(u8 irq) { InterruptDisabler disabler; ASSERT(!is_hard_disabled()); @@ -112,10 +130,16 @@ void PIC::enable(u8 irq) m_enabled = true; } -void PIC::eoi(u8 irq) const +void PIC::eoi(const GenericInterruptHandler& handler) const { InterruptDisabler disabler; ASSERT(!is_hard_disabled()); + ASSERT(handler.interrupt_number() >= gsi_base() && handler.interrupt_number() < interrupt_vectors_count()); + eoi_interrupt(handler.interrupt_number()); +} + +void PIC::eoi_interrupt(u8 irq) const +{ if (irq >= 8) IO::out8(PIC1_CTL, 0x20); IO::out8(PIC0_CTL, 0x20); @@ -159,7 +183,7 @@ void PIC::remap(u8 offset) IO::out8(PIC1_CMD, 0xff); // ...except IRQ2, since that's needed for the master to let through slave interrupts. - enable(2); + enable_vector(2); } void PIC::initialize() @@ -185,7 +209,7 @@ void PIC::initialize() IO::out8(PIC1_CMD, 0xff); // ...except IRQ2, since that's needed for the master to let through slave interrupts. - enable(2); + enable_vector(2); klog() << "PIC(i8259): cascading mode, vectors 0x" << String::format("%x", IRQ_VECTOR_BASE) << "-0x" << String::format("%x", IRQ_VECTOR_BASE + 0xf); } diff --git a/Kernel/Interrupts/PIC.h b/Kernel/Interrupts/PIC.h index b2f7314ce4..95b3cc7286 100644 --- a/Kernel/Interrupts/PIC.h +++ b/Kernel/Interrupts/PIC.h @@ -33,18 +33,22 @@ namespace Kernel { class PIC final : public IRQController { public: PIC(); - virtual void enable(u8 number) override; - virtual void disable(u8 number) override; + virtual void enable(const GenericInterruptHandler&) override; + virtual void disable(const GenericInterruptHandler&) override; virtual void hard_disable() override; - virtual void eoi(u8 number) const override; + virtual void eoi(const GenericInterruptHandler&) const override; virtual bool is_vector_enabled(u8 number) const override; + virtual void spurious_eoi(const GenericInterruptHandler&) const override; virtual u16 get_isr() const override; virtual u16 get_irr() const override; - virtual u32 get_gsi_base() const override { return 0; } + virtual u32 gsi_base() const override { return 0; } + virtual size_t interrupt_vectors_count() const { return 16; } virtual const char* model() const override { return "Dual i8259"; } virtual IRQControllerType type() const override { return IRQControllerType::i8259; } private: + void eoi_interrupt(u8 irq) const; + void enable_vector(u8 number); void remap(u8 offset); void complete_eoi() const; virtual void initialize() override; diff --git a/Kernel/Interrupts/SharedIRQHandler.cpp b/Kernel/Interrupts/SharedIRQHandler.cpp index 3d581f914f..0342de60f2 100644 --- a/Kernel/Interrupts/SharedIRQHandler.cpp +++ b/Kernel/Interrupts/SharedIRQHandler.cpp @@ -62,7 +62,7 @@ bool SharedIRQHandler::eoi() #ifdef INTERRUPT_DEBUG dbg() << "EOI IRQ " << interrupt_number(); #endif - m_responsible_irq_controller->eoi(interrupt_number()); + m_responsible_irq_controller->eoi(*this); return true; } @@ -115,7 +115,7 @@ void SharedIRQHandler::enable_interrupt_vector() if (m_enabled) return; m_enabled = true; - m_responsible_irq_controller->enable(interrupt_number()); + m_responsible_irq_controller->enable(*this); } void SharedIRQHandler::disable_interrupt_vector() @@ -123,7 +123,7 @@ void SharedIRQHandler::disable_interrupt_vector() if (!m_enabled) return; m_enabled = false; - m_responsible_irq_controller->disable(interrupt_number()); + m_responsible_irq_controller->disable(*this); } } diff --git a/Kernel/Interrupts/SpuriousInterruptHandler.cpp b/Kernel/Interrupts/SpuriousInterruptHandler.cpp index 885481f5c3..186b570b2a 100644 --- a/Kernel/Interrupts/SpuriousInterruptHandler.cpp +++ b/Kernel/Interrupts/SpuriousInterruptHandler.cpp @@ -44,8 +44,7 @@ void SpuriousInterruptHandler::unregister_handler(GenericInterruptHandler&) bool SpuriousInterruptHandler::eoi() { // FIXME: Actually check if IRQ7 or IRQ15 are spurious, and if not, call EOI with the correct interrupt number. - if (interrupt_number() == 15) - m_responsible_irq_controller->eoi(7); + m_responsible_irq_controller->spurious_eoi(*this); return false; } @@ -70,7 +69,7 @@ void SpuriousInterruptHandler::enable_interrupt_vector() if (m_enabled) return; m_enabled = true; - m_responsible_irq_controller->enable(interrupt_number()); + m_responsible_irq_controller->enable(*this); } void SpuriousInterruptHandler::disable_interrupt_vector() @@ -78,7 +77,7 @@ void SpuriousInterruptHandler::disable_interrupt_vector() if (!m_enabled) return; m_enabled = false; - m_responsible_irq_controller->disable(interrupt_number()); + m_responsible_irq_controller->disable(*this); } const char* SpuriousInterruptHandler::controller() const