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
7 * PROGRAMMER: Timo kreuzer (timo.kreuzer@reactos.org)
10 /* INCLUDES ******************************************************************/
13 #include <ksamd64.inc>
15 EXTERN KiSwapContextResume:PROC
17 /* FUNCTIONS ****************************************************************/
22 * \name KiThreadStartup
25 * The KiThreadStartup routine is the beginning of any thread.
29 * IN PKSTART_ROUTINE StartRoutine<rcx>,
30 * IN PVOID StartContext<rdx>,
33 * IN PVOID SystemRoutine);
36 * For Kernel Threads only, specifies the starting execution point
40 * For Kernel Threads only, specifies a pointer to variable
41 * context data to be sent to the StartRoutine above.
43 * \param P3, P4 - not used atm
45 * \param SystemRoutine
46 * Pointer to the System Startup Routine.
47 * Either PspUserThreadStartup or PspSystemThreadStartup
50 * Should never return for a system thread. Returns through the System Call
51 * Exit Dispatcher for a user thread.
54 * If a return from a system thread is detected, a bug check will occur.
57 PUBLIC KiThreadStartup
59 /* KSTART_FRAME is already on the stack when we enter here.
60 * The virtual prolog looks like this:
62 * mov [rsp + SfP1Home], rcx
63 * mov [rsp + SfP2Home], rdx
64 * mov [rsp + SfP3Home], r8
65 * mov [rsp + SfP4Home], r9
68 /* Terminate the unwind chain, by setting rbp as frame pointer,
73 /* Clear all the non-volatile registers, so the thread won't be tempted to
74 * expect any static data (like some badly coded usermode/win9x apps do) */
86 /* It's now safe to go to APC */
90 /* We have the KSTART_FRAME on the stack, P1Home and P2Home are preloaded
91 * with the parameters for the system routine. The address of the system
92 * routine is stored in P4Home. */
93 mov rcx, [rsp + SfP1Home] /* StartRoutine */
94 mov rdx, [rsp + SfP2Home] /* StartContext */
95 mov r8, [rsp + SfP3Home] /* ? */
96 call qword ptr [rsp + SfP4Home] /* SystemRoutine */
98 /* The thread returned. If it was a user-thread, we have a return address
99 and all is well, otherwise this is very bad. */
100 mov rcx, [rsp + SfReturn]
104 /* A system thread returned...this is very bad! */
108 /* It was a user thread, set our trapframe for the System Call Exit Dispatcher */
109 lea rcx, [rsp + 6 * 8 + KEXCEPTION_FRAME_LENGTH]
111 /* Return to the trap exit code */
117 * \name KiSwapContextInternal
120 * The KiSwapContextInternal routine switches context to another thread.
123 * Pointer to the KTHREAD to which the caller wishes to switch to.
126 * Pointer to the KTHREAD to which the caller wishes to switch from.
138 PUBLIC KiSwapContextInternal
139 .PROC KiSwapContextInternal
147 /* Save APC bypass */
148 mov [rsp + SwApcBypass], r8b
150 /* Save kernel stack of old thread */
151 mov [rdx + KTHREAD_KernelStack], rsp
153 /* Save new thread in rbp */
156 //call KiSwapContextSuspend
158 /* Load stack of new thread */
159 mov rsp, [rbp + KTHREAD_KernelStack]
161 /* Reload APC bypass */
162 mov r8b, [rsp + SwApcBypass]
164 call KiSwapContextResume
166 /* Cleanup and return */
179 * The KiSwapContext routine switches context to another thread.
182 * KiSwapContext(KIRQL WaitIrql, PKTHREAD CurrentThread);
184 * \param WaitIrql <rcx>
187 * \param CurrentThread <rdx>
188 * Pointer to the KTHREAD of the current thread.
191 * The WaitStatus of the Target Thread.
194 * This is a wrapper around KiSwapContextInternal which will save all the
195 * non-volatile registers so that the Internal function can use all of
196 * them. It will also save the old current thread and set the new one.
198 * The calling thread does not return after KiSwapContextInternal until
199 * another thread switches to IT.
205 /* Allocate a KEXCEPTION_FRAME on the stack (+8 for proper alignment) */
206 sub rsp, KEXCEPTION_FRAME_LENGTH + 8
207 .allocstack KEXCEPTION_FRAME_LENGTH + 8
209 /* save non-volatiles in KEXCEPTION_FRAME */
210 mov [rsp + KEXCEPTION_FRAME_Rbp], rbp
211 .savereg rbp, KEXCEPTION_FRAME_Rbp
212 mov [rsp + KEXCEPTION_FRAME_Rbx], rbx
213 .savereg rbx, KEXCEPTION_FRAME_Rbx
214 mov [rsp + KEXCEPTION_FRAME_Rdi], rdi
215 .savereg rdi, KEXCEPTION_FRAME_Rdi
216 mov [rsp + KEXCEPTION_FRAME_Rsi], rsi
217 .savereg rsi, KEXCEPTION_FRAME_Rsi
218 mov [rsp + KEXCEPTION_FRAME_R12], r12
219 .savereg r12, KEXCEPTION_FRAME_R12
220 mov [rsp + KEXCEPTION_FRAME_R13], r13
221 .savereg r13, KEXCEPTION_FRAME_R13
222 mov [rsp + KEXCEPTION_FRAME_R14], r14
223 .savereg r14, KEXCEPTION_FRAME_R14
224 mov [rsp + KEXCEPTION_FRAME_R15], r15
225 .savereg r15, KEXCEPTION_FRAME_R15
226 movdqa [rsp + KEXCEPTION_FRAME_Xmm6], xmm6
227 movdqa [rsp + KEXCEPTION_FRAME_Xmm7], xmm7
228 movdqa [rsp + KEXCEPTION_FRAME_Xmm8], xmm8
229 movdqa [rsp + KEXCEPTION_FRAME_Xmm9], xmm9
230 movdqa [rsp + KEXCEPTION_FRAME_Xmm10], xmm10
231 movdqa [rsp + KEXCEPTION_FRAME_Xmm11], xmm11
232 movdqa [rsp + KEXCEPTION_FRAME_Xmm12], xmm12
233 movdqa [rsp + KEXCEPTION_FRAME_Xmm13], xmm13
234 movdqa [rsp + KEXCEPTION_FRAME_Xmm14], xmm14
235 movdqa [rsp + KEXCEPTION_FRAME_Xmm15], xmm15
236 // KEXCEPTION_FRAME_MxCsr
239 /* Do the swap with the registers correctly setup */
240 mov rcx, gs:[PcCurrentThread] /* Pointer to the new thread */
241 call KiSwapContextInternal
243 /* restore non-volatile registers */
244 mov rbp, [rsp + KEXCEPTION_FRAME_Rbp]
245 mov rbx, [rsp + KEXCEPTION_FRAME_Rbx]
246 mov rdi, [rsp + KEXCEPTION_FRAME_Rdi]
247 mov rsi, [rsp + KEXCEPTION_FRAME_Rsi]
248 mov r12, [rsp + KEXCEPTION_FRAME_R12]
249 mov r13, [rsp + KEXCEPTION_FRAME_R13]
250 mov r14, [rsp + KEXCEPTION_FRAME_R14]
251 mov r15, [rsp + KEXCEPTION_FRAME_R15]
252 movdqa xmm6, [rsp + KEXCEPTION_FRAME_Xmm6]
253 movdqa xmm7, [rsp + KEXCEPTION_FRAME_Xmm7]
254 movdqa xmm8, [rsp + KEXCEPTION_FRAME_Xmm8]
255 movdqa xmm9, [rsp + KEXCEPTION_FRAME_Xmm9]
256 movdqa xmm10, [rsp + KEXCEPTION_FRAME_Xmm10]
257 movdqa xmm11, [rsp + KEXCEPTION_FRAME_Xmm11]
258 movdqa xmm12, [rsp + KEXCEPTION_FRAME_Xmm12]
259 movdqa xmm13, [rsp + KEXCEPTION_FRAME_Xmm13]
260 movdqa xmm14, [rsp + KEXCEPTION_FRAME_Xmm14]
261 movdqa xmm15, [rsp + KEXCEPTION_FRAME_Xmm15]
263 /* Clean stack and return */
264 add rsp, KEXCEPTION_FRAME_LENGTH + 8