xref: /reactos/ntoskrnl/ke/amd64/ctxswitch.S (revision e5993f13)
1/*
2 * COPYRIGHT:       See COPYING in the top level directory
3 * PROJECT:         ReactOS kernel
4 * FILE:            ntoskrnl/ke/amd64/ctxswitch.S
5 * PURPOSE:         Thread Context Switching
6 *
7 * PROGRAMMER:      Timo kreuzer (timo.kreuzer@reactos.org)
8 */
9
10/* INCLUDES ******************************************************************/
11
12#include <ksamd64.inc>
13#include <trapamd64.inc>
14
15/*
16 * BOOLEAN
17 * KiSwapContextResume(
18 *    _In_ KIRQL WaitIrql,
19 *    _In_ PKTHREAD OldThread,
20 *    _In_ PKTHREAD NewThread)
21 */
22EXTERN KiSwapContextResume:PROC
23
24/* FUNCTIONS ****************************************************************/
25
26.code64
27
28/*!
29 * \name KiThreadStartup
30 *
31 * \brief
32 *     The KiThreadStartup routine is the beginning of any thread.
33 *
34 * VOID
35 * KiThreadStartup(
36 *     IN PKSTART_ROUTINE StartRoutine<rcx>,
37 *     IN PVOID StartContext<rdx>,
38 *     IN PVOID P3<r8>,
39 *     IN PVOID P4<r9>,
40 *     IN PVOID SystemRoutine);
41 *
42 * \param StartRoutine
43 *     For Kernel Threads only, specifies the starting execution point
44 *     of the new thread.
45 *
46 * \param StartContext
47 *     For Kernel Threads only, specifies a pointer to variable
48 *     context data to be sent to the StartRoutine above.
49 *
50 * \param P3, P4 - not used atm
51 *
52 * \param SystemRoutine
53 *     Pointer to the System Startup Routine.
54 *     Either PspUserThreadStartup or PspSystemThreadStartup
55 *
56 * \return
57 *     Should never return for a system thread. Returns through the System Call
58 *     Exit Dispatcher for a user thread.
59 *
60 * \remarks
61 *     If a return from a system thread is detected, a bug check will occur.
62 *
63 *--*/
64PUBLIC KiThreadStartup
65.PROC KiThreadStartup
66    /* KSTART_FRAME is already on the stack when we enter here.
67     * The virtual prolog looks like this:
68     * sub rsp, 5 * 8
69     * mov [rsp + SfP1Home], rcx
70     * mov [rsp + SfP2Home], rdx
71     * mov [rsp + SfP3Home], r8
72     * mov [rsp + SfP4Home], r9
73     */
74    .allocstack (5 * 8)
75    .endprolog
76
77    /* Clear all the non-volatile registers, so the thread won't be tempted to
78     * expect any static data (like some badly coded usermode/win9x apps do) */
79    xor rbx, rbx
80    xor rsi, rsi
81    xor rdi, rdi
82    xor rbp, rbp
83    xor r10, r10
84    xor r11, r11
85    xor r12, r12
86    xor r13, r13
87    xor r14, r14
88    xor r15, r15
89
90    /* It's now safe to go to APC */
91    mov rax, APC_LEVEL
92    mov cr8, rax
93
94    /* We have the KSTART_FRAME on the stack, P1Home and P2Home are preloaded
95     * with the parameters for the system routine. The address of the system
96     * routine is stored in P4Home. */
97    mov rcx, [rsp + SfP1Home] /* StartRoutine */
98    mov rdx, [rsp + SfP2Home] /* StartContext */
99    mov r8, [rsp + SfP3Home]  /* ? */
100    call qword ptr [rsp + SfP4Home]     /* SystemRoutine */
101
102    /* Return to the exit code */
103    add rsp, 5 * 8
104    ret
105.ENDP
106
107PUBLIC KiInvalidSystemThreadStartupExit
108.PROC KiInvalidSystemThreadStartupExit
109    .endprolog
110
111    /* This is invalid! */
112    int HEX(2C)
113    nop
114.ENDP
115
116PUBLIC KiUserThreadStartupExit
117.PROC KiUserThreadStartupExit
118    .allocstack (KEXCEPTION_FRAME_LENGTH - 8)
119    .savereg rbp, ExRbp
120    .savereg rbx, ExRbx
121    .savereg rdi, ExRdi
122    .savereg rsi, ExRsi
123    .savereg r12, ExR12
124    .savereg r13, ExR13
125    .savereg r14, ExR14
126    .savereg r15, ExR15
127    .savexmm128 xmm6, ExXmm6
128    .savexmm128 xmm7, ExXmm7
129    .savexmm128 xmm8, ExXmm8
130    .savexmm128 xmm9, ExXmm9
131    .savexmm128 xmm10, ExXmm10
132    .savexmm128 xmm11, ExXmm11
133    .savexmm128 xmm12, ExXmm12
134    .savexmm128 xmm13, ExXmm13
135    .savexmm128 xmm14, ExXmm14
136    .savexmm128 xmm15, ExXmm15
137    .endprolog
138
139    /* Restore the exception frame */
140    RESTORE_EXCEPTION_STATE
141
142    /* Point rcx to the trap frame */
143    lea rcx, [rsp + 8]
144
145    /* Return to the trap exit code */
146    ret
147.ENDP
148
149/*!
150 * \name KiSwapContextInternal
151 *
152 * \brief
153 *     The KiSwapContextInternal routine switches context to another thread.
154 *
155 * \param cl
156 *     The IRQL at wich the old thread is suspended
157 *
158 * \param rdx
159 *     Pointer to the KTHREAD to which the caller wishes to switch from.
160 *
161 * \param r8
162 *     Pointer to the KTHREAD to which the caller wishes to switch to.
163 *
164 * \return
165 *     The WaitStatus of the Target Thread.
166 *
167 * \remarks
168 *     ...
169 *
170 *--*/
171.PROC KiSwapContextInternal
172
173    push rbp
174    .pushreg rbp
175    sub rsp, 6 * 8
176    .allocstack (6 * 8)
177    .endprolog
178
179    /* Wait for SwapBusy */
180.SwapBusySet:
181    cmp byte ptr [r8 + ThSwapBusy], 0
182    je .SwapBusyClear
183    pause
184    jmp .SwapBusySet
185.SwapBusyClear:
186
187    /* Save WaitIrql as KSWITCH_FRAME::ApcBypass */
188    mov [rsp + SwApcBypass], cl
189
190    /* Save kernel stack of old thread */
191    mov [rdx + KTHREAD_KernelStack], rsp
192
193    /* Load stack of new thread */
194    mov rsp, [r8 + KTHREAD_KernelStack]
195
196    /* Reload APC bypass */
197    mov cl, [rsp + SwApcBypass]
198
199    call KiSwapContextResume
200
201    /* Cleanup and return */
202    add rsp, 6 * 8
203    pop rbp
204    ret
205
206.ENDP
207
208
209
210/*!
211 * KiSwapContext
212 *
213 * \brief
214 *     The KiSwapContext routine switches context to another thread.
215 *
216 * BOOLEAN
217 * KiSwapContext(KIRQL WaitIrql, PKTHREAD OldThread);
218 *
219 * \param WaitIrql <cl>
220 *     The IRQL at wich the old thread is suspended
221 *
222 * \param OldThread <rdx>
223 *     Pointer to the KTHREAD of the previous thread.
224 *
225 * \return
226 *     The WaitStatus of the Target Thread.
227 *
228 * \remarks
229 *     This is a wrapper around KiSwapContextInternal which will save all the
230 *     non-volatile registers so that the Internal function can use all of
231 *     them. It will also save the old current thread and set the new one.
232 *
233 *     The calling thread does not return after KiSwapContextInternal until
234 *     another thread switches to IT.
235 *
236 *--*/
237PUBLIC KiSwapContext
238.PROC KiSwapContext
239
240    /* Generate a KEXCEPTION_FRAME on the stack */
241    GENERATE_EXCEPTION_FRAME
242
243    /* Do the swap with the registers correctly setup */
244    mov r8, gs:[PcCurrentThread] /* Pointer to the new thread */
245    call KiSwapContextInternal
246
247    /* Restore the registers from the KEXCEPTION_FRAME */
248    RESTORE_EXCEPTION_STATE
249
250    /* Return */
251    ret
252.ENDP
253
254END
255