From 30fc78bfaf084835530241e0b1c8e3cc2a45ab23 Mon Sep 17 00:00:00 2001 From: Liav A Date: Fri, 6 Mar 2020 03:19:40 +0200 Subject: [PATCH] Kernel: Acquire ISA interrupt overrides from Interrupt Management Also, InterruptDisabler were added to prevent critical function from being interrupted. In addition, the interrupt numbers are abstracted from IDT offsets, thus, allowing to create a better routing scheme when using IOAPICs for interrupt redirection. --- Kernel/Interrupts/GenericInterruptHandler.cpp | 8 ++--- Kernel/Interrupts/IOAPIC.cpp | 25 +++++++-------- Kernel/Interrupts/IOAPIC.h | 4 +-- Kernel/Interrupts/InterruptManagement.cpp | 32 ++++++++++++++++++- Kernel/Interrupts/InterruptManagement.h | 6 ++++ 5 files changed, 54 insertions(+), 21 deletions(-) diff --git a/Kernel/Interrupts/GenericInterruptHandler.cpp b/Kernel/Interrupts/GenericInterruptHandler.cpp index 00074b36193..12f078d8114 100644 --- a/Kernel/Interrupts/GenericInterruptHandler.cpp +++ b/Kernel/Interrupts/GenericInterruptHandler.cpp @@ -39,20 +39,20 @@ GenericInterruptHandler& GenericInterruptHandler::from(u8 interrupt_number) GenericInterruptHandler::GenericInterruptHandler(u8 interrupt_number) : m_interrupt_number(interrupt_number) { - register_generic_interrupt_handler(interrupt_number, *this); + register_generic_interrupt_handler(InterruptManagement::acquire_mapped_interrupt_number(m_interrupt_number), *this); } GenericInterruptHandler::~GenericInterruptHandler() { - unregister_generic_interrupt_handler(m_interrupt_number, *this); + unregister_generic_interrupt_handler(InterruptManagement::acquire_mapped_interrupt_number(m_interrupt_number), *this); } void GenericInterruptHandler::change_interrupt_number(u8 number) { ASSERT_INTERRUPTS_ENABLED(); - unregister_generic_interrupt_handler(interrupt_number(), *this); + unregister_generic_interrupt_handler(InterruptManagement::acquire_mapped_interrupt_number(interrupt_number()), *this); m_interrupt_number = number; - register_generic_interrupt_handler(interrupt_number(), *this); + register_generic_interrupt_handler(InterruptManagement::acquire_mapped_interrupt_number(interrupt_number()), *this); } void GenericInterruptHandler::increment_invoking_counter() { diff --git a/Kernel/Interrupts/IOAPIC.cpp b/Kernel/Interrupts/IOAPIC.cpp index dca67b6ead5..c1cb1d495bc 100644 --- a/Kernel/Interrupts/IOAPIC.cpp +++ b/Kernel/Interrupts/IOAPIC.cpp @@ -42,15 +42,14 @@ enum DeliveryMode { External = 7 }; -IOAPIC::IOAPIC(ioapic_mmio_regs& regs, u32 gsi_base, Vector>& isa_overrides, Vector>& pci_overrides) +IOAPIC::IOAPIC(ioapic_mmio_regs& regs, u32 gsi_base) : m_physical_access_registers(regs) , 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_isa_interrupt_overrides(isa_overrides) - , m_pci_interrupt_overrides(pci_overrides) { + 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 Arbitration ID 0x" << String::format("%x", read_register(0x2)); @@ -63,11 +62,8 @@ void IOAPIC::initialize() void IOAPIC::map_interrupt_redirection(u8 interrupt_vector) { - if (interrupt_vector == 11) { - configure_redirection_entry(11, 11 + IRQ_VECTOR_BASE, DeliveryMode::LowPriority, false, true, true, true, 0); - return; - } - for (auto redirection_override : m_isa_interrupt_overrides) { + InterruptDisabler disabler; + for (auto redirection_override : InterruptManagement::the().isa_overrides()) { ASSERT(!redirection_override.is_null()); if (redirection_override->source() != interrupt_vector) continue; @@ -102,7 +98,7 @@ void IOAPIC::map_interrupt_redirection(u8 interrupt_vector) trigger_level_mode = true; break; } - configure_redirection_entry(redirection_override->gsi(), redirection_override->source() + IRQ_VECTOR_BASE, DeliveryMode::LowPriority, false, active_low, trigger_level_mode, true, 0); + 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); return; } isa_identity_map(interrupt_vector); @@ -110,18 +106,20 @@ void IOAPIC::map_interrupt_redirection(u8 interrupt_vector) void IOAPIC::isa_identity_map(int index) { - configure_redirection_entry(index, index + IRQ_VECTOR_BASE, DeliveryMode::Normal, true, false, false, true, 1); + InterruptDisabler disabler; + configure_redirection_entry(index, InterruptManagement::acquire_mapped_interrupt_number(index) + IRQ_VECTOR_BASE, DeliveryMode::Normal, false, false, false, true, 0); } void IOAPIC::map_pci_interrupts() { + InterruptDisabler disabler; configure_redirection_entry(11, 11 + IRQ_VECTOR_BASE, DeliveryMode::Normal, false, false, true, true, 0); } void IOAPIC::map_isa_interrupts() { InterruptDisabler disabler; - for (auto redirection_override : m_isa_interrupt_overrides) { + for (auto redirection_override : InterruptManagement::the().isa_overrides()) { ASSERT(!redirection_override.is_null()); bool active_low; // See ACPI spec Version 6.2, page 205 to learn more about Interrupt Overriding Flags. @@ -154,7 +152,7 @@ void IOAPIC::map_isa_interrupts() trigger_level_mode = true; break; } - configure_redirection_entry(redirection_override->gsi(), redirection_override->source() + IRQ_VECTOR_BASE, 0, false, active_low, trigger_level_mode, true, 0); + 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); } } @@ -180,6 +178,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); 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; @@ -236,7 +235,7 @@ int IOAPIC::find_redirection_entry_by_vector(u8 vector) const { InterruptDisabler disabler; for (size_t index = 0; index < m_redirection_entries; index++) { - if (read_redirection_entry_vector(index) == (vector + IRQ_VECTOR_BASE)) + if (read_redirection_entry_vector(index) == (InterruptManagement::acquire_mapped_interrupt_number(vector) + IRQ_VECTOR_BASE)) return index; } return -1; diff --git a/Kernel/Interrupts/IOAPIC.h b/Kernel/Interrupts/IOAPIC.h index 4192421dfa5..d7d629ecce4 100644 --- a/Kernel/Interrupts/IOAPIC.h +++ b/Kernel/Interrupts/IOAPIC.h @@ -41,7 +41,7 @@ class PCIInterruptOverrideMetadata; class IOAPIC final : public IRQController { public: - IOAPIC(ioapic_mmio_regs& regs, u32 gsi_base, Vector>& overrides, Vector>& pci_overrides); + IOAPIC(ioapic_mmio_regs& regs, u32 gsi_base); virtual void enable(u8 number) override; virtual void disable(u8 number) override; virtual void hard_disable() override; @@ -81,7 +81,5 @@ private: u8 m_id; u8 m_version; u32 m_redirection_entries; - Vector> m_isa_interrupt_overrides; - Vector> m_pci_interrupt_overrides; }; } diff --git a/Kernel/Interrupts/InterruptManagement.cpp b/Kernel/Interrupts/InterruptManagement.cpp index b6217e5638d..adf9b0400b8 100644 --- a/Kernel/Interrupts/InterruptManagement.cpp +++ b/Kernel/Interrupts/InterruptManagement.cpp @@ -27,11 +27,14 @@ #include #include #include +#include #include #include #include #include +#include #include +#include #define PCAT_COMPAT_FLAG 0x1 @@ -72,6 +75,26 @@ IRQController& InterruptManagement::get_interrupt_controller(int index) return *m_interrupt_controllers[index]; } +Vector> InterruptManagement::isa_overrides() +{ + return m_isa_interrupt_overrides; +} + +u8 InterruptManagement::acquire_mapped_interrupt_number(u8 number) +{ + if (!InterruptManagement::initialized()) { + // This is necessary, because we install UnhandledInterruptHandlers before we actually initialize the Interrupt Management object... + return number; + } + return InterruptManagement::the().get_mapped_vector_number(number); +} + +u8 InterruptManagement::get_mapped_vector_number(u8 original_vector) +{ + // FIXME: For SMP configuration (with IOAPICs) use a better routing scheme to make redirections more efficient. + return original_vector; +} + RefPtr InterruptManagement::get_responsible_irq_controller(u8 interrupt_vector) { if (m_interrupt_controllers.size() == 1 && m_interrupt_controllers[0]->type() == IRQControllerType::i8259) { @@ -110,6 +133,8 @@ InterruptManagement::InterruptManagement() void InterruptManagement::switch_to_pic_mode() { klog() << "Interrupts: Switch to Legacy PIC mode"; + InterruptDisabler disabler; + m_smp_enabled = false; SpuriousInterruptHandler::initialize(7); SpuriousInterruptHandler::initialize(15); for (auto& irq_controller : m_interrupt_controllers) { @@ -126,6 +151,8 @@ void InterruptManagement::switch_to_pic_mode() void InterruptManagement::switch_to_ioapic_mode() { klog() << "Interrupts: Switch to IOAPIC mode"; + InterruptDisabler disabler; + m_smp_enabled = true; if (m_interrupt_controllers.size() == 1) { if (get_interrupt_controller(0).type() == IRQControllerType::i8259) { klog() << "Interrupts: NO IOAPIC detected, Reverting to PIC mode."; @@ -141,6 +168,9 @@ void InterruptManagement::switch_to_ioapic_mode() dbg() << "Interrupts: Detected " << irq_controller->model(); } } + APIC::init(); + APIC::enable_bsp(); + MultiProcessorParser::initialize(); } void InterruptManagement::locate_apic_data() @@ -163,7 +193,7 @@ void InterruptManagement::locate_apic_data() auto* ioapic_entry = (const ACPI::Structures::MADTEntries::IOAPIC*)madt_entry; dbg() << "IOAPIC found @ MADT entry " << entry_index << ", MMIO Registers @ Px" << String::format("%x", ioapic_entry->ioapic_address); m_interrupt_controllers.resize(1 + irq_controller_count); - m_interrupt_controllers[irq_controller_count] = adopt(*new IOAPIC(*(ioapic_mmio_regs*)ioapic_entry->ioapic_address, ioapic_entry->gsi_base, m_isa_interrupt_overrides, m_pci_interrupt_overrides)); + m_interrupt_controllers[irq_controller_count] = adopt(*new IOAPIC(*(ioapic_mmio_regs*)ioapic_entry->ioapic_address, ioapic_entry->gsi_base)); irq_controller_count++; } if (madt_entry->type == (u8)ACPI::Structures::MADTEntryType::InterruptSourceOverride) { diff --git a/Kernel/Interrupts/InterruptManagement.h b/Kernel/Interrupts/InterruptManagement.h index 50c695a18de..9c448c45beb 100644 --- a/Kernel/Interrupts/InterruptManagement.h +++ b/Kernel/Interrupts/InterruptManagement.h @@ -47,11 +47,16 @@ public: static InterruptManagement& the(); static void initialize(); static bool initialized(); + static u8 acquire_mapped_interrupt_number(u8); virtual void switch_to_pic_mode(); virtual void switch_to_ioapic_mode(); RefPtr get_responsible_irq_controller(u8 interrupt_vector); + Vector> isa_overrides(); + + u8 get_mapped_vector_number(u8 original_vector); + void enumerate_interrupt_handlers(Function); IRQController& get_interrupt_controller(int index); @@ -60,6 +65,7 @@ private: PhysicalAddress search_for_madt(); void locate_apic_data(); void locate_pci_interrupt_overrides(); + bool m_smp_enabled { false }; FixedArray> m_interrupt_controllers { 1 }; Vector> m_isa_interrupt_overrides; Vector> m_pci_interrupt_overrides;