/* * ReactOS kernel * Copyright (C) 2000 David Welch * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* $Id: syscall.S,v 1.16 2004/07/02 00:47:57 royce Exp $ * * FILE: ntoskrnl/hal/x86/syscall.s * PURPOSE: 2E trap handler * PROGRAMMER: David Welch (david.welch@seh.ox.ac.uk) * UPDATE HISTORY: * ??? */ #include #include #include #include #include #define KernelMode (0) #define UserMode (1) /* * */ .globl KeReturnFromSystemCall .globl KeReturnFromSystemCallWithHook .globl _interrupt_handler2e _interrupt_handler2e: /* Construct a trap frame on the stack */ /* Error code */ pushl $0 pushl %ebp pushl %ebx pushl %esi pushl %edi pushl %fs /* Load PCR selector into fs */ movl $PCR_SELECTOR, %ebx movl %ebx, %fs /* Save the old exception list */ movl %fs:KPCR_EXCEPTION_LIST, %ebx pushl %ebx /* Set the exception handler chain terminator */ movl $0xffffffff, %fs:KPCR_EXCEPTION_LIST /* Get a pointer to the current thread */ movl %fs:KPCR_CURRENT_THREAD, %esi /* Save the old previous mode */ movl $0, %ebx movb %ss:KTHREAD_PREVIOUS_MODE(%esi), %bl pushl %ebx /* Set the new previous mode based on the saved CS selector */ movl 0x24(%esp), %ebx andl $0x0000FFFF, %ebx cmpl $KERNEL_CS, %ebx jne L1 movb $KernelMode, %ss:KTHREAD_PREVIOUS_MODE(%esi) jmp L3 L1: movb $UserMode, %ss:KTHREAD_PREVIOUS_MODE(%esi) L3: /* Save other registers */ pushl %eax pushl %ecx pushl %edx pushl %ds pushl %es pushl %gs pushl $0 /* DR7 */ pushl $0 /* DR6 */ pushl $0 /* DR3 */ pushl $0 /* DR2 */ pushl $0 /* DR1 */ pushl $0 /* DR0 */ pushl $0 /* XXX: TempESP */ pushl $0 /* XXX: TempCS */ pushl $0 /* XXX: DebugPointer */ pushl $0 /* XXX: DebugArgMark */ #ifdef DBG /* Trick gdb 6 into backtracing over the system call */ movl 4(%ebp), %ebx pushl %ebx /* DebugEIP */ movl (%ebp), %ebx pushl %ebx /* DebugEBP */ #else movl 0x60(%esp), %ebx pushl %ebx /* DebugEIP */ pushl %ebp /* DebugEBP */ #endif /* Load the segment registers */ movl $KERNEL_DS, %ebx movl %ebx, %ds movl %ebx, %es movl %ebx, %gs /* * Save the old trap frame pointer over where we would save the EDX * register. */ movl KTHREAD_TRAP_FRAME(%esi), %ebx movl %ebx, KTRAP_FRAME_EDX(%esp) /* Allocate new Kernel stack frame */ movl %esp,%ebp /* Save a pointer to the trap frame in the TCB */ movl %ebp, KTHREAD_TRAP_FRAME(%esi) /* Set ES to kernel segment */ movw $KERNEL_DS,%bx movw %bx,%es /* Users's current stack frame pointer is source */ movl %edx,%esi /* Determine system service table to use */ cmpl $0x0fff, %eax ja new_useShadowTable /* Check to see if EAX is valid/inrange */ cmpl %es:_KeServiceDescriptorTable + 8, %eax jbe new_serviceInRange movl $STATUS_INVALID_SYSTEM_SERVICE, %eax movl %eax, KTRAP_FRAME_EAX(%ebp) /* save our return value in PKTRAP_FRAME->Eax */ jmp KeReturnFromSystemCall new_serviceInRange: #ifdef DBG /* GDB thinks the function starts here and wants a standard prolog, so let's give it */ pushl %ebp movl %esp,%ebp popl %ebp #endif /* Allocate room for argument list from kernel stack */ movl %es:_KeServiceDescriptorTable + 12, %ecx movb %es:(%ecx, %eax), %cl movzx %cl, %ecx subl %ecx, %esp /* Copy the arguments from the user stack to the kernel stack */ movl %esp,%edi cld rep movsb /* DS is now also kernel segment */ movw %bx, %ds /* Call system call hook */ pushl %eax call _KiSystemCallHook popl %eax /* Make the system service call */ movl %es:_KeServiceDescriptorTable, %ecx movl %es:(%ecx, %eax, 4), %eax call *%eax movl %eax, KTRAP_FRAME_EAX(%ebp) /* save our return value in PKTRAP_FRAME->Eax */ #if CHECKED /* Bump Service Counter */ #endif jmp KeDeallocateStackAndReturnFromSystemCallWithHook new_useShadowTable: subl $0x1000, %eax /* Check to see if EAX is valid/inrange */ cmpl %es:_KeServiceDescriptorTableShadow + 24, %eax jbe new_shadowServiceInRange movl $STATUS_INVALID_SYSTEM_SERVICE, %eax movl %eax, KTRAP_FRAME_EAX(%ebp) /* save our return value in PKTRAP_FRAME->Eax */ jmp KeReturnFromSystemCall new_shadowServiceInRange: #ifdef DBG /* GDB thinks the function starts here and wants a standard prolog, so let's give it */ pushl %ebp movl %esp,%ebp popl %ebp #endif /* Allocate room for argument list from kernel stack */ movl %es:_KeServiceDescriptorTableShadow + 28, %ecx movb %es:(%ecx, %eax), %cl movzx %cl, %ecx subl %ecx, %esp /* Copy the arguments from the user stack to the kernel stack */ movl %esp,%edi cld rep movsb /* DS is now also kernel segment */ movw %bx,%ds /* Call system call hook */ // pushl %eax // call _KiSystemCallHook // popl %eax /* Call service check routine */ pushl %eax call _KiServiceCheck popl %eax /* Make the system service call */ movl %es:_KeServiceDescriptorTableShadow + 16, %ecx movl %es:(%ecx, %eax, 4), %eax call *%eax movl %eax, KTRAP_FRAME_EAX(%ebp) /* save our return value in PKTRAP_FRAME->Eax */ #if CHECKED /* Bump Service Counter */ #endif KeDeallocateStackAndReturnFromSystemCallWithHook: /* Deallocate the kernel stack frame */ movl %ebp,%esp KeReturnFromSystemCallWithHook: /* Call the post system call hook and deliver any pending APCs */ pushl %esp call _KiAfterSystemCallHook addl $4,%esp KeReturnFromSystemCall: /* Restore the user context */ /* Get a pointer to the current thread */ movl %fs:0x124, %esi /* Restore the old trap frame pointer */ movl KTRAP_FRAME_EDX(%esp), %ebx movl %ebx, KTHREAD_TRAP_FRAME(%esi) KiRosTrapReturn: #if 0 mov KTRAP_FRAME_RESERVED1(%ebp), %ax cmp %ax, SSIDX_NTCONTINUE jnz KeNoEpilogPrint movl KTRAP_FRAME_ESP(%ebp), %ecx movl KTRAP_FRAME_EBP(%ebp), %edx call @KeRosPrintEspEbp@8 KeNoEpilogPrint: #endif /* Skip debug information and unsaved registers */ addl $0x30, %esp popl %gs popl %es popl %ds popl %edx popl %ecx popl %eax /* Restore the old previous mode */ popl %ebx movb %bl, %ss:KTHREAD_PREVIOUS_MODE(%esi) /* Restore the old exception handler list */ popl %ebx movl %ebx, %fs:KPCR_EXCEPTION_LIST popl %fs popl %edi popl %esi popl %ebx popl %ebp addl $0x4, %esp /* Ignore error code */ iret /* R3: NOTE: This is part of my in-progress attempt at correcting NtContinue * It is not being called, yet... */ .globl @KeRosTrapReturn@8 @KeRosTrapReturn@8: /* point %esp to the trap frame to restore */ movl %ecx, %esp movl %esp, %ebp /* Call the post system call hook and deliver any pending APCs */ pushl %esp call _KiAfterSystemCallHook addl $4,%esp /* Restore the user context */ /* Get a pointer to the current thread */ movl %fs:0x124, %esi /* Restore the old trap frame pointer */ movl %edx, KTHREAD_TRAP_FRAME(%esi) jmp KiRosTrapReturn;