https://git.reactos.org/?p=reactos.git;a=commitdiff;h=40b6b1dab3169b1a59473bed06de9a9588f24d5b

commit 40b6b1dab3169b1a59473bed06de9a9588f24d5b
Author:     Timo Kreuzer <timo.kreu...@reactos.org>
AuthorDate: Sun Nov 26 17:32:27 2023 +0200
Commit:     Timo Kreuzer <timo.kreu...@reactos.org>
CommitDate: Sun Dec 3 00:07:53 2023 +0200

    [HAL] Implement IPI support functions
---
 hal/hal.spec               |   4 +-
 hal/halx86/apic/apicp.h    |   2 +-
 hal/halx86/apic/apicsmp.c  | 177 +++++++++++++++++++++++++++++++++++++++++++--
 hal/halx86/generic/up.c    |  19 +++++
 hal/halx86/include/smp.h   |  38 ++++++++++
 hal/halx86/smp/ipi.c       |  24 ++++++
 sdk/include/ndk/halfuncs.h |  17 +++++
 7 files changed, 270 insertions(+), 11 deletions(-)

diff --git a/hal/hal.spec b/hal/hal.spec
index 94bb141afee..2a3285e1c81 100644
--- a/hal/hal.spec
+++ b/hal/hal.spec
@@ -41,8 +41,8 @@
 @ stdcall HalRequestIpi(long)
 @ fastcall HalRequestSoftwareInterrupt(long)
 @ stdcall HalReturnToFirmware(long)
-;@ stdcall -arch=x86_64 HalSendNMI()
-;@ stdcall -arch=x86_64 HalSendSoftwareInterrupt()
+@ stdcall -arch=x86_64 HalSendNMI(int64)
+@ stdcall -arch=x86_64 HalSendSoftwareInterrupt(int64 long)
 @ stdcall HalSetBusData(long long long ptr long)
 @ stdcall HalSetBusDataByOffset(long long long ptr long long)
 @ stdcall HalSetDisplayParameters(long long)
diff --git a/hal/halx86/apic/apicp.h b/hal/halx86/apic/apicp.h
index 245ab197f59..0a91da45992 100644
--- a/hal/halx86/apic/apicp.h
+++ b/hal/halx86/apic/apicp.h
@@ -151,7 +151,7 @@ typedef enum _APIC_DSH
     APIC_DSH_Destination,
     APIC_DSH_Self,
     APIC_DSH_AllIncludingSelf,
-    APIC_DSH_AllExclusingSelf
+    APIC_DSH_AllExcludingSelf
 } APIC_DSH;
 
 /* Write Constants */
diff --git a/hal/halx86/apic/apicsmp.c b/hal/halx86/apic/apicsmp.c
index d8684742268..47415bc84b6 100644
--- a/hal/halx86/apic/apicsmp.c
+++ b/hal/halx86/apic/apicsmp.c
@@ -106,14 +106,6 @@ ApicRequestGlobalInterrupt(
 
 /* SMP SUPPORT FUNCTIONS 
******************************************************/
 
-VOID
-NTAPI
-HalpRequestIpi(_In_ KAFFINITY TargetProcessors)
-{
-    UNIMPLEMENTED;
-    __debugbreak();
-}
-
 VOID
 ApicStartApplicationProcessor(
     _In_ ULONG NTProcessorNumber,
@@ -138,3 +130,172 @@ ApicStartApplicationProcessor(
     
ApicRequestGlobalInterrupt(HalpProcessorIdentity[NTProcessorNumber].LapicId, 
(StartupLoc.LowPart) >> 12,
         APIC_MT_Startup, APIC_TGM_Edge, APIC_DSH_Destination);
 }
+
+/* HAL IPI FUNCTIONS 
**********************************************************/
+
+/*!
+ *  \brief Broadcasts an IPI with a specified vector to all processors.
+ *
+ *  \param Vector - Specifies the interrupt vector to be delivered.
+ *  \param IncludeSelf - Specifies whether to include the current processor.
+ */
+VOID
+NTAPI
+HalpBroadcastIpiSpecifyVector(
+    _In_ UCHAR Vector,
+    _In_ BOOLEAN IncludeSelf)
+{
+    APIC_DSH DestinationShortHand = IncludeSelf ?
+        APIC_DSH_AllIncludingSelf : APIC_DSH_AllExcludingSelf;
+
+    /* Request the interrupt targeted at all processors */
+    ApicRequestGlobalInterrupt(0, // Ignored
+                               Vector,
+                               APIC_MT_Fixed,
+                               APIC_TGM_Edge,
+                               DestinationShortHand);
+}
+
+/*!
+ *  \brief Requests an IPI with a specified vector on the specified processors.
+ *
+ *  \param TargetSet - Specifies the set of processors to send the IPI to.
+ *  \param Vector - Specifies the interrupt vector to be delivered.
+ *
+ *  \remarks This function is exported on Windows 10.
+ */
+VOID
+NTAPI
+HalRequestIpiSpecifyVector(
+    _In_ KAFFINITY TargetSet,
+    _In_ UCHAR Vector)
+{
+    KAFFINITY ActiveProcessors = KeQueryActiveProcessors();
+    KAFFINITY RemainingSet, SetMember;
+    ULONG ProcessorIndex;
+    ULONG LApicId;
+
+    /* Sanitize the target set */
+    TargetSet &= ActiveProcessors;
+
+    /* Check if all processors are requested */
+    if (TargetSet == ActiveProcessors)
+    {
+        /* Send an IPI to all processors, including this processor */
+        HalpBroadcastIpiSpecifyVector(Vector, TRUE);
+        return;
+    }
+
+    /* Check if all processors except the current one are requested */
+    if (TargetSet == (ActiveProcessors & ~KeGetCurrentPrcb()->SetMember))
+    {
+        /* Send an IPI to all processors, excluding this processor */
+        HalpBroadcastIpiSpecifyVector(Vector, FALSE);
+        return;
+    }
+
+    /* Loop while we have more processors */
+    RemainingSet = TargetSet;
+    while (RemainingSet != 0)
+    {
+        NT_VERIFY(BitScanForwardAffinity(&ProcessorIndex, RemainingSet) != 0);
+        ASSERT(ProcessorIndex < KeNumberProcessors);
+        SetMember = AFFINITY_MASK(ProcessorIndex);
+        RemainingSet &= ~SetMember;
+
+        /* Send the interrupt to the target processor */
+        LApicId = HalpProcessorIdentity[ProcessorIndex].LapicId;
+        ApicRequestGlobalInterrupt(LApicId,
+                                   Vector,
+                                   APIC_MT_Fixed,
+                                   APIC_TGM_Edge,
+                                   APIC_DSH_Destination);
+    }
+}
+
+/*!
+ *  \brief Requests an IPI interrupt on the specified processors.
+ *
+ *  \param TargetSet - Specifies the set of processors to send the IPI to.
+ */
+VOID
+NTAPI
+HalpRequestIpi(
+    _In_ KAFFINITY TargetSet)
+{
+    /* Request the IPI vector */
+    HalRequestIpiSpecifyVector(TargetSet, APIC_IPI_VECTOR);
+}
+
+#ifdef _M_AMD64
+
+/*!
+ *  \brief Requests a software interrupt on the specified processors.
+ *
+ *  \param TargetSet - Specifies the set of processors to send the IPI to.
+ *  \param Irql - Specifies the IRQL of the software interrupt.
+ */
+VOID
+NTAPI
+HalpSendSoftwareInterrupt(
+    _In_ KAFFINITY TargetSet,
+    _In_ KIRQL Irql)
+{
+    UCHAR Vector;
+
+    /* Get the vector for the requested IRQL */
+    if (Irql == APC_LEVEL)
+    {
+        Vector = APC_VECTOR;
+    }
+    else if (Irql == DISPATCH_LEVEL)
+    {
+        Vector = DISPATCH_VECTOR;
+    }
+    else
+    {
+        ASSERT(FALSE);
+        return;
+    }
+
+    /* Request the IPI with the specified vector */
+    HalRequestIpiSpecifyVector(TargetSet, Vector);
+}
+
+/*!
+ *  \brief Requests an NMI interrupt on the specified processors.
+ *
+ *  \param TargetSet - Specifies the set of processors to send the IPI to.
+ */
+VOID
+NTAPI
+HalpSendNMI(
+    _In_ KAFFINITY TargetSet)
+{
+    KAFFINITY RemainingSet, SetMember;
+    ULONG ProcessorIndex;
+    ULONG LApicId;
+
+    /* Make sure we do not send an NMI to ourselves */
+    ASSERT((TargetSet & ~KeGetCurrentPrcb()->SetMember) == 0);
+
+    /* Loop while we have more processors */
+    RemainingSet = TargetSet;
+    while (RemainingSet != 0)
+    {
+        NT_VERIFY(BitScanForwardAffinity(&ProcessorIndex, RemainingSet) != 0);
+        ASSERT(ProcessorIndex < KeNumberProcessors);
+        SetMember = AFFINITY_MASK(ProcessorIndex);
+        RemainingSet &= ~SetMember;
+
+        /* Send and NMI to the target processor */
+        LApicId = HalpProcessorIdentity[ProcessorIndex].LapicId;
+        ApicRequestGlobalInterrupt(LApicId,
+                                   0,
+                                   APIC_MT_NMI,
+                                   APIC_TGM_Edge,
+                                   APIC_DSH_Destination);
+    }
+}
+
+#endif // _M_AMD64
diff --git a/hal/halx86/generic/up.c b/hal/halx86/generic/up.c
index a7162774d89..dd60cc1cffb 100644
--- a/hal/halx86/generic/up.c
+++ b/hal/halx86/generic/up.c
@@ -32,3 +32,22 @@ HalStartNextProcessor(
     /* Always return false on UP systems */
     return FALSE;
 }
+
+#ifdef _M_AMD64
+
+VOID
+NTAPI
+HalSendNMI(
+    _In_ KAFFINITY TargetSet)
+{
+}
+
+VOID
+NTAPI
+HalSendSoftwareInterrupt(
+    _In_ KAFFINITY TargetSet,
+    _In_ KIRQL Irql)
+{
+}
+
+#endif // _M_AMD64
diff --git a/hal/halx86/include/smp.h b/hal/halx86/include/smp.h
index 86b1ded5f77..d35189801c5 100644
--- a/hal/halx86/include/smp.h
+++ b/hal/halx86/include/smp.h
@@ -7,6 +7,15 @@
 
 #pragma once
 
+#define AFFINITY_MASK(Id) ((KAFFINITY)1 << (Id))
+
+/* Helper to find the lowest CPU in a KAFFINITY */
+#ifdef _WIN64
+#define BitScanForwardAffinity BitScanForward64
+#else
+#define BitScanForwardAffinity BitScanForward
+#endif
+
 /* This table is filled for each physical processor on system */
 typedef struct _PROCESSOR_IDENTITY
 {
@@ -53,3 +62,32 @@ VOID
 NTAPI
 HalpRequestIpi(
     _In_ KAFFINITY TargetProcessors);
+
+VOID
+NTAPI
+HalpBroadcastIpiSpecifyVector(
+    _In_ UCHAR Vector,
+    _In_ BOOLEAN IncludeSelf);
+
+VOID
+NTAPI
+HalRequestIpiSpecifyVector(
+    _In_ KAFFINITY TargetSet,
+    _In_ UCHAR Vector);
+
+#ifdef _M_AMD64
+
+NTHALAPI
+VOID
+NTAPI
+HalpSendNMI(
+    _In_ KAFFINITY TargetSet);
+
+NTHALAPI
+VOID
+NTAPI
+HalpSendSoftwareInterrupt(
+    _In_ KAFFINITY TargetSet,
+    _In_ KIRQL Irql);
+
+#endif // _M_AMD64
diff --git a/hal/halx86/smp/ipi.c b/hal/halx86/smp/ipi.c
index b215508c622..a2411961dae 100644
--- a/hal/halx86/smp/ipi.c
+++ b/hal/halx86/smp/ipi.c
@@ -22,3 +22,27 @@ HalRequestIpi(
 {
     HalpRequestIpi(TargetProcessors);
 }
+
+#ifdef _M_AMD64
+
+VOID
+NTAPI
+HalSendNMI(
+    _In_ KAFFINITY TargetSet)
+{
+    HalpSendNMI(TargetSet);
+}
+
+// See:
+// - 
https://www.virtualbox.org/browser/vbox/trunk/src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h#L53
+// 
https://github.com/mirror/vbox/blob/b9657cd5351cf17432b664009cc25bb480dc64c1/src/VBox/Runtime/r0drv/nt/mp-r0drv-nt.cpp#L683
+VOID
+NTAPI
+HalSendSoftwareInterrupt(
+    _In_ KAFFINITY TargetSet,
+    _In_ KIRQL Irql)
+{
+    HalpSendSoftwareInterrupt(TargetSet, Irql);
+}
+
+#endif // _M_AMD64
diff --git a/sdk/include/ndk/halfuncs.h b/sdk/include/ndk/halfuncs.h
index 2c4b56075ad..d5bb1aae56d 100644
--- a/sdk/include/ndk/halfuncs.h
+++ b/sdk/include/ndk/halfuncs.h
@@ -192,6 +192,23 @@ HalRequestSoftwareInterrupt(
     _In_ KIRQL SoftwareInterruptRequested
 );
 
+#ifdef _M_AMD64
+
+NTHALAPI
+VOID
+NTAPI
+HalSendNMI(
+    _In_ KAFFINITY TargetSet);
+
+NTHALAPI
+VOID
+NTAPI
+HalSendSoftwareInterrupt(
+    _In_ KAFFINITY TargetSet,
+    _In_ KIRQL Irql);
+
+#endif // _M_AMD64
+
 NTHALAPI
 VOID
 NTAPI

Reply via email to