Initial revision
[reactos.git] / msvc6 / ntoskrnl / ke_i386_syscall.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2000 David Welch <welch@cwcom.net>
4 *
5 * Converted to MSVC-compatible inline assembler by Mike Nordell, 2003.
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: MSVC6/ntoskrnl/ke_i386_syscall.c
23 * based on ntoskrnl/ke/i386/syscall.s
24 * PURPOSE: syscall dispatching and support
25 * PROGRAMMER: David Welch (welch@cwcom.net)
26 * UPDATE HISTORY:
27 * Created 09/10/00
28 */
29
30 /* INCLUDES ******************************************************************/
31
32 #pragma hdrstop
33
34 #include <ddk/ntddk.h>
35 #include <ddk/status.h>
36 #include <internal/i386/segment.h>
37 #include <internal/i386/fpu.h>
38 #include <internal/ps.h>
39 #include <ddk/defines.h>
40 #include <internal/v86m.h>
41 #include <ntos/tss.h>
42 //#include <ntos/service.h>
43 #include <internal/trap.h>
44 #include <internal/ps.h>
45
46 #include <roscfg.h>
47 #include <internal/ntoskrnl.h>
48 #include <internal/i386/segment.h>
49
50
51 #define KernelMode (0)
52 #define UserMode (1)
53
54
55 // TMN: Replicated here to reduce mess-time
56 #ifdef STATUS_INVALID_SYSTEM_SERVICE
57 #undef STATUS_INVALID_SYSTEM_SERVICE
58 #endif
59 #define STATUS_INVALID_SYSTEM_SERVICE 0xc000001c
60
61
62 /*
63 *
64 */
65
66 void KiServiceCheck (ULONG Nr);
67 ULONG KiAfterSystemCallHook(ULONG NtStatus, PKTRAP_FRAME TrapFrame);
68 VOID KiSystemCallHook(ULONG Nr, ...);
69
70 void KeReturnFromSystemCallWithHook();
71 void KeReturnFromSystemCall();
72
73
74 __declspec(naked)
75 void interrupt_handler2e(void)
76 {
77 __asm
78 {
79 /* Construct a trap frame on the stack */
80
81 /* Error code */
82 push 0
83 push ebp
84 push ebx
85 push esi
86 push edi
87 push fs
88 /* Load PCR selector into fs */
89 mov ebx, PCR_SELECTOR
90 mov fs, bx
91
92 /* Save the old exception list */
93 mov ebx, fs:KPCR_EXCEPTION_LIST
94 push ebx
95 /* Set the exception handler chain terminator */
96 mov dword ptr fs:KPCR_EXCEPTION_LIST, 0xffffffff
97 /* Get a pointer to the current thread */
98 mov esi, fs:KPCR_CURRENT_THREAD
99 /* Save the old previous mode */
100 xor ebx,ebx
101 mov bl, ss:KTHREAD_PREVIOUS_MODE[esi]
102 push ebx
103 /* Set the new previous mode based on the saved CS selector */
104 mov ebx, 0x24[esp]
105 and ebx, 0x0000FFFF
106 cmp ebx, KERNEL_CS
107 #if 0
108 // TODO: Verify implementation change and use this code path
109 // to remove two conditional jumps.
110 setnz bl
111 mov ss:KTHREAD_PREVIOUS_MODE[esi], bl
112 #else
113 jne L1
114 mov ss:KTHREAD_PREVIOUS_MODE[esi], KernelMode
115 jmp L3
116 L1:
117 mov ss:KTHREAD_PREVIOUS_MODE[esi], UserMode
118 L3:
119
120 #endif
121 /* Save other registers */
122 push eax
123 push ecx
124 push edx
125 push ds
126 push es
127 push gs
128 push 0 /* DR7 */
129 push 0 /* DR6 */
130 push 0 /* DR3 */
131 push 0 /* DR2 */
132 push 0 /* DR1 */
133 push 0 /* DR0 */
134 push 0 /* XXX: TempESP */
135 push 0 /* XXX: TempCS */
136 push 0 /* XXX: DebugPointer */
137 push 0 /* XXX: DebugArgMark */
138 mov ebx, 0x60[esp]
139 push ebx /* DebugEIP */
140 push ebp /* DebugEBP */
141
142 /* Load the segment registers */
143 mov bx, KERNEL_DS
144 mov ds, bx
145 mov es, bx
146 mov gs, bx
147
148 /*
149 * Save the old trap frame pointer over where we would save the EDX
150 * register.
151 */
152 mov ebx, KTHREAD_TRAP_FRAME[esi]
153 mov 0x3C[esp], ebx
154
155 /* Save a pointer to the trap frame in the TCB */
156 mov KTHREAD_TRAP_FRAME[esi], esp
157
158 /* Set ES to kernel segment */
159 mov bx, KERNEL_DS
160 mov es, bx
161
162 /* Allocate new Kernel stack frame */
163 mov ebp, esp
164
165 /* Users's current stack frame pointer is source */
166 mov esi, edx
167
168 /* Determine system service table to use */
169 cmp eax, 0x0fff
170 ja new_useShadowTable
171
172 /* Check to see if EAX is valid/inrange */
173 cmp eax, es:KeServiceDescriptorTable + 8
174 jbe new_serviceInRange
175 mov eax, STATUS_INVALID_SYSTEM_SERVICE
176 jmp KeReturnFromSystemCall
177
178 new_serviceInRange:
179
180 /* Allocate room for argument list from kernel stack */
181 mov ecx, es:KeServiceDescriptorTable + 12
182 mov ecx, es:[ecx + eax * 4]
183 sub esp, ecx
184
185 /* Copy the arguments from the user stack to the kernel stack */
186 mov edi, esp
187 cld
188 repe movsb
189
190 /* DS is now also kernel segment */
191 mov ds, bx
192
193 /* Call system call hook */
194 push eax
195 call KiSystemCallHook
196 pop eax
197
198 /* Make the system service call */
199 mov ecx, es:KeServiceDescriptorTable
200 mov eax, es:[ecx + eax * 4]
201 call eax
202
203 #if CHECKED
204 /* Bump Service Counter */
205 #endif
206
207 /* Deallocate the kernel stack frame */
208 mov esp, ebp
209
210 /* Call the post system call hook and deliver any pending APCs */
211 push ebp
212 push eax
213 call KiAfterSystemCallHook
214 add esp, 8
215
216 jmp KeReturnFromSystemCall
217
218 new_useShadowTable:
219
220 sub eax, 0x1000
221
222 /* Check to see if EAX is valid/inrange */
223 cmp eax, es:KeServiceDescriptorTableShadow + 24
224 jbe new_shadowServiceInRange
225 mov eax, STATUS_INVALID_SYSTEM_SERVICE
226 jmp KeReturnFromSystemCall
227
228 new_shadowServiceInRange:
229
230 /* Allocate room for argument list from kernel stack */
231 mov ecx, es:KeServiceDescriptorTableShadow + 28
232 mov ecx, es:[ecx + eax * 4]
233 sub esp, ecx
234
235 /* Copy the arguments from the user stack to the kernel stack */
236 mov edi, esp
237 cld
238 repe movsb
239
240 /* DS is now also kernel segment */
241 mov ds, bx
242
243 /* Call system call hook */
244 // pushl %eax
245 // call _KiSystemCallHook
246 // popl %eax
247
248 /* Call service check routine */
249 push eax
250 call KiServiceCheck
251 pop eax
252
253 /* Make the system service call */
254 mov ecx, es:KeServiceDescriptorTableShadow + 16
255 mov eax, es:[ecx + eax * 4]
256 call eax
257
258 #if CHECKED
259 /* Bump Service Counter */
260 #endif
261
262 /* Deallocate the kernel stack frame */
263 mov esp, ebp
264
265 // TMN: Added, to be able to separate this into different functions
266 jmp KeReturnFromSystemCallWithHook
267 }
268 }
269
270 __declspec(naked)
271 void KeReturnFromSystemCallWithHook()
272 {
273 __asm
274 {
275 /* Call the post system call hook and deliver any pending APCs */
276 push esp
277 push eax
278 call KiAfterSystemCallHook
279 add esp, 8
280
281 // TMN: Added, to be able to separate this into different functions
282 jmp KeReturnFromSystemCall
283 }
284 }
285
286 __declspec(naked)
287 void KeReturnFromSystemCall()
288 {
289 __asm
290 {
291 /* Restore the user context */
292 /* Get a pointer to the current thread */
293 mov esi, fs:0x124
294
295 /* Restore the old trap frame pointer */
296 mov ebx, 0x3c[esp]
297 mov KTHREAD_TRAP_FRAME[esi], ebx
298
299 /* Skip debug information and unsaved registers */
300 add esp, 0x30
301 pop gs
302 pop es
303 pop ds
304 pop edx
305 pop ecx
306 add esp, 4 /* Don't restore eax */
307
308 /* Restore the old previous mode */
309 pop ebx
310 mov ss:KTHREAD_PREVIOUS_MODE[esi], bl
311
312 /* Restore the old exception handler list */
313 pop ebx
314 mov fs:KPCR_EXCEPTION_LIST, ebx
315
316 pop fs
317 pop edi
318 pop esi
319 pop ebx
320 pop ebp
321 add esp, 4 /* Ignore error code */
322
323 iretd
324 }
325 }