f843f97599c848cb46656c1e61cfe92496843124
[reactos.git] / reactos / ntoskrnl / ke / i386 / syscall.S
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2000 David Welch <welch@cwcom.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: syscall.S,v 1.14 2004/04/07 15:35:14 ekohl Exp $
20 *
21 * FILE: ntoskrnl/hal/x86/syscall.s
22 * PURPOSE: 2E trap handler
23 * PROGRAMMER: David Welch (david.welch@seh.ox.ac.uk)
24 * UPDATE HISTORY:
25 * ???
26 */
27
28 #include <ddk/status.h>
29 #include <internal/i386/segment.h>
30 #include <internal/ps.h>
31 #include <roscfg.h>
32
33 #define KernelMode (0)
34 #define UserMode (1)
35
36 /*
37 *
38 */
39 .globl KeReturnFromSystemCall
40 .globl KeReturnFromSystemCallWithHook
41 .globl _interrupt_handler2e
42 _interrupt_handler2e:
43
44 /* Construct a trap frame on the stack */
45
46 /* Error code */
47 pushl $0
48 pushl %ebp
49 pushl %ebx
50 pushl %esi
51 pushl %edi
52 pushl %fs
53 /* Load PCR selector into fs */
54 movl $PCR_SELECTOR, %ebx
55 movl %ebx, %fs
56
57 /* Save the old exception list */
58 movl %fs:KPCR_EXCEPTION_LIST, %ebx
59 pushl %ebx
60 /* Set the exception handler chain terminator */
61 movl $0xffffffff, %fs:KPCR_EXCEPTION_LIST
62 /* Get a pointer to the current thread */
63 movl %fs:KPCR_CURRENT_THREAD, %esi
64 /* Save the old previous mode */
65 movl $0, %ebx
66 movb %ss:KTHREAD_PREVIOUS_MODE(%esi), %bl
67 pushl %ebx
68 /* Set the new previous mode based on the saved CS selector */
69 movl 0x24(%esp), %ebx
70 andl $0x0000FFFF, %ebx
71 cmpl $KERNEL_CS, %ebx
72 jne L1
73 movb $KernelMode, %ss:KTHREAD_PREVIOUS_MODE(%esi)
74 jmp L3
75 L1:
76 movb $UserMode, %ss:KTHREAD_PREVIOUS_MODE(%esi)
77 L3:
78
79 /* Save other registers */
80 pushl %eax
81 pushl %ecx
82 pushl %edx
83 pushl %ds
84 pushl %es
85 pushl %gs
86 pushl $0 /* DR7 */
87 pushl $0 /* DR6 */
88 pushl $0 /* DR3 */
89 pushl $0 /* DR2 */
90 pushl $0 /* DR1 */
91 pushl $0 /* DR0 */
92 pushl $0 /* XXX: TempESP */
93 pushl $0 /* XXX: TempCS */
94 pushl $0 /* XXX: DebugPointer */
95 pushl $0 /* XXX: DebugArgMark */
96 #ifdef DBG
97 /* Trick gdb 6 into backtracing over the system call */
98 movl 4(%ebp), %ebx
99 pushl %ebx /* DebugEIP */
100 movl (%ebp), %ebx
101 pushl %ebx /* DebugEBP */
102 #else
103 movl 0x60(%esp), %ebx
104 pushl %ebx /* DebugEIP */
105 pushl %ebp /* DebugEBP */
106 #endif
107
108 /* Load the segment registers */
109 movl $KERNEL_DS, %ebx
110 movl %ebx, %ds
111 movl %ebx, %es
112 movl %ebx, %gs
113
114 /*
115 * Save the old trap frame pointer over where we would save the EDX
116 * register.
117 */
118 movl KTHREAD_TRAP_FRAME(%esi), %ebx
119 movl %ebx, 0x3C(%esp)
120
121 /* Save a pointer to the trap frame in the TCB */
122 movl %esp, KTHREAD_TRAP_FRAME(%esi)
123
124 /* Set ES to kernel segment */
125 movw $KERNEL_DS,%bx
126 movw %bx,%es
127
128 /* Allocate new Kernel stack frame */
129 movl %esp,%ebp
130
131 /* Users's current stack frame pointer is source */
132 movl %edx,%esi
133
134 /* Determine system service table to use */
135 cmpl $0x0fff, %eax
136 ja new_useShadowTable
137
138 /* Check to see if EAX is valid/inrange */
139 cmpl %es:_KeServiceDescriptorTable + 8, %eax
140 jbe new_serviceInRange
141 movl $STATUS_INVALID_SYSTEM_SERVICE, %eax
142 jmp KeReturnFromSystemCall
143
144 new_serviceInRange:
145
146 #ifdef DBG
147 /* GDB thinks the function starts here and
148 wants a standard prolog, so let's give it */
149 pushl %ebp
150 movl %esp,%ebp
151 popl %ebp
152 #endif
153
154 /* Allocate room for argument list from kernel stack */
155 movl %es:_KeServiceDescriptorTable + 12, %ecx
156 movb %es:(%ecx, %eax), %cl
157 movzx %cl, %ecx
158 subl %ecx, %esp
159
160 /* Copy the arguments from the user stack to the kernel stack */
161 movl %esp,%edi
162 cld
163 rep movsb
164
165 /* DS is now also kernel segment */
166 movw %bx, %ds
167
168 /* Call system call hook */
169 pushl %eax
170 call _KiSystemCallHook
171 popl %eax
172
173 /* Make the system service call */
174 movl %es:_KeServiceDescriptorTable, %ecx
175 movl %es:(%ecx, %eax, 4), %eax
176 call *%eax
177
178 #if CHECKED
179 /* Bump Service Counter */
180 #endif
181
182 /* Deallocate the kernel stack frame */
183 movl %ebp,%esp
184
185 /* Call the post system call hook and deliver any pending APCs */
186 pushl %ebp
187 pushl %eax
188 call _KiAfterSystemCallHook
189 addl $8,%esp
190
191 jmp KeReturnFromSystemCall
192
193 new_useShadowTable:
194
195 subl $0x1000, %eax
196
197 /* Check to see if EAX is valid/inrange */
198 cmpl %es:_KeServiceDescriptorTableShadow + 24, %eax
199 jbe new_shadowServiceInRange
200 movl $STATUS_INVALID_SYSTEM_SERVICE, %eax
201 jmp KeReturnFromSystemCall
202
203 new_shadowServiceInRange:
204
205 #ifdef DBG
206 /* GDB thinks the function starts here and
207 wants a standard prolog, so let's give it */
208 pushl %ebp
209 movl %esp,%ebp
210 popl %ebp
211 #endif
212
213 /* Allocate room for argument list from kernel stack */
214 movl %es:_KeServiceDescriptorTableShadow + 28, %ecx
215 movb %es:(%ecx, %eax), %cl
216 movzx %cl, %ecx
217 subl %ecx, %esp
218
219 /* Copy the arguments from the user stack to the kernel stack */
220 movl %esp,%edi
221 cld
222 rep movsb
223
224 /* DS is now also kernel segment */
225 movw %bx,%ds
226
227 /* Call system call hook */
228 // pushl %eax
229 // call _KiSystemCallHook
230 // popl %eax
231
232 /* Call service check routine */
233 pushl %eax
234 call _KiServiceCheck
235 popl %eax
236
237 /* Make the system service call */
238 movl %es:_KeServiceDescriptorTableShadow + 16, %ecx
239 movl %es:(%ecx, %eax, 4), %eax
240 call *%eax
241
242 #if CHECKED
243 /* Bump Service Counter */
244 #endif
245
246 /* Deallocate the kernel stack frame */
247 movl %ebp,%esp
248
249 KeReturnFromSystemCallWithHook:
250 /* Call the post system call hook and deliver any pending APCs */
251 pushl %esp
252 pushl %eax
253 call _KiAfterSystemCallHook
254 addl $8,%esp
255
256 KeReturnFromSystemCall:
257
258 /* Restore the user context */
259 /* Get a pointer to the current thread */
260 movl %fs:0x124, %esi
261
262 /* Restore the old trap frame pointer */
263 movl 0x3c(%esp), %ebx
264 movl %ebx, KTHREAD_TRAP_FRAME(%esi)
265
266 /* Skip debug information and unsaved registers */
267 addl $0x30, %esp
268 popl %gs
269 popl %es
270 popl %ds
271 popl %edx
272 popl %ecx
273 addl $0x4, %esp /* Don't restore eax */
274
275 /* Restore the old previous mode */
276 popl %ebx
277 movb %bl, %ss:KTHREAD_PREVIOUS_MODE(%esi)
278
279 /* Restore the old exception handler list */
280 popl %ebx
281 movl %ebx, %fs:KPCR_EXCEPTION_LIST
282
283 popl %fs
284 popl %edi
285 popl %esi
286 popl %ebx
287 popl %ebp
288 addl $0x4, %esp /* Ignore error code */
289
290 iret