3 * FILE: ntoskrnl/ke/i386/syscall.S
4 * COPYRIGHT: See COPYING in the top level directory
5 * PURPOSE: System Call Handler
6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
8 * ??-??-??: Original Version - David Welch(?)
9 * 13-01-05: Complete rewrite, added support for SYSENTER, direct kmode syscalls
10 * and re-wrote most of handler code. - Alex Ionescu
14 #include <internal/i386/ke.h>
15 #include <internal/asm.h>
16 #include <ndk/i386/segment.h>
17 #include <napi/shared_data.h>
21 .globl KeReturnFromSystemCallWithHook
23 .globl _KiServiceExit2
24 .globl _KiFastCallEntry
25 .globl _KiSystemService
26 .globl _KiDebugService
31 movl $PCR_SELECTOR, %ecx
34 /* Set the current stack to Kernel Stack */
35 movl %fs:KPCR_TSS, %ecx
36 movl %ss:KTSS_ESP0(%ecx), %ecx
39 /* Set up a fake INT Stack. */
41 pushl %edx /* Ring 3 SS:ESP */
43 orl $X86_EFLAGS_IF, (%esp) /* Re-enable IRQs in EFLAGS, to fake INT */
45 pushl $KUSER_SHARED_SYSCALL_RET
47 /* User Parameter List */
53 * Construct a trap frame on the stack.
54 * The following are already on the stack.
68 /* Load PCR Selector into fs */
69 movw $PCR_SELECTOR, %bx
72 /* Save the previous exception list */
73 pushl %fs:KPCR_EXCEPTION_LIST // + 0x2C
75 /* Set the exception handler chain terminator */
76 movl $0xffffffff, %fs:KPCR_EXCEPTION_LIST
78 /* Get a pointer to the current thread */
79 movl %fs:KPCR_CURRENT_THREAD, %esi
81 /* Save the old previous mode */
82 pushl %ss:KTHREAD_PREVIOUS_MODE(%esi) // + 0x30
84 /* Set the new previous mode based on the saved CS selector */
87 movb %bl, %ss:KTHREAD_PREVIOUS_MODE(%esi)
89 /* Save other registers */
96 sub $0x28, %esp // + 0x70
99 /* Trick gdb 6 into backtracing over the system call */
101 pushl 4(%ebx) /* DebugEIP */ // + 0x74
103 pushl 0x60(%esp) /* DebugEIP */ // + 0x74
105 pushl %ebp /* DebugEBP */ // + 0x78
107 /* Load the segment registers */
113 /* Save the old trap frame pointer where EDX would be saved */
114 movl KTHREAD_TRAP_FRAME(%esi), %ebx
115 movl %ebx, KTRAP_FRAME_EDX(%esp)
117 /* Allocate new Kernel stack frame */
120 /* Save a pointer to the trap frame in the TCB */
121 movl %ebp, KTHREAD_TRAP_FRAME(%esi)
127 * GDB thinks the function starts here and
128 * wants a standard prolog, so let's give it
136 * Find out which table offset to use. Converts 0x1124 into 0x10.
137 * The offset is related to the Table Index as such: Offset = TableIndex x 10
144 /* Now add the thread's base system table to the offset */
145 addl KTHREAD_SERVICE_TABLE(%esi), %edi
147 /* Get the true syscall ID and check it */
152 /* Invalid ID, try to load Win32K Table */
153 jnb KiBBTUnexpectedRange
155 /* Users's current stack frame pointer is source */
158 /* Allocate room for argument list from kernel stack */
160 movb (%ecx, %eax), %cl
163 /* Allocate space on our stack */
166 /* Get pointer to function */
168 movl (%edi, %eax, 4), %eax
170 /* Copy the arguments from the user stack to our stack */
176 /* Do the System Call */
178 movl %eax, KTRAP_FRAME_EAX(%ebp)
180 /* Deallocate the kernel stack frame */
183 KeReturnFromSystemCall:
185 /* Get the Current Thread */
186 movl %fs:KPCR_CURRENT_THREAD, %esi
188 /* Restore the old trap frame pointer */
189 movl KTRAP_FRAME_EDX(%esp), %ebx
190 movl %ebx, KTHREAD_TRAP_FRAME(%esi)
194 /* Get the Current Thread */
196 movl %fs:KPCR_CURRENT_THREAD, %esi
198 /* Deliver APCs only if we were called from user mode */
199 testb $1, KTRAP_FRAME_CS(%esp)
202 /* And only if any are actually pending */
203 cmpb $0, KTHREAD_PENDING_USER_APC(%esi)
206 /* Save pointer to Trap Frame */
209 /* Raise IRQL to APC_LEVEL */
221 call _KiDeliverApc@12
224 /* Return to old IRQL */
230 /* Skip debug information and unsaved registers */
231 addl $0x30, %esp // + 0x48
239 /* Restore the old previous mode */
241 movb %bl, %ss:KTHREAD_PREVIOUS_MODE(%esi)
243 /* Restore the old exception handler list */
244 popl %fs:KPCR_EXCEPTION_LIST // + 0x28
246 /* Restore final registers from trap frame */
252 add $4, %esp // + 0x10
254 /* Check if previous CS is from user-mode */
257 /* It is, so use Fast Exit */
261 * Restore what the stub pushed, and return back to it.
262 * Note that we were CALLed, so the first thing on our stack is the ret EIP!
275 /* Is SYSEXIT Supported/Wanted? */
276 cmpl $0, %ss:_KiFastSystemCallDisable
279 /* Restore FS to TIB */
280 mov $TEB_SELECTOR, %ecx
283 /* We will be cleaning up the stack ourselves */
284 popl %edx /* New Ring 3 EIP */
285 add $0x4, %esp /* Skip Ring 3 DS */
286 andl $~X86_EFLAGS_IF, (%esp) /* Remove IRQ hack from EFLAGS */
287 popfl /* Restore old EFLAGS */
288 popl %ecx /* Old Ring 3 SS:ESP */
292 * ECX points to the old User Stack.
293 * EDX points to the instruction to execute in usermode after the sysenter
298 KiBBTUnexpectedRange:
300 /* If this isn't a Win32K call, fail */
304 /* Set up Win32K Table */
311 /* Try the Call again */
316 /* Invalid System Call */
317 movl $0xC000001C, %eax /* STATUS_INVALID_SYSTEM_SERVICE */
318 movl %eax, KTRAP_FRAME_EAX(%ebp)
323 /* Get the Current Thread */
325 movl %fs:KPCR_CURRENT_THREAD, %esi
327 /* Deliver APCs only if we were called from user mode */
328 testb $1, KTRAP_FRAME_CS(%esp)
331 /* And only if any are actually pending */
332 cmpb $0, KTHREAD_PENDING_USER_APC(%esi)
335 /* Save pointer to Trap Frame */
338 /* Raise IRQL to APC_LEVEL */
350 call _KiDeliverApc@12
353 /* Return to old IRQL */
357 /* Skip useless Debug Data */
358 addl $0x18, %esp // + 0x74
360 /* Restore Debug Registers */
374 /* Restore Registers */
382 /* Restore the old previous mode */
384 movb %bl, %ss:KTHREAD_PREVIOUS_MODE(%esi)
386 /* Restore the old exception handler list */
387 popl %fs:KPCR_EXCEPTION_LIST // + 0x28
389 /* Restore final registers from trap frame */
395 add $4, %esp // + 0x10
397 /* Return to user-mode */
400 .intel_syntax noprefix
403 /* Create the Trap Frame */
411 /* Switch to correct FS */
415 /* Save Exception List */
416 push fs:[KPCR_EXCEPTION_LIST]
418 /* Use Old Previous Mode */
419 mov ebx, fs:[KPCR_CURRENT_THREAD]
420 push [ebx+KTHREAD_PREVIOUS_MODE]
422 /* Continue building the Trap Frame */
430 /* Switch Segments to Kernel */
435 /* Save Debug Registers */
451 /* Skip useless debug data */
454 /* Call debug service dispatcher */
458 call _KdpServiceDispatcher@12
460 /* Exit through common routine */