diff options
author | Liav A <liavalb@gmail.com> | 2020-03-08 12:47:33 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-03-24 16:15:33 +0100 |
commit | f86be46c989499562b0b9ab9cd194e16dbc5bb36 (patch) | |
tree | a96a8328a29fa3e10e068b73d91176706fcaafee | |
parent | 666990fbcb5fe3611577e23fd181e1e9b9e1219c (diff) | |
download | serenity-f86be46c989499562b0b9ab9cd194e16dbc5bb36.zip |
Kernel: Abstract IRQ controller handling from Interrupt handlers
Now we don't send raw numbers, but we let the IRQController object to
figure out the correct IRQ number.
This helps in a situation when we have 2 or more IOAPICs, so if IOAPIC
1 is assigned for IRQs 0-23 and IOAPIC 2 is assigned for IRQs 24-47,
if an IRQHandler of IRQ 25 invokes disable() for example, it will call
his responsible IRQController (IOAPIC 2), and the IRQController will
subtract the IRQ number with his assigned offset, and the result is that
the second redirection entry in IOAPIC 2 will be masked.
-rw-r--r-- | Kernel/Interrupts/APIC.cpp | 5 | ||||
-rw-r--r-- | Kernel/Interrupts/APIC.h | 2 | ||||
-rw-r--r-- | Kernel/Interrupts/IOAPIC.cpp | 46 | ||||
-rw-r--r-- | Kernel/Interrupts/IOAPIC.h | 12 | ||||
-rw-r--r-- | Kernel/Interrupts/IRQController.h | 10 | ||||
-rw-r--r-- | Kernel/Interrupts/IRQHandler.cpp | 6 | ||||
-rw-r--r-- | Kernel/Interrupts/InterruptManagement.cpp | 2 | ||||
-rw-r--r-- | Kernel/Interrupts/PIC.cpp | 34 | ||||
-rw-r--r-- | Kernel/Interrupts/PIC.h | 12 | ||||
-rw-r--r-- | Kernel/Interrupts/SharedIRQHandler.cpp | 6 | ||||
-rw-r--r-- | Kernel/Interrupts/SpuriousInterruptHandler.cpp | 7 |
11 files changed, 97 insertions, 45 deletions
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<IRQController> { 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<IRQController> 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 <AK/Assertions.h> #include <AK/Types.h> #include <Kernel/Arch/i386/CPU.h> +#include <Kernel/Interrupts/GenericInterruptHandler.h> #include <Kernel/Interrupts/PIC.h> #include <LibBareMetal/IO.h> @@ -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 |