eb4f068b7f94f92210af0c34706d03266ea0605b
[reactos.git] / 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$
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 <ddk/defines.h>
32
33 /*
34  *
35  */
36 .globl KeReturnFromSystemCall
37 .globl KeReturnFromSystemCallWithHook
38 .globl _interrupt_handler2e
39 _interrupt_handler2e:
40
41            /* Construct a trap frame on the stack */
42
43            /* Error code */
44            pushl        $0     
45            pushl        %ebp
46            pushl        %ebx
47            pushl        %esi
48            pushl        %edi
49            pushl        %fs
50            /* Load PCR selector into fs */
51            movl         $PCR_SELECTOR, %ebx 
52            movl         %ebx, %fs
53
54            /* Save the old exception list */
55            movl         %fs:KPCR_EXCEPTION_LIST, %ebx
56            pushl        %ebx
57            /* Set the exception handler chain terminator */
58            movl         $0xffffffff, %fs:KPCR_EXCEPTION_LIST
59            /* Get a pointer to the current thread */
60            movl         %fs:KPCR_CURRENT_THREAD, %esi
61            /* Save the old previous mode */
62            movl         $0, %ebx
63            movb         %ss:KTHREAD_PREVIOUS_MODE(%esi), %bl
64            pushl        %ebx
65            /* Set the new previous mode based on the saved CS selector */
66            movl         0x24(%esp), %ebx
67            andl         $0x0000FFFF, %ebx
68            cmpl         $KERNEL_CS, %ebx
69            jne          L1
70            movb         $KernelMode, %ss:KTHREAD_PREVIOUS_MODE(%esi)
71            jmp          L3
72 L1:
73            movb         $UserMode, %ss:KTHREAD_PREVIOUS_MODE(%esi)
74 L3:
75
76            /* Save other registers */      
77            pushl %eax
78            pushl %ecx
79            pushl %edx
80            pushl %ds
81            pushl %es
82            pushl %gs
83            pushl $0     /* DR7 */
84            pushl $0     /* DR6 */
85            pushl $0     /* DR3 */
86            pushl $0     /* DR2 */
87            pushl $0     /* DR1 */
88            pushl $0     /* DR0 */
89            pushl $0     /* XXX: TempESP */
90            pushl $0     /* XXX: TempCS */
91            pushl $0     /* XXX: DebugPointer */
92            pushl $0     /* XXX: DebugArgMark */
93            movl  0x60(%esp), %ebx
94            pushl %ebx   /* DebugEIP */
95            pushl %ebp   /* DebugEBP */
96
97            /* Load the segment registers */
98            movl  $KERNEL_DS, %ebx
99            movl  %ebx, %ds
100            movl  %ebx, %es
101            movl  %ebx, %gs
102
103            /* 
104             * Save the old trap frame pointer over where we would save the EDX
105             * register.
106             */
107            movl KTHREAD_TRAP_FRAME(%esi), %ebx
108            movl %ebx, 0x3C(%esp)
109         
110            /* Save a pointer to the trap frame in the TCB */
111            movl %esp, KTHREAD_TRAP_FRAME(%esi)
112          
113            /*  Set ES to kernel segment  */
114            movw $KERNEL_DS,%bx
115            movw %bx,%es
116
117            /*  Allocate new Kernel stack frame  */
118            movl %esp,%ebp
119
120            /*  Users's current stack frame pointer is source  */
121            movl %edx,%esi
122
123            /*  Determine system service table to use  */
124            cmpl  $0x0fff, %eax
125            ja    new_useShadowTable
126
127            /*  Check to see if EAX is valid/inrange  */
128            cmpl  %es:_KeServiceDescriptorTable + 8, %eax
129            jbe   new_serviceInRange
130            movl  $STATUS_INVALID_SYSTEM_SERVICE, %eax
131            jmp   KeReturnFromSystemCall
132
133 new_serviceInRange:
134
135            /*  Allocate room for argument list from kernel stack  */
136            movl  %es:_KeServiceDescriptorTable + 12, %ecx
137            movl  %es:(%ecx, %eax, 4), %ecx
138            subl  %ecx, %esp
139
140            /*  Copy the arguments from the user stack to the kernel stack  */
141            movl %esp,%edi
142            rep  movsb
143
144            /*  DS is now also kernel segment  */
145            movw %bx, %ds
146            
147            /* Call system call hook */
148            pushl %eax
149            call _KiSystemCallHook
150            popl %eax
151
152            /*  Make the system service call  */
153            movl  %es:_KeServiceDescriptorTable, %ecx
154            movl  %es:(%ecx, %eax, 4), %eax
155            call  *%eax
156
157 #if CHECKED
158            /*  Bump Service Counter  */
159 #endif
160
161            /*  Deallocate the kernel stack frame  */
162            movl %ebp,%esp
163
164            /* Call the post system call hook and deliver any pending APCs */
165            pushl %ebp
166            pushl %eax
167            call _KiAfterSystemCallHook
168            addl $8,%esp
169
170            jmp  KeReturnFromSystemCall
171
172 new_useShadowTable:
173
174            subl  $0x1000, %eax
175
176            /*  Check to see if EAX is valid/inrange  */
177            cmpl  %es:_KeServiceDescriptorTableShadow + 24, %eax
178            jbe   new_shadowServiceInRange
179            movl  $STATUS_INVALID_SYSTEM_SERVICE, %eax
180            jmp   KeReturnFromSystemCall
181
182 new_shadowServiceInRange:
183
184            /*  Allocate room for argument list from kernel stack  */
185            movl  %es:_KeServiceDescriptorTableShadow + 28, %ecx
186            movl  %es:(%ecx, %eax, 4), %ecx
187            subl  %ecx, %esp
188
189            /*  Copy the arguments from the user stack to the kernel stack  */
190            movl %esp,%edi
191            rep movsb
192
193            /*  DS is now also kernel segment  */
194            movw %bx,%ds
195
196            /* Call system call hook */
197            pushl %eax
198            call _KiSystemCallHook
199            popl %eax
200  
201            /*  Make the system service call  */
202            movl  %es:_KeServiceDescriptorTableShadow + 16, %ecx
203            movl  %es:(%ecx, %eax, 4), %eax
204            call  *%eax
205
206 #if CHECKED
207            /*  Bump Service Counter  */
208 #endif
209
210            /*  Deallocate the kernel stack frame  */
211            movl %ebp,%esp
212
213 KeReturnFromSystemCallWithHook: 
214            /* Call the post system call hook and deliver any pending APCs */
215            pushl %esp
216            pushl %eax
217            call _KiAfterSystemCallHook
218            addl $8,%esp
219
220 KeReturnFromSystemCall:
221         
222            /* Restore the user context */
223            /* Get a pointer to the current thread */
224            movl %fs:0x124, %esi
225         
226            /* Restore the old trap frame pointer */
227            movl 0x3c(%esp), %ebx
228            movl %ebx, KTHREAD_TRAP_FRAME(%esi)
229         
230            /* Skip debug information and unsaved registers */
231            addl $0x30, %esp
232            popl %gs
233            popl %es
234            popl %ds
235            popl %edx
236            popl %ecx
237            addl $0x4, %esp   /* Don't restore eax */
238
239            /* Restore the old previous mode */
240            popl %ebx
241            movb %bl, %ss:KTHREAD_PREVIOUS_MODE(%esi)
242
243            /* Restore the old exception handler list */
244            popl %ebx
245            movl %ebx, %fs:KPCR_EXCEPTION_LIST
246         
247            popl %fs 
248            popl %edi
249            popl %esi
250            popl %ebx
251            popl %ebp
252            addl $0x4, %esp  /* Ignore error code */
253                 
254            iret