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.
This commit is contained in:
Bananymous 2024-07-21 17:30:59 +03:00
parent 819c130366
commit f49689caac
4 changed files with 24 additions and 2 deletions

View File

@ -19,6 +19,7 @@ namespace Kernel
virtual BAN::Optional<uint8_t> get_free_irq() override; virtual BAN::Optional<uint8_t> get_free_irq() override;
virtual void initialize_multiprocessor() override; virtual void initialize_multiprocessor() override;
virtual void send_ipi(ProcessorID target) override;
virtual void broadcast_ipi() override; virtual void broadcast_ipi() override;
virtual void enable() override; virtual void enable() override;

View File

@ -22,6 +22,7 @@ namespace Kernel
static InterruptController& get(); static InterruptController& get();
virtual void initialize_multiprocessor() = 0; virtual void initialize_multiprocessor() = 0;
virtual void send_ipi(ProcessorID target) = 0;
virtual void broadcast_ipi() = 0; virtual void broadcast_ipi() = 0;
virtual void enable() = 0; virtual void enable() = 0;

View File

@ -17,6 +17,7 @@ namespace Kernel
virtual BAN::Optional<uint8_t> get_free_irq() override; virtual BAN::Optional<uint8_t> get_free_irq() override;
virtual void initialize_multiprocessor() override; virtual void initialize_multiprocessor() override;
virtual void send_ipi(ProcessorID) override {}
virtual void broadcast_ipi() override {} virtual void broadcast_ipi() override {}
virtual void enable() override {} virtual void enable() override {}

View File

@ -319,8 +319,29 @@ namespace Kernel
dprintln("{} processors started", *g_ap_running_count); 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() 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_HI_REG, (read_from_local_apic(LAPIC_ICR_HI_REG) & 0x00FFFFFF) | 0xFF000000);
write_to_local_apic(LAPIC_ICR_LO_REG, write_to_local_apic(LAPIC_ICR_LO_REG,
(read_from_local_apic(LAPIC_ICR_LO_REG) & ICR_LO_reserved_mask) (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 | ICR_LO_destination_shorthand_all_excluding_self
| (IRQ_VECTOR_BASE + IRQ_IPI) | (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() void APIC::enable()