From 58deafb1d845d0e5cdbf8d139fca8ed1ecc4ab34 Mon Sep 17 00:00:00 2001 From: Aiken Harris Date: Mon, 27 Apr 2026 22:11:30 +0200 Subject: [PATCH] Add support for sending broadcast IPIs --- xtoskrnl/hl/x86/pic.cc | 65 ++++++++++++++++++++++++++++++++++++- xtoskrnl/includes/hl/pic.hh | 8 +++-- 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/xtoskrnl/hl/x86/pic.cc b/xtoskrnl/hl/x86/pic.cc index 2b82955..b7005fb 100644 --- a/xtoskrnl/hl/x86/pic.cc +++ b/xtoskrnl/hl/x86/pic.cc @@ -726,6 +726,69 @@ HL::Pic::ResolveInterruptOverride(IN UCHAR Irq, *Gsi = (ULONG)Irq; } +/** + * Sends a Broadcast IPI (Inter-Processor Interrupt) to all processors in the system. + * + * @param Vector + * Supplies the hardware interrupt vector to trigger on the target processors. + * + * @param Self + * Supplies a boolean value indicating the broadcast scope. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +HL::Pic::SendBroadcastIpi(IN ULONG Vector, + IN BOOLEAN Self) +{ + APIC_COMMAND_REGISTER Register; + BOOLEAN Interrupts; + + /* Check whether interrupts are enabled */ + Interrupts = AR::CpuFunc::InterruptsEnabled(); + + /* Disable interrupts */ + AR::CpuFunc::ClearInterruptFlag(); + + /* Prepare the APIC command register */ + Register.LongLong = 0; + Register.DeliveryMode = APIC_DM_FIXED; + Register.DestinationShortHand = Self ? APIC_DSH_AllIncludingSelf : APIC_DSH_AllExclusingSelf; + Register.Level = 1; + Register.TriggerMode = APIC_TGM_EDGE; + Register.Vector = Vector; + + /* Check current APIC mode */ + if(ApicMode == APIC_MODE_X2APIC) + { + /* In x2APIC mode, writing the full 64-bit value to the ICR MSR is sufficient */ + WriteApicRegister(APIC_ICR0, Register.LongLong); + } + else + { + /* Wait for the APIC to clear the delivery status */ + while((ReadApicRegister(APIC_ICR0) & 0x1000) != 0) + { + /* Yield the processor */ + AR::CpuFunc::YieldProcessor(); + } + + /* In xAPIC compatibility mode, write the command to the ICR registers */ + WriteApicRegister(APIC_ICR1, Register.Long1); + WriteApicRegister(APIC_ICR0, Register.Long0); + } + + /* Check whether interrupts need to be re-enabled */ + if(Interrupts) + { + /* Re-enable interrupts */ + AR::CpuFunc::SetInterruptFlag(); + } +} + /** * Signals to the APIC that handling an interrupt is complete. * @@ -818,7 +881,7 @@ HL::Pic::SendSelfIpi(IN ULONG Vector) AR::CpuFunc::YieldProcessor(); } - /* In xAPIC compatibility mode, ICR0 is used */ + /* In xAPIC compatibility mode, write the command to the ICR registers */ WriteApicRegister(APIC_ICR1, Register.Long1); WriteApicRegister(APIC_ICR0, Register.Long0); diff --git a/xtoskrnl/includes/hl/pic.hh b/xtoskrnl/includes/hl/pic.hh index da6578a..19c41d4 100644 --- a/xtoskrnl/includes/hl/pic.hh +++ b/xtoskrnl/includes/hl/pic.hh @@ -26,11 +26,16 @@ namespace HL STATIC UCHAR MappedVectors[256]; public: + STATIC XTAPI VOID AllocateSystemInterrupt(IN UCHAR Irq, + IN UCHAR RunLevel, + IN UCHAR Vector); STATIC XTAPI VOID ClearApicErrors(VOID); STATIC XTAPI ULONG GetCpuApicId(VOID); STATIC XTAPI VOID InitializeIOApic(VOID); STATIC XTAPI VOID InitializePic(VOID); STATIC XTFASTCALL ULONGLONG ReadApicRegister(IN APIC_REGISTER Register); + STATIC XTAPI VOID SendBroadcastIpi(IN ULONG Vector, + IN BOOLEAN Self); STATIC XTAPI VOID SendEoi(VOID); STATIC XTAPI VOID SendIpi(IN ULONG ApicId, IN ULONG Vector); @@ -39,9 +44,6 @@ namespace HL IN ULONGLONG Value); private: - STATIC XTAPI VOID AllocateSystemInterrupt(IN UCHAR Irq, - IN UCHAR RunLevel, - IN UCHAR Vector); STATIC XTAPI BOOLEAN CheckApicSupport(VOID); STATIC XTAPI BOOLEAN CheckX2ApicSupport(VOID); STATIC XTAPI XTSTATUS DetectIoApicControllers(VOID);