diff --git a/ntoskrnl/ke/amd64/trap.S b/ntoskrnl/ke/amd64/trap.S index 88679949b17..79b58559129 100644 --- a/ntoskrnl/ke/amd64/trap.S +++ b/ntoskrnl/ke/amd64/trap.S @@ -850,12 +850,9 @@ GLOBAL_LABEL KiSystemServiceExit ASSERT_TRAP_FRAME_INTS_ENABLED rsp + MAX_SYSCALL_PARAM_SIZE - /* Check for pending user APC */ - mov rcx, gs:qword ptr [PcCurrentThread] - cmp byte ptr [rcx + ThApcState + AsUserApcPending], 0 - jz no_user_apc_pending - call KiInitiateUserApc -no_user_apc_pending: + /* Check for pending user APCs */ + mov rcx, gs:[PcCurrentThread] + HANDLE_USER_APCS rcx, rsp + MAX_SYSCALL_PARAM_SIZE /* Disable interrupts for return */ cli @@ -1137,12 +1134,23 @@ PUBLIC KiSetTrapContext */ EXTERN KiDeliverApc:PROC +/* + * VOID + * KiInitiateUserApc( + * _In_ PKTRAP_FRAME TrapFrame@); + * + * This function is called to deliver user mode APCs. + * It clobbers all non-volatile registers, except rax. + */ PUBLIC KiInitiateUserApc .PROC KiInitiateUserApc /* Generate a KEXCEPTION_FRAME on the stack */ GENERATE_EXCEPTION_FRAME + /* Save rax to not clobber the return for the system call handler */ + mov [rsp + ExP1Home], rax + /* Raise IRQL to APC_LEVEL */ mov rax, APC_LEVEL mov cr8, rax @@ -1150,6 +1158,9 @@ PUBLIC KiInitiateUserApc /* Get the current thread */ mov rbp, gs:[PcCurrentThread] + /* Save the trap frame in rsi */ + mov rsi, rcx + deliver_apcs: /* Enable interrupts */ @@ -1158,7 +1169,7 @@ deliver_apcs: /* Call the C function */ mov ecx, 1 mov rdx, rsp - mov r8, [rbp + ThTrapFrame] + mov r8, rsi call KiDeliverApc /* Disable interrupts again */ @@ -1173,6 +1184,7 @@ deliver_apcs: mov cr8, rax /* Restore the registers from the KEXCEPTION_FRAME */ + mov rax, [rsp + ExP1Home] RESTORE_EXCEPTION_STATE /* Return */ diff --git a/sdk/include/asm/trapamd64.inc b/sdk/include/asm/trapamd64.inc index 5303adf2dbb..0c09063f058 100644 --- a/sdk/include/asm/trapamd64.inc +++ b/sdk/include/asm/trapamd64.inc @@ -37,6 +37,19 @@ IrqlIsPassive: #endif ENDM +// Checks for user APCs and delivers them if necessary. +// Clobbers all volatile registers except rax. +MACRO(HANDLE_USER_APCS, ThreadReg, TrapFrame) + LOCAL NoUserApcPending + + /* Check for pending user APC */ + cmp byte ptr [ThreadReg + ThApcState + AsUserApcPending], 0 + jz NoUserApcPending + lea rcx, [TrapFrame] + call KiInitiateUserApc +NoUserApcPending: +ENDM + APIC_EOI = HEX(0FFFFFFFFFFFE00B0) TF_VOLATILES = HEX(01) @@ -195,7 +208,6 @@ ENDM */ MACRO(ExitTrap, Flags) LOCAL kernel_mode_return - LOCAL NoUserApc ASSERT_TRAP_FRAME_IRQL_VALID rbp @@ -217,12 +229,8 @@ MACRO(ExitTrap, Flags) jz kernel_mode_return if (Flags AND TF_CHECKUSERAPC) - /* Load current thread into r10 */ mov r10, gs:[PcCurrentThread] - cmp byte ptr [r10 + KTHREAD_UserApcPending], 0 - je NoUserApc - call KiInitiateUserApc - NoUserApc: + HANDLE_USER_APCS r10, rbp endif ASSERT_TRAP_FRAME_INTS_ENABLED rbp