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