xref: /reactos/ntoskrnl/ke/i386/ctxswitch.S (revision 84344399)
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