https://git.reactos.org/?p=reactos.git;a=commitdiff;h=40b6b1dab3169b1a59473…
commit 40b6b1dab3169b1a59473bed06de9a9588f24d5b
Author: Timo Kreuzer <timo.kreuzer(a)reactos.org>
AuthorDate: Sun Nov 26 17:32:27 2023 +0200
Commit: Timo Kreuzer <timo.kreuzer(a)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/int…
+//
https://github.com/mirror/vbox/blob/b9657cd5351cf17432b664009cc25bb480dc64c…
+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