Initial revision
[reactos.git] / msvc6 / ntoskrnl / ke_i386_v86m_sup.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2000 David Welch <welch@cwcom.net>
4 *
5 * Moved to MSVC-compatible inline assembler by Mike Nordell, 2003-12-25
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 /*
22 * FILE: ntoskrnl/ke/i386/vm86_sup.S
23 * PURPOSE: V86 mode support
24 * PROGRAMMER: David Welch (welch@cwcom.net)
25 * UPDATE HISTORY:
26 * Created 09/10/00
27 */
28
29 /* INCLUDES ******************************************************************/
30
31 #pragma hdrstop
32
33 #include <ddk/ntddk.h>
34 #include <ddk/status.h>
35 #include <internal/i386/segment.h>
36 #include <internal/i386/fpu.h>
37 #include <internal/ps.h>
38 #include <ddk/defines.h>
39 #include <internal/v86m.h>
40 #include <ntos/tss.h>
41 #include <internal/trap.h>
42 #include <internal/ps.h>
43
44 #include <roscfg.h>
45 #include <internal/ntoskrnl.h>
46 #include <internal/i386/segment.h>
47 #include <internal/ps.h>
48
49
50 // Taken from ntoskrnl/include/internal/v86m.h, since that one must be fixed
51 // a bit before it could be used from here.
52 #define KV86M_REGISTERS_EBP (0x0)
53 #define KV86M_REGISTERS_EDI (0x4)
54 #define KV86M_REGISTERS_ESI (0x8)
55 #define KV86M_REGISTERS_EDX (0xC)
56 #define KV86M_REGISTERS_ECX (0x10)
57 #define KV86M_REGISTERS_EBX (0x14)
58 #define KV86M_REGISTERS_EAX (0x18)
59 #define KV86M_REGISTERS_DS (0x1C)
60 #define KV86M_REGISTERS_ES (0x20)
61 #define KV86M_REGISTERS_FS (0x24)
62 #define KV86M_REGISTERS_GS (0x28)
63 #define KV86M_REGISTERS_EIP (0x2C)
64 #define KV86M_REGISTERS_CS (0x30)
65 #define KV86M_REGISTERS_EFLAGS (0x34)
66 #define KV86M_REGISTERS_ESP (0x38)
67 #define KV86M_REGISTERS_SS (0x3C)
68
69
70 void KiV86Complete();
71
72
73 /*
74 * Starts in v86 mode with the registers set to the
75 * specified values.
76 */
77
78 __declspec(naked)
79 VOID Ki386RetToV86Mode(KV86M_REGISTERS* InRegs,
80 KV86M_REGISTERS* OutRegs)
81 {
82 __asm
83 {
84 /*
85 * Setup a stack frame
86 */
87 push ebp
88 mov ebp, esp
89
90 pushad /* Save registers */
91
92 mov ebx, InRegs
93
94 /*
95 * Save ebp
96 */
97 push ebp
98
99 /*
100 * Save a pointer to IN_REGS which the v86m exception handler will
101 * use to handle exceptions
102 */
103 push ebx
104
105 /*
106 * Since we are going to fiddle with the stack pointer this must be
107 * a critical section for this processor
108 */
109
110 /*
111 * Save the old initial stack
112 */
113 mov esi, fs:KPCR_CURRENT_THREAD
114 mov edi, KTHREAD_INITIAL_STACK[esi]
115 push edi
116
117 /*
118 * We also need to set the stack in the kthread structure
119 */
120 mov KTHREAD_INITIAL_STACK[esi], esp
121
122 /*
123 * The stack used for handling exceptions from v86 mode in this thread
124 * will be the current stack adjusted so we don't overwrite the
125 * existing stack frames
126 */
127 mov esi, fs:KPCR_TSS
128 mov KTSS_ESP0[esi], esp
129
130 /*
131 * Create the stack frame for an iret to v86 mode
132 */
133 push KV86M_REGISTERS_GS[ebx]
134 push KV86M_REGISTERS_FS[ebx]
135 push KV86M_REGISTERS_DS[ebx]
136 push KV86M_REGISTERS_ES[ebx]
137 push KV86M_REGISTERS_SS[ebx]
138 push KV86M_REGISTERS_ESP[ebx]
139 push KV86M_REGISTERS_EFLAGS[ebx]
140 push KV86M_REGISTERS_CS[ebx]
141 push KV86M_REGISTERS_EIP[ebx]
142
143 /*
144 * Setup the CPU registers
145 */
146 mov eax, KV86M_REGISTERS_EAX[ebx]
147 mov ecx, KV86M_REGISTERS_ECX[ebx]
148 mov edx, KV86M_REGISTERS_EDX[ebx]
149 mov esi, KV86M_REGISTERS_ESI[ebx]
150 mov edi, KV86M_REGISTERS_EDI[ebx]
151 mov ebp, KV86M_REGISTERS_EBP[ebx]
152 mov ebx, KV86M_REGISTERS_EBX[ebx]
153
154 /*
155 * Go to v86 mode
156 */
157 iretd
158
159 /*
160 * Handle the completion of a vm86 routine. We are called from
161 * an exception handler with the registers at the point of the
162 * exception on the stack.
163 */
164
165 jmp KiV86Complete // TMN: Function-splitting
166 }
167 }
168
169 __declspec(naked)
170 void KiV86Complete()
171 {
172 __asm
173 {
174 /* Restore the original ebp */
175 mov ebp, TF_ORIG_EBP[esp]
176
177 /* Get a pointer to the OUT_REGS structure */
178 mov ebx, 12[ebp] // OutRegs
179
180 /* Skip debug information and unsaved registers */
181 add esp, 0x30
182
183 /* Ignore 32-bit segment registers */
184 add esp, 12
185
186 /* Save the vm86 registers into the OUT_REGS structure */
187 pop dword ptr KV86M_REGISTERS_EDX[ebx]
188 pop dword ptr KV86M_REGISTERS_ECX[ebx]
189 pop dword ptr KV86M_REGISTERS_EAX[ebx]
190
191 /* Restore the old previous mode */
192 pop eax
193 mov ss:KTHREAD_PREVIOUS_MODE[esi], al
194
195 /* Restore the old exception handler list */
196 pop eax
197 mov fs:KPCR_EXCEPTION_LIST, eax
198
199 /* Ignore the 32-bit fs register */
200 add esp, 4
201
202 pop dword ptr KV86M_REGISTERS_EDI[ebx]
203 pop dword ptr KV86M_REGISTERS_ESI[ebx]
204 pop dword ptr KV86M_REGISTERS_EBX[ebx]
205 pop dword ptr KV86M_REGISTERS_EBP[ebx]
206
207 /* Ignore error code */
208 add esp, 4
209
210 pop dword ptr KV86M_REGISTERS_EIP[ebx]
211 pop dword ptr KV86M_REGISTERS_CS[ebx]
212 pop dword ptr KV86M_REGISTERS_EFLAGS[ebx]
213 pop dword ptr KV86M_REGISTERS_ESP[ebx]
214 pop dword ptr KV86M_REGISTERS_SS[ebx]
215 pop dword ptr KV86M_REGISTERS_ES[ebx]
216 pop dword ptr KV86M_REGISTERS_DS[ebx]
217 pop dword ptr KV86M_REGISTERS_FS[ebx]
218 pop dword ptr KV86M_REGISTERS_GS[ebx]
219
220 /*
221 * We are going to fiddle with the stack so this must be a critical
222 * section for this process
223 */
224 cli
225
226 /*
227 * Restore the initial stack
228 */
229 pop eax
230 mov esi, fs:KPCR_TSS
231 mov KTSS_ESP0[esi], eax
232
233 /*
234 * We also need to set the stack in the kthread structure
235 */
236 mov esi, fs:KPCR_CURRENT_THREAD
237 mov edi, KTHREAD_INITIAL_STACK[esi]
238 mov KTHREAD_INITIAL_STACK[esi], eax
239
240 /* Exit the critical section */
241 sti
242
243 /* Ignore IN_REGS pointer */
244 add esp, 4
245
246 /* Ignore ebp restored above */
247 add esp, 4
248
249 /* Return to caller */
250 popad
251 mov esp, ebp
252 pop ebp
253 ret
254
255 } // end of __asm block
256 }