From 89ca4c8a8b6d9c7892a2fdba4de9cbbaed3e7a12 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Sat, 9 Mar 2024 23:53:38 +0200 Subject: [PATCH] Kernel: Implement IPI broadcasting --- kernel/arch/x86_64/IDT.cpp | 2 +- kernel/arch/x86_64/interrupts.S | 1 + kernel/include/kernel/APIC.h | 2 ++ kernel/include/kernel/IDT.h | 1 + kernel/include/kernel/InterruptController.h | 2 ++ kernel/include/kernel/PIC.h | 2 ++ kernel/kernel/APIC.cpp | 30 ++++++++++++++++++--- kernel/kernel/kernel.cpp | 1 + 8 files changed, 36 insertions(+), 5 deletions(-) diff --git a/kernel/arch/x86_64/IDT.cpp b/kernel/arch/x86_64/IDT.cpp index c11ff2b856..dce1d4e341 100644 --- a/kernel/arch/x86_64/IDT.cpp +++ b/kernel/arch/x86_64/IDT.cpp @@ -10,7 +10,7 @@ #include #define ISR_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31) -#define IRQ_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31) +#define IRQ_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31) X(32) namespace Kernel { diff --git a/kernel/arch/x86_64/interrupts.S b/kernel/arch/x86_64/interrupts.S index 45acaa6aa9..7a78e818ce 100644 --- a/kernel/arch/x86_64/interrupts.S +++ b/kernel/arch/x86_64/interrupts.S @@ -174,6 +174,7 @@ irq 28 irq 29 irq 30 irq 31 +irq 32 // arguments in RAX, RBX, RCX, RDX, RSI, RDI // System V ABI: RDI, RSI, RDX, RCX, R8, R9 diff --git a/kernel/include/kernel/APIC.h b/kernel/include/kernel/APIC.h index 2e57e5de4c..074a5e0799 100644 --- a/kernel/include/kernel/APIC.h +++ b/kernel/include/kernel/APIC.h @@ -19,6 +19,8 @@ namespace Kernel virtual BAN::Optional get_free_irq() override; virtual void initialize_multiprocessor() override; + virtual void broadcast_ipi() override; + virtual void enable() override; private: uint32_t read_from_local_apic(ptrdiff_t); diff --git a/kernel/include/kernel/IDT.h b/kernel/include/kernel/IDT.h index 0a79c8a817..b99a66f298 100644 --- a/kernel/include/kernel/IDT.h +++ b/kernel/include/kernel/IDT.h @@ -7,6 +7,7 @@ #include constexpr uint8_t IRQ_VECTOR_BASE = 0x20; +constexpr uint8_t IRQ_IPI = 32; namespace Kernel { diff --git a/kernel/include/kernel/InterruptController.h b/kernel/include/kernel/InterruptController.h index 82b286e995..115d011220 100644 --- a/kernel/include/kernel/InterruptController.h +++ b/kernel/include/kernel/InterruptController.h @@ -21,6 +21,8 @@ namespace Kernel static InterruptController& get(); virtual void initialize_multiprocessor() = 0; + virtual void broadcast_ipi() = 0; + virtual void enable() = 0; virtual BAN::ErrorOr reserve_irq(uint8_t irq) = 0; virtual BAN::Optional get_free_irq() = 0; diff --git a/kernel/include/kernel/PIC.h b/kernel/include/kernel/PIC.h index 51fe0413c3..117071a42f 100644 --- a/kernel/include/kernel/PIC.h +++ b/kernel/include/kernel/PIC.h @@ -17,6 +17,8 @@ namespace Kernel virtual BAN::Optional get_free_irq() override; virtual void initialize_multiprocessor() override; + virtual void broadcast_ipi() override {} + virtual void enable() override {} static void remap(); static void mask_all(); diff --git a/kernel/kernel/APIC.cpp b/kernel/kernel/APIC.cpp index 274449c3a5..0c46d6513b 100644 --- a/kernel/kernel/APIC.cpp +++ b/kernel/kernel/APIC.cpp @@ -215,9 +215,8 @@ namespace Kernel io_apic.max_redirs = io_apic.read(IOAPIC_MAX_REDIRS); } - // Mask all interrupts - uint32_t sivr = apic->read_from_local_apic(LAPIC_SIV_REG); - apic->write_to_local_apic(LAPIC_SIV_REG, sivr | 0x1FF); + // Enable local apic + apic->write_to_local_apic(LAPIC_SIV_REG, apic->read_from_local_apic(LAPIC_SIV_REG) | 0x1FF); return apic; } @@ -313,6 +312,28 @@ namespace Kernel dprintln("{} processors started", *g_ap_running_count); } + void APIC::broadcast_ipi() + { + write_to_local_apic(LAPIC_ICR_HI_REG, (read_from_local_apic(LAPIC_ICR_HI_REG) & 0x00FFFFFF) | 0xFF000000); + write_to_local_apic(LAPIC_ICR_LO_REG, + (read_from_local_apic(LAPIC_ICR_LO_REG) & ICR_LO_reserved_mask) + | ICR_LO_delivery_mode_fixed + | ICR_LO_destination_mode_physical + | ICR_LO_level_assert + | ICR_LO_trigger_mode_level + | ICR_LO_destination_shorthand_all_excluding_self + | (IRQ_VECTOR_BASE + IRQ_IPI) + ); + while ((read_from_local_apic(LAPIC_ICR_LO_REG) & ICR_LO_delivery_status_send_pending) == ICR_LO_delivery_status_send_pending) + __builtin_ia32_pause(); + } + + void APIC::enable() + { + write_to_local_apic(LAPIC_SIV_REG, read_from_local_apic(LAPIC_SIV_REG) | 0x1FF); + } + + uint32_t APIC::read_from_local_apic(ptrdiff_t offset) { return MMIO::read32(m_local_apic_vaddr + offset); @@ -370,7 +391,8 @@ namespace Kernel redir.vector = IRQ_VECTOR_BASE + irq; redir.mask = 0; - redir.destination = m_processors.front().apic_id; + // FIXME: distribute IRQs more evenly? + redir.destination = Kernel::Processor::bsb_id(); ioapic->write(IOAPIC_REDIRS + gsi * 2, redir.lo_dword); ioapic->write(IOAPIC_REDIRS + gsi * 2 + 1, redir.hi_dword); diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index 238d1f8d91..c9f85c8f6f 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -214,6 +214,7 @@ extern "C" void ap_main() Processor::initialize(); PageTable::kernel().initial_load(); Processor::allocate_idle_thread(); + InterruptController::get().enable(); dprintln("ap{} initialized", Processor::current_id());