https://git.reactos.org/?p=reactos.git;a=commitdiff;h=7f2e0ece5a4e408f50929…
commit 7f2e0ece5a4e408f509299a7efe1aec72a471432
Author: Timo Kreuzer <timo.kreuzer(a)reactos.org>
AuthorDate: Fri Mar 9 23:55:54 2018 +0100
Commit: Timo Kreuzer <timo.kreuzer(a)reactos.org>
CommitDate: Fri Jun 4 09:19:13 2021 +0200
[NTOS:KE/x64] Handle shared interrupts
---
ntoskrnl/ke/amd64/interrupt.c | 37 ++++++++++++++++++++++++++++++-------
ntoskrnl/ke/amd64/trap.S | 37 ++++++++++++++++++++++++++++++-------
2 files changed, 60 insertions(+), 14 deletions(-)
diff --git a/ntoskrnl/ke/amd64/interrupt.c b/ntoskrnl/ke/amd64/interrupt.c
index 1ca46b33673..a1e66da4dde 100644
--- a/ntoskrnl/ke/amd64/interrupt.c
+++ b/ntoskrnl/ke/amd64/interrupt.c
@@ -81,10 +81,14 @@ NTAPI
KeConnectInterrupt(IN PKINTERRUPT Interrupt)
{
PVOID CurrentHandler;
+ PKINTERRUPT ConnectedInterrupt;
+ ASSERT(Interrupt->Vector >= PRIMARY_VECTOR_BASE);
ASSERT(Interrupt->Vector <= MAXIMUM_IDTVECTOR);
ASSERT(Interrupt->Number < KeNumberProcessors);
ASSERT(Interrupt->Irql <= HIGH_LEVEL);
+ ASSERT(Interrupt->SynchronizeIrql >= Interrupt->Irql);
+ ASSERT(Interrupt->Irql == (Interrupt->Vector >> 4));
/* Check if its already connected */
if (Interrupt->Connected) return TRUE;
@@ -92,7 +96,7 @@ KeConnectInterrupt(IN PKINTERRUPT Interrupt)
/* Query the current handler */
CurrentHandler = KeQueryInterruptHandler(Interrupt->Vector);
- /* Check if the vector is already unused */
+ /* Check if the vector is unused */
if ((CurrentHandler >= (PVOID)KiUnexpectedRange) &&
(CurrentHandler <= (PVOID)KiUnexpectedRangeEnd))
{
@@ -106,6 +110,7 @@ KeConnectInterrupt(IN PKINTERRUPT Interrupt)
KeRegisterInterruptHandler(Interrupt->Vector,
Interrupt->DispatchCode);
+ /* Enable the interrupt */
if (!HalEnableSystemInterrupt(Interrupt->Vector,
Interrupt->Irql,
Interrupt->Mode))
@@ -115,16 +120,28 @@ KeConnectInterrupt(IN PKINTERRUPT Interrupt)
KeRegisterInterruptHandler(Interrupt->Vector, CurrentHandler);
return FALSE;
}
-
- /* Mark as connected */
- Interrupt->Connected = TRUE;
}
else
{
- // later
- __debugbreak();
+ /* Get the connected interrupt */
+ ConnectedInterrupt = CONTAINING_RECORD(CurrentHandler, KINTERRUPT,
DispatchCode);
+
+ /* Check if sharing is ok */
+ if ((Interrupt->ShareVector == 0) ||
+ (ConnectedInterrupt->ShareVector == 0) ||
+ (Interrupt->Mode != ConnectedInterrupt->Mode))
+ {
+ return FALSE;
+ }
+
+ /* Insert the new interrupt into the connected interrupt's list */
+ InsertTailList(&ConnectedInterrupt->InterruptListEntry,
+ &Interrupt->InterruptListEntry);
}
+ /* Mark as connected */
+ Interrupt->Connected = TRUE;
+
return TRUE;
}
@@ -132,9 +149,15 @@ BOOLEAN
NTAPI
KeDisconnectInterrupt(IN PKINTERRUPT Interrupt)
{
+ /* If the interrupt wasn't connected, there's nothing to do */
+ if (!Interrupt->Connected)
+ {
+ return FALSE;
+ }
+
UNIMPLEMENTED;
__debugbreak();
- return FALSE;
+ return TRUE;
}
BOOLEAN
diff --git a/ntoskrnl/ke/amd64/trap.S b/ntoskrnl/ke/amd64/trap.S
index 7fb5c05919b..b7a267a7256 100644
--- a/ntoskrnl/ke/amd64/trap.S
+++ b/ntoskrnl/ke/amd64/trap.S
@@ -696,26 +696,35 @@ FUNC KiInterruptDispatch
/* Increase interrupt count */
inc dword ptr gs:[PcInterruptCount];
- /* Load the address of the interrupt object into rcx */
- mov rcx, [rbp + KTRAP_FRAME_ErrorCode]
+ /* Save rbx and rsi in the trap frame */
+ mov [rbp + KTRAP_FRAME_Rbx], rbx
+ mov [rbp + KTRAP_FRAME_Rsi], rsi
+
+ /* Load the address of the dispatch code into rbx */
+ mov rbx, [rbp + KTRAP_FRAME_ErrorCode]
/* Substract offset of the DispatchCode member plus 6 for the call instruction */
- sub rcx, KINTERRUPT_DispatchCode + 6
+ sub rbx, KINTERRUPT_DispatchCode + 6
+
+ /* Save the address of the InterruptListEntry in rsi */
+ lea rsi, [rbx + KINTERRUPT_InterruptListEntry]
+.DoDispatchInterrupt:
/* Raise IRQL to SynchronizeIrql */
- movzx rax, byte ptr [rcx + KINTERRUPT_SynchronizeIrql]
+ movzx rax, byte ptr [rbx + KINTERRUPT_SynchronizeIrql]
mov cr8, rax
#ifdef CONFIG_SMP
/* Acquire interrupt lock */
- mov r8, [rcx + KINTERRUPT_ActualLock]
+ mov r8, [rbx + KINTERRUPT_ActualLock]
//KxAcquireSpinLock(Interrupt->ActualLock);
#endif
/* Call the ISR */
- mov rdx, [rcx + KINTERRUPT_ServiceContext]
- call qword ptr [rcx + KINTERRUPT_ServiceRoutine]
+ mov rcx, rbx
+ mov rdx, [rbx + KINTERRUPT_ServiceContext]
+ call qword ptr [rbx + KINTERRUPT_ServiceRoutine]
#ifdef CONFIG_SMP
/* Release interrupt lock */
@@ -726,6 +735,20 @@ FUNC KiInterruptDispatch
movzx rax, byte ptr [rbp + KTRAP_FRAME_PreviousIrql]
mov cr8, rax
+ /* Check for chained interrupts */
+ mov rax, [rbx + KINTERRUPT_InterruptListEntry]
+ cmp rax, rsi
+ je .Done
+
+ /* Load the next interrupt object into rbx and repeat */
+ lea rbx, [rax - KINTERRUPT_InterruptListEntry]
+ jmp .DoDispatchInterrupt
+
+.Done:
+ /* Restore rbx and rsi */
+ mov rbx, [rbp + KTRAP_FRAME_Rbx]
+ mov rsi, [rbp + KTRAP_FRAME_Rsi]
+
/* Return */
ExitTrap (TF_SAVE_ALL or TF_SEND_EOI)
ENDFUNC