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 14; BOOLEAN 15; KiSwapContextResume( 16; _In_ KIRQL WaitIrql, 17; _In_ PKTHREAD OldThread, 18; _In_ PKTHREAD NewThread) 19EXTERN KiSwapContextResume:PROC 20 21/* FUNCTIONS ****************************************************************/ 22 23.code64 24 25/*! 26 * \name KiThreadStartup 27 * 28 * \brief 29 * The KiThreadStartup routine is the beginning of any thread. 30 * 31 * VOID 32 * KiThreadStartup( 33 * IN PKSTART_ROUTINE StartRoutine<rcx>, 34 * IN PVOID StartContext<rdx>, 35 * IN PVOID P3<r8>, 36 * IN PVOID P4<r9>, 37 * IN PVOID SystemRoutine); 38 * 39 * \param StartRoutine 40 * For Kernel Threads only, specifies the starting execution point 41 * of the new thread. 42 * 43 * \param StartContext 44 * For Kernel Threads only, specifies a pointer to variable 45 * context data to be sent to the StartRoutine above. 46 * 47 * \param P3, P4 - not used atm 48 * 49 * \param SystemRoutine 50 * Pointer to the System Startup Routine. 51 * Either PspUserThreadStartup or PspSystemThreadStartup 52 * 53 * \return 54 * Should never return for a system thread. Returns through the System Call 55 * Exit Dispatcher for a user thread. 56 * 57 * \remarks 58 * If a return from a system thread is detected, a bug check will occur. 59 * 60 *--*/ 61PUBLIC KiThreadStartup 62.PROC KiThreadStartup 63 /* KSTART_FRAME is already on the stack when we enter here. 64 * The virtual prolog looks like this: 65 * sub rsp, 5 * 8 66 * mov [rsp + SfP1Home], rcx 67 * mov [rsp + SfP2Home], rdx 68 * mov [rsp + SfP3Home], r8 69 * mov [rsp + SfP4Home], r9 70 */ 71 72 /* Terminate the unwind chain, by setting rbp as frame pointer, 73 which contains 0 */ 74 .setframe rbp, 0 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 /* The thread returned. If it was a user-thread, we have a return address 103 and all is well, otherwise this is very bad. */ 104 mov rcx, [rsp + SfReturn] 105 or rcx, rcx 106 jnz .leave 107 108 /* A system thread returned...this is very bad! */ 109 int 3 110 111.leave: 112 /* It was a user thread, set our trapframe for the System Call Exit Dispatcher */ 113 lea rcx, [rsp + 6 * 8 + KEXCEPTION_FRAME_LENGTH] 114 115 /* Return to the trap exit code */ 116 add rsp, 5 * 8 117 ret 118.ENDP 119 120/*! 121 * \name KiSwapContextInternal 122 * 123 * \brief 124 * The KiSwapContextInternal routine switches context to another thread. 125 * 126 * \param cl 127 * The IRQL at wich the old thread is suspended 128 * 129 * \param rdx 130 * Pointer to the KTHREAD to which the caller wishes to switch from. 131 * 132 * \param r8 133 * Pointer to the KTHREAD to which the caller wishes to switch to. 134 * 135 * \return 136 * The WaitStatus of the Target Thread. 137 * 138 * \remarks 139 * ... 140 * 141 *--*/ 142.PROC KiSwapContextInternal 143 144 push rbp 145 .pushreg rbp 146 sub rsp, 6 * 8 147 .allocstack 6 * 8 148 .endprolog 149 150 /* Save WaitIrql as KSWITCH_FRAME::ApcBypass */ 151 mov [rsp + SwApcBypass], cl 152 153 /* Save kernel stack of old thread */ 154 mov [rdx + KTHREAD_KernelStack], rsp 155 156 /* Load stack of new thread */ 157 mov rsp, [r8 + KTHREAD_KernelStack] 158 159 /* Reload APC bypass */ 160 mov cl, [rsp + SwApcBypass] 161 162 call KiSwapContextResume 163 164 /* Cleanup and return */ 165 add rsp, 6 * 8 166 pop rbp 167 ret 168 169.ENDP 170 171 172 173/*! 174 * KiSwapContext 175 * 176 * \brief 177 * The KiSwapContext routine switches context to another thread. 178 * 179 * BOOLEAN 180 * KiSwapContext(KIRQL WaitIrql, PKTHREAD OldThread); 181 * 182 * \param WaitIrql <cl> 183 * The IRQL at wich the old thread is suspended 184 * 185 * \param OldThread <rdx> 186 * Pointer to the KTHREAD of the previous thread. 187 * 188 * \return 189 * The WaitStatus of the Target Thread. 190 * 191 * \remarks 192 * This is a wrapper around KiSwapContextInternal which will save all the 193 * non-volatile registers so that the Internal function can use all of 194 * them. It will also save the old current thread and set the new one. 195 * 196 * The calling thread does not return after KiSwapContextInternal until 197 * another thread switches to IT. 198 * 199 *--*/ 200PUBLIC KiSwapContext 201.PROC KiSwapContext 202 203 /* Generate a KEXCEPTION_FRAME on the stack */ 204 GENERATE_EXCEPTION_FRAME 205 206 /* Do the swap with the registers correctly setup */ 207 mov r8, gs:[PcCurrentThread] /* Pointer to the new thread */ 208 call KiSwapContextInternal 209 210 /* Restore the registers from the KEXCEPTION_FRAME */ 211 RESTORE_EXCEPTION_STATE 212 213 /* Return */ 214 ret 215.ENDP 216 217END 218