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()