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

commit a016ccd1171ecaa39bc0f86edd451e32c716d2c7
Author:     Timo Kreuzer <[email protected]>
AuthorDate: Mon Feb 12 20:53:15 2018 +0100
Commit:     Timo Kreuzer <[email protected]>
CommitDate: Sat Oct 31 14:23:16 2020 +0100

    [NTOS:KE:X64][ASM:X64] Fix delivery of APCs
    
    - Deliver pending APCs on trap exit
    - Pass the trapframe of KiApcInterrupt to KiDeliverApcs, not NULL.
    - Fix parameter passing from KiSwapContext to KiSwapContextInternal and 
KiSwapContextResume, so that the ApcBypass parameter is not uninitialized
    - Fix return value of KiSwapContextResume to correctly indicate whether we 
want to have APCs directly delivered or not (when there are non, or when 
delivery is suppressed)
---
 ntoskrnl/ke/amd64/ctxswitch.S | 41 +++++++++++++++++++--------------------
 ntoskrnl/ke/amd64/thrdini.c   | 19 +++++++++---------
 ntoskrnl/ke/amd64/trap.S      | 45 ++++++++++++++++++++++++++++++++++++++++---
 sdk/include/asm/trapamd64.inc |  6 ++++--
 4 files changed, 76 insertions(+), 35 deletions(-)

diff --git a/ntoskrnl/ke/amd64/ctxswitch.S b/ntoskrnl/ke/amd64/ctxswitch.S
index a8346021e89..a88188e00d0 100644
--- a/ntoskrnl/ke/amd64/ctxswitch.S
+++ b/ntoskrnl/ke/amd64/ctxswitch.S
@@ -11,6 +11,11 @@
 
 #include <ksamd64.inc>
 
+; BOOLEAN
+; KiSwapContextResume(
+;    _In_ KIRQL WaitIrql,
+;    _In_ PKTHREAD OldThread,
+;    _In_ PKTHREAD NewThread)
 EXTERN KiSwapContextResume:PROC
 
 /* FUNCTIONS ****************************************************************/
@@ -118,23 +123,22 @@ PUBLIC KiThreadStartup
  * \brief
  *     The KiSwapContextInternal routine switches context to another thread.
  *
- * \param rcx
- *     Pointer to the KTHREAD to which the caller wishes to switch to.
+ * \param cl
+ *     The IRQL at wich the old thread is suspended
  *
  * \param rdx
  *     Pointer to the KTHREAD to which the caller wishes to switch from.
  *
- * \param r8b
- *     APC bypass
+ * \param r8
+ *     Pointer to the KTHREAD to which the caller wishes to switch to.
  *
  * \return
- *     None.
+ *     The WaitStatus of the Target Thread.
  *
  * \remarks
  *     ...
  *
  *--*/
-PUBLIC KiSwapContextInternal
 .PROC KiSwapContextInternal
 
     push rbp
@@ -143,22 +147,17 @@ PUBLIC KiSwapContextInternal
     .allocstack 6 * 8
     .endprolog
 
-    /* Save APC bypass */
-    mov [rsp + SwApcBypass], r8b
+    /* Save WaitIrql as KSWITCH_FRAME::ApcBypass */
+    mov [rsp + SwApcBypass], cl
 
     /* Save kernel stack of old thread */
     mov [rdx + KTHREAD_KernelStack], rsp
 
-    /* Save new thread in rbp */
-    mov rbp, rcx
-
-    //call KiSwapContextSuspend
-
     /* Load stack of new thread */
-    mov rsp, [rbp + KTHREAD_KernelStack]
+    mov rsp, [r8 + KTHREAD_KernelStack]
 
     /* Reload APC bypass */
-    mov r8b, [rsp + SwApcBypass]
+    mov cl, [rsp + SwApcBypass]
 
     call KiSwapContextResume
 
@@ -178,13 +177,13 @@ PUBLIC KiSwapContextInternal
  *     The KiSwapContext routine switches context to another thread.
  *
  * BOOLEAN
- * KiSwapContext(KIRQL WaitIrql, PKTHREAD CurrentThread);
+ * KiSwapContext(KIRQL WaitIrql, PKTHREAD OldThread);
  *
- * \param WaitIrql <rcx>
- *     ...
+ * \param WaitIrql <cl>
+ *     The IRQL at wich the old thread is suspended
  *
- * \param CurrentThread <rdx>
- *     Pointer to the KTHREAD of the current thread.
+ * \param OldThread <rdx>
+ *     Pointer to the KTHREAD of the previous thread.
  *
  * \return
  *     The WaitStatus of the Target Thread.
@@ -205,7 +204,7 @@ PUBLIC KiSwapContext
     GENERATE_EXCEPTION_FRAME
 
     /* Do the swap with the registers correctly setup */
-    mov rcx, gs:[PcCurrentThread] /* Pointer to the new thread */
+    mov r8, gs:[PcCurrentThread] /* Pointer to the new thread */
     call KiSwapContextInternal
 
     /* Restore the registers from the KEXCEPTION_FRAME */
diff --git a/ntoskrnl/ke/amd64/thrdini.c b/ntoskrnl/ke/amd64/thrdini.c
index c064d8aba16..6548a385651 100644
--- a/ntoskrnl/ke/amd64/thrdini.c
+++ b/ntoskrnl/ke/amd64/thrdini.c
@@ -137,9 +137,9 @@ KiInitializeContextThread(IN PKTHREAD Thread,
 
 BOOLEAN
 KiSwapContextResume(
-    IN PKTHREAD NewThread,
-    IN PKTHREAD OldThread,
-    IN BOOLEAN ApcBypass)
+    _In_ BOOLEAN ApcBypass,
+    _In_ PKTHREAD OldThread,
+    _In_ PKTHREAD NewThread)
 {
     PKIPCR Pcr = (PKIPCR)KeGetPcr();
     PKPROCESS OldProcess, NewProcess;
@@ -187,14 +187,15 @@ KiSwapContextResume(
     if (NewThread->ApcState.KernelApcPending)
     {
         /* Are APCs enabled? */
-        if (!NewThread->SpecialApcDisable)
+        if ((NewThread->SpecialApcDisable == 0) &&
+            (ApcBypass == 0))
         {
-            /* Request APC delivery */
-            if (!ApcBypass)
-                HalRequestSoftwareInterrupt(APC_LEVEL);
-            else
-                return TRUE;
+            /* Return TRUE to indicate that we want APCs to be delivered */
+            return TRUE;
         }
+
+        /* Request an APC interrupt to be delivered later */
+        HalRequestSoftwareInterrupt(APC_LEVEL);
     }
 
     /* Return stating that no kernel APCs are pending*/
diff --git a/ntoskrnl/ke/amd64/trap.S b/ntoskrnl/ke/amd64/trap.S
index 7dbe7a291f4..8efcd81d9d8 100644
--- a/ntoskrnl/ke/amd64/trap.S
+++ b/ntoskrnl/ke/amd64/trap.S
@@ -592,7 +592,7 @@ PUBLIC KiApcInterrupt
     mov cl, [rbp + KTRAP_FRAME_SegCs] // ProcessorMode
     and cl, 1
     mov rdx, 0                        // ExceptionFrame
-    mov r8, rdx                       // TrapFrame
+    mov r8, rbp                       // TrapFrame
     call KiDeliverApc
 
     /* Disable interrupts */
@@ -1000,8 +1000,47 @@ KiConvertToGuiThreadFailed:
 
 ENDFUNC
 
-KiExitToUserApc:
-    int 3
+;
+; VOID
+; KiDeliverApc(
+;     _In_ KPROCESSOR_MODE DeliveryMode,
+;     _In_ PKEXCEPTION_FRAME ExceptionFrame,
+;     _In_ PKTRAP_FRAME TrapFrame);
+;
+EXTERN KiDeliverApc:PROC
+
+PUBLIC KiInitiateUserApc
+.PROC KiInitiateUserApc
+
+    ; Generate a KEXCEPTION_FRAME on the stack
+    GENERATE_EXCEPTION_FRAME
+
+    ; Raise IRQL to APC_LEVEL
+    mov rax, APC_LEVEL
+    mov cr8, rax
+
+    ; Enable interrupts
+    sti
+
+    ; Get the current trap frame
+    mov rax, gs:[PcCurrentThread]
+    mov r8, [rax + KTHREAD_TrapFrame]
+
+    ; Call the C function
+    mov ecx, 1
+    mov rdx, rsp
+    call KiDeliverApc
+
+    ; Disable interrupts again
+    cli
+
+    ; Restore the registers from the KEXCEPTION_FRAME
+    RESTORE_EXCEPTION_STATE
+
+    ; Return
+    ret
+
+.ENDP
 
 
 PUBLIC KiInitializeSegments
diff --git a/sdk/include/asm/trapamd64.inc b/sdk/include/asm/trapamd64.inc
index f5ae982a380..4774fc09076 100644
--- a/sdk/include/asm/trapamd64.inc
+++ b/sdk/include/asm/trapamd64.inc
@@ -150,6 +150,7 @@ ENDM
 MACRO(ExitTrap, Flags)
     LOCAL kernel_mode_return
     LOCAL IntsEnabled
+    LOCAL NoUserApc
 
 #if DBG
         /* Check previous irql */
@@ -181,8 +182,9 @@ MACRO(ExitTrap, Flags)
         /* Load current thread into r10 */
         mov r10, gs:[PcCurrentThread]
         cmp byte ptr [r10 + KTHREAD_UserApcPending], 0
-        jne KiExitToUserApc
-
+        je NoUserApc
+        call KiInitiateUserApc
+    NoUserApc:
     endif
 
 #if DBG

Reply via email to