xref: /reactos/ntoskrnl/ke/amd64/usercall_asm.S (revision 85fc290b)
1/*
2 * PROJECT:     ReactOS Kernel
3 * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE:     ReactOS AMD64 user mode callback helper
5 * COPYRIGHT:   Timo Kreuzer (timo.kreuzer@reactos.org)
6 */
7
8#include <ksamd64.inc>
9#include <trapamd64.inc>
10
11EXTERN KiInitiateUserApc:PROC
12EXTERN KeUserCallbackDispatcher:QWORD
13
14/*
15 * NTSTATUS
16 * KiUserModeCallout (
17 *     _Inout_ PKCALLOUT_FRAME CalloutFrame);
18 */
19EXTERN KiUserModeCallout:PROC
20
21.code64
22
23/*
24 * NTSTATUS
25 * KiCallUserMode (
26 *     _In_ PVOID *OutputBuffer@<rcx>,
27 *     _In_ PULONG OutputLength@<rdx>);
28 */
29PUBLIC KiCallUserMode
30.PROC KiCallUserMode
31
32    /* Generate a KEXCEPTION_FRAME on the stack */
33    /* This is identical to a KCALLOUT_FRAME */
34    GENERATE_EXCEPTION_FRAME
35
36    /* Save OutputBuffer and OutputLength */
37    mov [rsp + ExOutputBuffer], rcx
38    mov [rsp + ExOutputLength], rdx
39
40    /* Call the C function */
41    mov rcx, rsp
42    call KiUserModeCallout
43
44    /* Restore the registers from the KEXCEPTION_FRAME */
45    RESTORE_EXCEPTION_STATE
46
47    /* Return */
48    ret
49
50.ENDP
51
52
53/*!
54 * \brief Exits to user mode, restores only rsp and rip, zeroes the rest.
55 *
56 * \todo Merge this with KiCallUserMode + KiUserModeCallout and skip the trap frame.
57 *
58 * DECLSPEC_NORETURN
59 * VOID
60 * KiUserCallbackExit(
61 *     _In_ PKTRAP_FRAME TrapFrame@<rcx>);
62 */
63 PUBLIC KiUserCallbackExit
64KiUserCallbackExit:
65
66    /* Point rsp to the trap frame */
67    mov rsp, rcx
68
69    /* Zero non-volatile registers for KiUserCallbackDispatcher.
70       This must be done before dispatching a pending user APC. */
71    xor rbx, rbx
72    xor rdi, rdi
73    xor rsi, rsi
74    xor rbp, rbp
75    xor r12, r12
76    xor r13, r13
77    xor r14, r14
78    xor r15, r15
79    pxor xmm6, xmm6
80    pxor xmm7, xmm7
81    pxor xmm8, xmm8
82    pxor xmm9, xmm9
83    pxor xmm10, xmm10
84    pxor xmm11, xmm11
85    pxor xmm12, xmm12
86    pxor xmm13, xmm13
87    pxor xmm14, xmm14
88    pxor xmm15, xmm15
89
90    /* Check for pending user APC */
91    mov rdx, gs:[PcCurrentThread]
92    HANDLE_USER_APCS rdx, rsp
93
94    /* Zero volatile registers */
95    xor rax, rax
96    xor rdx, rdx
97    xor r8, r8
98    xor r9, r9
99    xor r10, r10
100    pxor xmm0, xmm0
101    pxor xmm1, xmm1
102    pxor xmm2, xmm2
103    pxor xmm3, xmm3
104    pxor xmm4, xmm4
105    pxor xmm5, xmm5
106
107    /* Disable interrupts for return */
108    cli
109
110    /* Prepare user mode return address (rcx) and eflags (r11) for sysret */
111    mov rcx, qword ptr KeUserCallbackDispatcher[rip]
112    mov r11, EFLAGS_IF_MASK
113
114    /* Load user mode stack (It was copied to the trap frame) */
115    mov rsp, [rsp + KTRAP_FRAME_Rsp]
116
117    /* Swap gs back to user */
118    swapgs
119
120    /* return to user mode */
121    sysretq
122
123
124/*
125 * DECLSPEC_NORETURN
126 * VOID
127 * KiCallbackReturn (
128 *     _In_ PVOID Stack,
129 *     _In_ NTSTATUS Status);
130 */
131PUBLIC KiCallbackReturn
132.PROC KiCallbackReturn
133
134    .ENDPROLOG
135
136    /* Restore the stack */
137    mov rsp, rcx
138
139    /* Set return status */
140    mov eax, edx
141
142    /* Restore the registers from the KEXCEPTION_FRAME */
143    RESTORE_EXCEPTION_STATE
144
145    /* Return */
146    ret
147
148.ENDP
149
150
151END
152