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

commit edb7575faa0be6c9f19a2632f15e95f96ab2f54d
Author:     Marcin Jabłoński <[email protected]>
AuthorDate: Tue Nov 22 21:52:18 2022 +0100
Commit:     GitHub <[email protected]>
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/a2c6af0da4acbba9c254d003e9d9f4ea6e03ed63/ntoskrnl/ke/amd64/except.c#L77
    
    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;
 }
 

Reply via email to