1/* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * FILE: ntoskrnl/ke/i386/ctxswitch.S 5 * PURPOSE: Thread Context Switching 6 * 7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 8 * Gregor Anich (FPU Code) 9 */ 10 11/* INCLUDES ******************************************************************/ 12 13#include <asm.inc> 14#include <ks386.inc> 15 16EXTERN @KiSwapContextEntry@8:PROC 17EXTERN @KiSwapContextExit@8:PROC 18EXTERN @KiRetireDpcList@4:PROC 19EXTERN @KiEnterV86Mode@4:PROC 20EXTERN @KiExitV86Mode@4:PROC 21EXTERN _KeI386FxsrPresent:DWORD 22 23/* FUNCTIONS ****************************************************************/ 24.code 25 26/*++ 27 * KiSwapContextInternal 28 * 29 * \brief 30 * The KiSwapContextInternal routine switches context to another thread. 31 * 32 * BOOLEAN USERCALL KiSwapContextInternal(ULONG_PTR OldThreadAndApcFlag@<edx>); 33 * 34 * \param OldThreadAndApcFlag@<edx> 35 * Pointer to the current thread with the lowest bit set to the current IRQL. 36 * 37 * \returns 38 * APC state. 39 * 40 * \remarks 41 * Absolutely all registers except ESP can be trampled here for maximum code flexibility. 42 * 43 *--*/ 44PUBLIC @KiSwapContextInternal@0 45@KiSwapContextInternal@0: 46 /* Build switch frame */ 47 sub esp, 2 * 4 48 mov ecx, esp 49 jmp @KiSwapContextEntry@8 50 51 52/** 53 * KiSwapContext 54 * 55 * \brief 56 * The KiSwapContext routine switches context to another thread. 57 * 58 * BOOLEAN FASTCALL 59 * KiSwapContext(KIRQL WaitIrql@<cl>, PKTHREAD CurrentThread@<edx>); 60 * 61 * \param WaitIrql@<cl> 62 * The IRQL at which the wait happens. 63 * 64 * \param CurrentThread@<edx> 65 * Pointer to the KTHREAD of the current thread. 66 * 67 * \returns 68 * The WaitStatus of the Target Thread. 69 * 70 * \remarks 71 * This is a wrapper around KiSwapContextInternal which will save all the 72 * non-volatile registers so that the Internal function can use all of 73 * them. It will also save the old current thread and set the new one. 74 * 75 * The calling thread does not return after KiSwapContextInternal until 76 * another thread switches to IT. 77 * 78 *--*/ 79PUBLIC @KiSwapContext@8 80@KiSwapContext@8: 81 /* Save 4 registers */ 82 sub esp, 4 * 4 83 84 /* Save all the non-volatile ones */ 85 mov [esp+12], ebx 86 mov [esp+8], esi 87 mov [esp+4], edi 88 mov [esp+0], ebp 89 90 /* Combine current thread and the wait IRQL in edx */ 91 or dl, cl 92 93 /* Do the swap with the registers correctly setup */ 94 call @KiSwapContextInternal@0 95 96 /* Restore the registers */ 97 mov ebp, [esp+0] 98 mov edi, [esp+4] 99 mov esi, [esp+8] 100 mov ebx, [esp+12] 101 102 /* Clean stack */ 103 add esp, 4 * 4 104 ret 105 106 107PUBLIC @KiSwitchThreads@8 108@KiSwitchThreads@8: 109 /* Load the new kernel stack and switch OS to new thread */ 110 mov esp, edx 111#if DBG 112 /* Restore the frame pointer early to get sensible backtraces */ 113 mov ebp, [esp+12] 114#endif 115 call @KiSwapContextExit@8 116 117 /* Now we're on the new thread. Return to the caller to restore registers */ 118 add esp, 2 * 4 119 ret 120 121 122PUBLIC @KiRetireDpcListInDpcStack@8 123@KiRetireDpcListInDpcStack@8: 124 /* Switch stacks and retire DPCs */ 125 mov eax, esp 126 mov esp, edx 127 push eax 128 call @KiRetireDpcList@4 129 130 /* Return on original stack */ 131 pop esp 132 ret 133 134PUBLIC _Ki386EnableCurrentLargePage@8 135_Ki386EnableCurrentLargePage@8: 136 /* Save StartAddress in eax */ 137 mov eax, [esp + 4] 138 139 /* Save new CR3 value in ecx */ 140 mov ecx, [esp + 8] 141 142 /* Save flags value */ 143 pushfd 144 145 /* Disable interrupts */ 146 cli 147 148 /* Compute linear address */ 149 sub eax, offset _Ki386EnableCurrentLargePage@8 150 add eax, offset _Ki386LargePageIdentityLabel 151 152 /* Save old CR3 in edx and replace with a new one */ 153 mov edx, cr3 154 mov cr3, ecx 155 156 /* Jump to the next instruction but in linear mapping */ 157 jmp eax 158 159_Ki386LargePageIdentityLabel: 160 /* Disable paging */ 161 mov eax, cr0 162 and eax, NOT CR0_PG 163 mov cr0, eax 164 165 /* Jump to the next instruction to clear the prefetch queue */ 166 jmp $+2 167 168 /* Enable Page Size Extension in CR4 */ 169 mov ecx, cr4 170 or ecx, CR4_PSE 171 mov cr4, ecx 172 173 /* Done, now re-enable paging */ 174 or eax, CR0_PG 175 mov cr0, eax 176 177 /* Jump to virtual address */ 178 mov eax, offset VirtualSpace 179 jmp eax 180 181VirtualSpace: 182 /* Restore CR3 contents */ 183 mov cr3, edx 184 185 /* Restore flags */ 186 popfd 187 188 ret 8 189 190/* FIXFIX: Move to C code ****/ 191PUBLIC _Ki386SetupAndExitToV86Mode@4 192_Ki386SetupAndExitToV86Mode@4: 193 194 /* Enter V8086 mode */ 195 pushad 196 sub esp, (12 + KTRAP_FRAME_LENGTH + NPX_FRAME_LENGTH + 16) 197 mov ecx, esp 198 call @KiEnterV86Mode@4 199 jmp $ 200 201 202PUBLIC @Ki386BiosCallReturnAddress@4 203@Ki386BiosCallReturnAddress@4: 204 205 /* Exit V8086 mode */ 206 call @KiExitV86Mode@4 207 mov esp, eax 208 add esp, (12 + KTRAP_FRAME_LENGTH + NPX_FRAME_LENGTH + 16) 209 popad 210 ret 4 211 212PUBLIC _FrRestore 213PUBLIC @Ke386LoadFpuState@4 214@Ke386LoadFpuState@4: 215 216 /* Check if we have FXSR and choose which operand to use */ 217 test byte ptr [_KeI386FxsrPresent], 1 218 jz _FrRestore 219 220 /* Restore all the FPU, MMX, XMM and MXCSR registers */ 221 fxrstor [ecx] 222 ret 223 224 /* 225 * Just restore the basic FPU registers. 226 * This may raise an exception depending 227 * on the status word, which KiNpxHandler will 228 * need to check for and handle during delayed load 229 * to avoid raising an unhandled exception 230 * and crashing the system. 231 */ 232_FrRestore: 233 frstor [ecx] 234 ret 235 236END 237