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