Skip to content

Commit

Permalink
[NTOS:KE/x64][SDK] Add HANDLE_USER_APCS asm macro
Browse files Browse the repository at this point in the history
This also fixes delivering APCs from the system call handler, which previously would have clobbered rax. Also don't use the thread's TrapFrame member, which is not always set, when returning.
  • Loading branch information
tkreuzer committed Apr 1, 2024
1 parent 88e24bc commit 24b4026
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 13 deletions.
26 changes: 19 additions & 7 deletions ntoskrnl/ke/amd64/trap.S
Expand Up @@ -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
Expand Down Expand Up @@ -1137,19 +1134,33 @@ PUBLIC KiSetTrapContext
*/
EXTERN KiDeliverApc:PROC

/*
* VOID
* KiInitiateUserApc(
* _In_ PKTRAP_FRAME TrapFrame@<rcx>);
*
* 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

/* Get the current thread */
mov rbp, gs:[PcCurrentThread]

/* Save the trap frame in rsi */
mov rsi, rcx

deliver_apcs:

/* Enable interrupts */
Expand All @@ -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 */
Expand All @@ -1173,6 +1184,7 @@ deliver_apcs:
mov cr8, rax

/* Restore the registers from the KEXCEPTION_FRAME */
mov rax, [rsp + ExP1Home]
RESTORE_EXCEPTION_STATE

/* Return */
Expand Down
20 changes: 14 additions & 6 deletions sdk/include/asm/trapamd64.inc
Expand Up @@ -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)
Expand Down Expand Up @@ -195,7 +208,6 @@ ENDM
*/
MACRO(ExitTrap, Flags)
LOCAL kernel_mode_return
LOCAL NoUserApc

ASSERT_TRAP_FRAME_IRQL_VALID rbp

Expand All @@ -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
Expand Down

0 comments on commit 24b4026

Please sign in to comment.