https://git.reactos.org/?p=reactos.git;a=commitdiff;h=edb7575faa0be6c9f19a2…
commit edb7575faa0be6c9f19a2632f15e95f96ab2f54d
Author: Marcin Jabłoński <nnxcomputing(a)gmail.com>
AuthorDate: Tue Nov 22 21:52:18 2022 +0100
Commit: GitHub <noreply(a)github.com>
CommitDate: Tue Nov 22 23:52:18 2022 +0300
[NTOS:KE/x64] Implement KeDisconnectInterrupt() for amd64 (#4883)
Choose the correct element of the KiUnexpectedRange array,
depending on the interrupt vector, the same way as here:
https://github.com/reactos/reactos/blob/a2c6af0da4acbba9c254d003e9d9f4ea6e0…
And guard KeConnectInterrupt() execution with dispatcher lock.
CORE-14922
---
ntoskrnl/ke/amd64/interrupt.c | 86 ++++++++++++++++++++++++++++++++++++++-----
1 file changed, 76 insertions(+), 10 deletions(-)
diff --git a/ntoskrnl/ke/amd64/interrupt.c b/ntoskrnl/ke/amd64/interrupt.c
index a1e66da4dde..bf74eb2722c 100644
--- a/ntoskrnl/ke/amd64/interrupt.c
+++ b/ntoskrnl/ke/amd64/interrupt.c
@@ -17,8 +17,8 @@
#include <debug.h>
extern UCHAR KiInterruptDispatchTemplate[16];
-extern UCHAR KiUnexpectedRange[];
-extern UCHAR KiUnexpectedRangeEnd[];
+extern KI_INTERRUPT_DISPATCH_ENTRY KiUnexpectedRange[256];
+extern KI_INTERRUPT_DISPATCH_ENTRY KiUnexpectedRangeEnd[];
void KiInterruptDispatch(void);
@@ -82,6 +82,7 @@ KeConnectInterrupt(IN PKINTERRUPT Interrupt)
{
PVOID CurrentHandler;
PKINTERRUPT ConnectedInterrupt;
+ KIRQL OldIrql;
ASSERT(Interrupt->Vector >= PRIMARY_VECTOR_BASE);
ASSERT(Interrupt->Vector <= MAXIMUM_IDTVECTOR);
@@ -93,6 +94,10 @@ KeConnectInterrupt(IN PKINTERRUPT Interrupt)
/* Check if its already connected */
if (Interrupt->Connected) return TRUE;
+ /* Set the system affinity and acquire the dispatcher lock */
+ KeSetSystemAffinityThread(1ULL << Interrupt->Number);
+ OldIrql = KiAcquireDispatcherLock();
+
/* Query the current handler */
CurrentHandler = KeQueryInterruptHandler(Interrupt->Vector);
@@ -118,7 +123,7 @@ KeConnectInterrupt(IN PKINTERRUPT Interrupt)
/* Didn't work, restore old handler */
DPRINT1("HalEnableSystemInterrupt failed\n");
KeRegisterInterruptHandler(Interrupt->Vector, CurrentHandler);
- return FALSE;
+ goto Cleanup;
}
}
else
@@ -131,7 +136,7 @@ KeConnectInterrupt(IN PKINTERRUPT Interrupt)
(ConnectedInterrupt->ShareVector == 0) ||
(Interrupt->Mode != ConnectedInterrupt->Mode))
{
- return FALSE;
+ goto Cleanup;
}
/* Insert the new interrupt into the connected interrupt's list */
@@ -142,21 +147,82 @@ KeConnectInterrupt(IN PKINTERRUPT Interrupt)
/* Mark as connected */
Interrupt->Connected = TRUE;
- return TRUE;
+Cleanup:
+ /* Release the dispatcher lock and restore the thread affinity */
+ KiReleaseDispatcherLock(OldIrql);
+ KeRevertToUserAffinityThread();
+ return Interrupt->Connected;
}
BOOLEAN
NTAPI
KeDisconnectInterrupt(IN PKINTERRUPT Interrupt)
{
- /* If the interrupt wasn't connected, there's nothing to do */
- if (!Interrupt->Connected)
+ KIRQL OldIrql;
+ PVOID VectorHandler, UnexpectedHandler;
+ PKINTERRUPT VectorFirstInterrupt, NextInterrupt;
+ PLIST_ENTRY HandlerHead;
+
+ /* Set the system affinity and acquire the dispatcher lock */
+ KeSetSystemAffinityThread(1ULL << Interrupt->Number);
+ OldIrql = KiAcquireDispatcherLock();
+
+ /* Check if the interrupt was connected - otherwise there's nothing to do */
+ if (Interrupt->Connected)
{
- return FALSE;
+ /* Get the handler for this interrupt vector */
+ VectorHandler = KeQueryInterruptHandler(Interrupt->Vector);
+
+ /* Get the first interrupt for this handler */
+ VectorFirstInterrupt = CONTAINING_RECORD(VectorHandler, KINTERRUPT,
DispatchCode);
+
+ /* The first interrupt list entry is the interrupt list head */
+ HandlerHead = &VectorFirstInterrupt->InterruptListEntry;
+
+ /* If the list is empty, this is the only interrupt for this vector */
+ if (IsListEmpty(HandlerHead))
+ {
+ /* If the list is empty, and the head is not from this interrupt,
+ * this interrupt is somehow incorrectly connected */
+ ASSERT(VectorFirstInterrupt == Interrupt);
+
+ UnexpectedHandler = &KiUnexpectedRange[Interrupt->Vector]._Op_push;
+
+ /* This is the only interrupt, the handler can be disconnected */
+ HalDisableSystemInterrupt(Interrupt->Vector, Interrupt->Irql);
+ KeRegisterInterruptHandler(Interrupt->Vector, UnexpectedHandler);
+ }
+ /* If the interrupt to be disconnected is the list head, but some others follow
*/
+ else if (VectorFirstInterrupt == Interrupt)
+ {
+ /* Relocate the head to the next element */
+ HandlerHead = HandlerHead->Flink;
+ RemoveTailList(HandlerHead);
+
+ /* Get the next interrupt from the list head */
+ NextInterrupt = CONTAINING_RECORD(HandlerHead,
+ KINTERRUPT,
+ InterruptListEntry);
+
+ /* Set the next interrupt as the handler for this vector */
+ KeRegisterInterruptHandler(Interrupt->Vector,
+ NextInterrupt->DispatchCode);
+ }
+ /* If the interrupt to be disconnected is not the list head */
+ else
+ {
+ /* Remove the to be disconnected interrupt from the interrupt list */
+ RemoveEntryList(&Interrupt->InterruptListEntry);
+ }
+
+ /* Mark as not connected */
+ Interrupt->Connected = FALSE;
}
- UNIMPLEMENTED;
- __debugbreak();
+ /* Release the dispatcher lock and restore the thread affinity */
+ KiReleaseDispatcherLock(OldIrql);
+ KeRevertToUserAffinityThread();
+
return TRUE;
}