From f49689caac4cac9acaed3332825cc2fd0ec54687 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Sun, 21 Jul 2024 17:30:59 +0300 Subject: [PATCH] Kernel: Implement API for sending IPIs for only one processor Also move the spin wait to check for pending IPI sends to the start of ipi sending function. There is no need to wait for IPI send succeeding right after it. It is enough to make sure there are not multiple IPIs being sent at the same time. --- kernel/include/kernel/APIC.h | 1 + kernel/include/kernel/InterruptController.h | 1 + kernel/include/kernel/PIC.h | 1 + kernel/kernel/APIC.cpp | 23 +++++++++++++++++++-- 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/kernel/include/kernel/APIC.h b/kernel/include/kernel/APIC.h index 074a5e0799..b0bd0427b7 100644 --- a/kernel/include/kernel/APIC.h +++ b/kernel/include/kernel/APIC.h @@ -19,6 +19,7 @@ namespace Kernel virtual BAN::Optional get_free_irq() override; virtual void initialize_multiprocessor() override; + virtual void send_ipi(ProcessorID target) override; virtual void broadcast_ipi() override; virtual void enable() override; diff --git a/kernel/include/kernel/InterruptController.h b/kernel/include/kernel/InterruptController.h index 47a53f84f6..6f11c7b6d2 100644 --- a/kernel/include/kernel/InterruptController.h +++ b/kernel/include/kernel/InterruptController.h @@ -22,6 +22,7 @@ namespace Kernel static InterruptController& get(); virtual void initialize_multiprocessor() = 0; + virtual void send_ipi(ProcessorID target) = 0; virtual void broadcast_ipi() = 0; virtual void enable() = 0; diff --git a/kernel/include/kernel/PIC.h b/kernel/include/kernel/PIC.h index 117071a42f..31193a3560 100644 --- a/kernel/include/kernel/PIC.h +++ b/kernel/include/kernel/PIC.h @@ -17,6 +17,7 @@ namespace Kernel virtual BAN::Optional get_free_irq() override; virtual void initialize_multiprocessor() override; + virtual void send_ipi(ProcessorID) override {} virtual void broadcast_ipi() override {} virtual void enable() override {} diff --git a/kernel/kernel/APIC.cpp b/kernel/kernel/APIC.cpp index 8830a6991c..393c4506ac 100644 --- a/kernel/kernel/APIC.cpp +++ b/kernel/kernel/APIC.cpp @@ -319,8 +319,29 @@ namespace Kernel dprintln("{} processors started", *g_ap_running_count); } + + void APIC::send_ipi(ProcessorID target) + { + ASSERT(Kernel::Processor::get_interrupt_state() == InterruptState::Disabled); + while ((read_from_local_apic(LAPIC_ICR_LO_REG) & ICR_LO_delivery_status_send_pending) == ICR_LO_delivery_status_send_pending) + __builtin_ia32_pause(); + write_to_local_apic(LAPIC_ICR_HI_REG, (read_from_local_apic(LAPIC_ICR_HI_REG) & 0x00FFFFFF) | (target << 24)); + 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_none + | (IRQ_VECTOR_BASE + IRQ_IPI) + ); + } + void APIC::broadcast_ipi() { + ASSERT(Kernel::Processor::get_interrupt_state() == InterruptState::Disabled); + while ((read_from_local_apic(LAPIC_ICR_LO_REG) & ICR_LO_delivery_status_send_pending) == ICR_LO_delivery_status_send_pending) + __builtin_ia32_pause(); 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) @@ -331,8 +352,6 @@ namespace Kernel | 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()