From 7f2e0ece5a4e408f509299a7efe1aec72a471432 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Fri, 9 Mar 2018 23:55:54 +0100 Subject: [PATCH] [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