浏览代码

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.
Liav A 5 年之前
父节点
当前提交
30fc78bfaf

+ 4 - 4
Kernel/Interrupts/GenericInterruptHandler.cpp

@@ -39,20 +39,20 @@ GenericInterruptHandler& GenericInterruptHandler::from(u8 interrupt_number)
 GenericInterruptHandler::GenericInterruptHandler(u8 interrupt_number)
 GenericInterruptHandler::GenericInterruptHandler(u8 interrupt_number)
     : m_interrupt_number(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()
 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)
 void GenericInterruptHandler::change_interrupt_number(u8 number)
 {
 {
     ASSERT_INTERRUPTS_ENABLED();
     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;
     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()
 void GenericInterruptHandler::increment_invoking_counter()
 {
 {

+ 12 - 13
Kernel/Interrupts/IOAPIC.cpp

@@ -42,15 +42,14 @@ enum DeliveryMode {
     External = 7
     External = 7
 };
 };
 
 
-IOAPIC::IOAPIC(ioapic_mmio_regs& regs, u32 gsi_base, Vector<RefPtr<ISAInterruptOverrideMetadata>>& isa_overrides, Vector<RefPtr<PCIInterruptOverrideMetadata>>& pci_overrides)
+IOAPIC::IOAPIC(ioapic_mmio_regs& regs, u32 gsi_base)
     : m_physical_access_registers(regs)
     : m_physical_access_registers(regs)
     , m_gsi_base(gsi_base)
     , m_gsi_base(gsi_base)
     , m_id((read_register(0x0) >> 24) & 0xFF)
     , m_id((read_register(0x0) >> 24) & 0xFF)
     , m_version(read_register(0x1) & 0xFF)
     , m_version(read_register(0x1) & 0xFF)
     , m_redirection_entries((read_register(0x1) >> 16) + 1)
     , 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 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;
     klog() << "IOAPIC Arbitration ID 0x" << String::format("%x", read_register(0x2));
     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)
 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());
         ASSERT(!redirection_override.is_null());
         if (redirection_override->source() != interrupt_vector)
         if (redirection_override->source() != interrupt_vector)
             continue;
             continue;
@@ -102,7 +98,7 @@ void IOAPIC::map_interrupt_redirection(u8 interrupt_vector)
             trigger_level_mode = true;
             trigger_level_mode = true;
             break;
             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;
         return;
     }
     }
     isa_identity_map(interrupt_vector);
     isa_identity_map(interrupt_vector);
@@ -110,18 +106,20 @@ void IOAPIC::map_interrupt_redirection(u8 interrupt_vector)
 
 
 void IOAPIC::isa_identity_map(int index)
 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()
 void IOAPIC::map_pci_interrupts()
 {
 {
+    InterruptDisabler disabler;
     configure_redirection_entry(11, 11 + IRQ_VECTOR_BASE, DeliveryMode::Normal, false, false, true, true, 0);
     configure_redirection_entry(11, 11 + IRQ_VECTOR_BASE, DeliveryMode::Normal, false, false, true, true, 0);
 }
 }
 
 
 void IOAPIC::map_isa_interrupts()
 void IOAPIC::map_isa_interrupts()
 {
 {
     InterruptDisabler disabler;
     InterruptDisabler disabler;
-    for (auto redirection_override : m_isa_interrupt_overrides) {
+    for (auto redirection_override : InterruptManagement::the().isa_overrides()) {
         ASSERT(!redirection_override.is_null());
         ASSERT(!redirection_override.is_null());
         bool active_low;
         bool active_low;
         // See ACPI spec Version 6.2, page 205 to learn more about Interrupt Overriding Flags.
         // 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;
             trigger_level_mode = true;
             break;
             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
 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);
     u32 redirection_entry1 = interrupt_vector | (delivery_mode & 0b111) << 8 | logical_destination << 11 | active_low << 13 | trigger_level_mode << 15 | masked << 16;
     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;
     u32 redirection_entry2 = destination << 24;
@@ -236,7 +235,7 @@ int IOAPIC::find_redirection_entry_by_vector(u8 vector) const
 {
 {
     InterruptDisabler disabler;
     InterruptDisabler disabler;
     for (size_t index = 0; index < m_redirection_entries; index++) {
     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 index;
     }
     }
     return -1;
     return -1;

+ 1 - 3
Kernel/Interrupts/IOAPIC.h

@@ -41,7 +41,7 @@ class PCIInterruptOverrideMetadata;
 
 
 class IOAPIC final : public IRQController {
 class IOAPIC final : public IRQController {
 public:
 public:
-    IOAPIC(ioapic_mmio_regs& regs, u32 gsi_base, Vector<RefPtr<ISAInterruptOverrideMetadata>>& overrides, Vector<RefPtr<PCIInterruptOverrideMetadata>>& pci_overrides);
+    IOAPIC(ioapic_mmio_regs& regs, u32 gsi_base);
     virtual void enable(u8 number) override;
     virtual void enable(u8 number) override;
     virtual void disable(u8 number) override;
     virtual void disable(u8 number) override;
     virtual void hard_disable() override;
     virtual void hard_disable() override;
@@ -81,7 +81,5 @@ private:
     u8 m_id;
     u8 m_id;
     u8 m_version;
     u8 m_version;
     u32 m_redirection_entries;
     u32 m_redirection_entries;
-    Vector<RefPtr<ISAInterruptOverrideMetadata>> m_isa_interrupt_overrides;
-    Vector<RefPtr<PCIInterruptOverrideMetadata>> m_pci_interrupt_overrides;
 };
 };
 }
 }

+ 31 - 1
Kernel/Interrupts/InterruptManagement.cpp

@@ -27,11 +27,14 @@
 #include <AK/FixedArray.h>
 #include <AK/FixedArray.h>
 #include <Kernel/ACPI/MultiProcessorParser.h>
 #include <Kernel/ACPI/MultiProcessorParser.h>
 #include <Kernel/Arch/i386/CPU.h>
 #include <Kernel/Arch/i386/CPU.h>
+#include <Kernel/Interrupts/APIC.h>
 #include <Kernel/Interrupts/IOAPIC.h>
 #include <Kernel/Interrupts/IOAPIC.h>
 #include <Kernel/Interrupts/InterruptManagement.h>
 #include <Kernel/Interrupts/InterruptManagement.h>
 #include <Kernel/Interrupts/PIC.h>
 #include <Kernel/Interrupts/PIC.h>
 #include <Kernel/Interrupts/SpuriousInterruptHandler.h>
 #include <Kernel/Interrupts/SpuriousInterruptHandler.h>
+#include <Kernel/Interrupts/UnhandledInterruptHandler.h>
 #include <Kernel/VM/MemoryManager.h>
 #include <Kernel/VM/MemoryManager.h>
+#include <LibBareMetal/IO.h>
 
 
 #define PCAT_COMPAT_FLAG 0x1
 #define PCAT_COMPAT_FLAG 0x1
 
 
@@ -72,6 +75,26 @@ IRQController& InterruptManagement::get_interrupt_controller(int index)
     return *m_interrupt_controllers[index];
     return *m_interrupt_controllers[index];
 }
 }
 
 
+Vector<RefPtr<ISAInterruptOverrideMetadata>> 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<IRQController> InterruptManagement::get_responsible_irq_controller(u8 interrupt_vector)
 RefPtr<IRQController> InterruptManagement::get_responsible_irq_controller(u8 interrupt_vector)
 {
 {
     if (m_interrupt_controllers.size() == 1 && m_interrupt_controllers[0]->type() == IRQControllerType::i8259) {
     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()
 void InterruptManagement::switch_to_pic_mode()
 {
 {
     klog() << "Interrupts: Switch to Legacy PIC mode";
     klog() << "Interrupts: Switch to Legacy PIC mode";
+    InterruptDisabler disabler;
+    m_smp_enabled = false;
     SpuriousInterruptHandler::initialize(7);
     SpuriousInterruptHandler::initialize(7);
     SpuriousInterruptHandler::initialize(15);
     SpuriousInterruptHandler::initialize(15);
     for (auto& irq_controller : m_interrupt_controllers) {
     for (auto& irq_controller : m_interrupt_controllers) {
@@ -126,6 +151,8 @@ void InterruptManagement::switch_to_pic_mode()
 void InterruptManagement::switch_to_ioapic_mode()
 void InterruptManagement::switch_to_ioapic_mode()
 {
 {
     klog() << "Interrupts: Switch to IOAPIC mode";
     klog() << "Interrupts: Switch to IOAPIC mode";
+    InterruptDisabler disabler;
+    m_smp_enabled = true;
     if (m_interrupt_controllers.size() == 1) {
     if (m_interrupt_controllers.size() == 1) {
         if (get_interrupt_controller(0).type() == IRQControllerType::i8259) {
         if (get_interrupt_controller(0).type() == IRQControllerType::i8259) {
             klog() << "Interrupts: NO IOAPIC detected, Reverting to PIC mode.";
             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();
             dbg() << "Interrupts: Detected " << irq_controller->model();
         }
         }
     }
     }
+    APIC::init();
+    APIC::enable_bsp();
+    MultiProcessorParser::initialize();
 }
 }
 
 
 void InterruptManagement::locate_apic_data()
 void InterruptManagement::locate_apic_data()
@@ -163,7 +193,7 @@ void InterruptManagement::locate_apic_data()
             auto* ioapic_entry = (const ACPI::Structures::MADTEntries::IOAPIC*)madt_entry;
             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);
             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.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++;
             irq_controller_count++;
         }
         }
         if (madt_entry->type == (u8)ACPI::Structures::MADTEntryType::InterruptSourceOverride) {
         if (madt_entry->type == (u8)ACPI::Structures::MADTEntryType::InterruptSourceOverride) {

+ 6 - 0
Kernel/Interrupts/InterruptManagement.h

@@ -47,11 +47,16 @@ public:
     static InterruptManagement& the();
     static InterruptManagement& the();
     static void initialize();
     static void initialize();
     static bool initialized();
     static bool initialized();
+    static u8 acquire_mapped_interrupt_number(u8);
 
 
     virtual void switch_to_pic_mode();
     virtual void switch_to_pic_mode();
     virtual void switch_to_ioapic_mode();
     virtual void switch_to_ioapic_mode();
     RefPtr<IRQController> get_responsible_irq_controller(u8 interrupt_vector);
     RefPtr<IRQController> get_responsible_irq_controller(u8 interrupt_vector);
 
 
+    Vector<RefPtr<ISAInterruptOverrideMetadata>> isa_overrides();
+
+    u8 get_mapped_vector_number(u8 original_vector);
+
     void enumerate_interrupt_handlers(Function<void(GenericInterruptHandler&)>);
     void enumerate_interrupt_handlers(Function<void(GenericInterruptHandler&)>);
     IRQController& get_interrupt_controller(int index);
     IRQController& get_interrupt_controller(int index);
 
 
@@ -60,6 +65,7 @@ private:
     PhysicalAddress search_for_madt();
     PhysicalAddress search_for_madt();
     void locate_apic_data();
     void locate_apic_data();
     void locate_pci_interrupt_overrides();
     void locate_pci_interrupt_overrides();
+    bool m_smp_enabled { false };
     FixedArray<RefPtr<IRQController>> m_interrupt_controllers { 1 };
     FixedArray<RefPtr<IRQController>> m_interrupt_controllers { 1 };
     Vector<RefPtr<ISAInterruptOverrideMetadata>> m_isa_interrupt_overrides;
     Vector<RefPtr<ISAInterruptOverrideMetadata>> m_isa_interrupt_overrides;
     Vector<RefPtr<PCIInterruptOverrideMetadata>> m_pci_interrupt_overrides;
     Vector<RefPtr<PCIInterruptOverrideMetadata>> m_pci_interrupt_overrides;