From f2414f3c2cd360cc2cdcaec3a415a84cd397ee34 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Tue, 17 Jan 2006 06:36:35 +0000 Subject: [PATCH] - Move some assembly functions around in better suited locations. - Merge syscall.S and trap.S into trap.S, and nicely document the software interrupt table that we service, as well as special cases. svn path=/trunk/; revision=20936 --- reactos/ntoskrnl/ke/i386/cpu.S | 23 + reactos/ntoskrnl/ke/i386/ctxswitch.S | 34 ++ reactos/ntoskrnl/ke/i386/syscall.S | 584 ---------------------- reactos/ntoskrnl/ke/i386/trap.s | 705 +++++++++++++++++++++++---- reactos/ntoskrnl/ntoskrnl.xml | 1 - 5 files changed, 669 insertions(+), 678 deletions(-) delete mode 100644 reactos/ntoskrnl/ke/i386/syscall.S diff --git a/reactos/ntoskrnl/ke/i386/cpu.S b/reactos/ntoskrnl/ke/i386/cpu.S index 8cb750435ff..494ca6bbf0a 100644 --- a/reactos/ntoskrnl/ke/i386/cpu.S +++ b/reactos/ntoskrnl/ke/i386/cpu.S @@ -46,3 +46,26 @@ _KeFlushCurrentTb@0: mov cr3, eax ret .endfunc + +.globl _KiCoprocessorError@0 +.func KiCoprocessorError@0 +_KiCoprocessorError@0: + + /* Get the NPX Thread's Initial stack */ + mov eax, [fs:KPCR_NPX_THREAD] + mov eax, [eax+KTHREAD_INITIAL_STACK] + + /* Make space for the FPU Save area */ + sub eax, SIZEOF_FX_SAVE_AREA + + /* Set the CR0 State */ + mov dword ptr [eax+FN_CR0_NPX_STATE], 8 + + /* Update it */ + mov eax, cr0 + or eax, 8 + mov cr0, eax + + /* Return to caller */ + ret +.endfunc diff --git a/reactos/ntoskrnl/ke/i386/ctxswitch.S b/reactos/ntoskrnl/ke/i386/ctxswitch.S index 22b5ccf051d..ad0761d1743 100644 --- a/reactos/ntoskrnl/ke/i386/ctxswitch.S +++ b/reactos/ntoskrnl/ke/i386/ctxswitch.S @@ -329,3 +329,37 @@ SameProcess: add esp, 4 * 4 ret +.globl _Ki386AdjustEsp0@4 +.func Ki386AdjustEsp0@4 +_Ki386AdjustEsp0@4: + + /* Get the current thread */ + mov eax, [fs:KPCR_CURRENT_THREAD] + + /* Get trap frame and stack */ + mov edx, [esp+4] + mov eax, [eax+KTHREAD_INITIAL_STACK] + + /* Check if V86 */ + test dword ptr [edx+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK + jnz 1f + + /* Bias the stack */ + sub eax, KTRAP_FRAME_V86_GS - KTRAP_FRAME_SS + +1: + /* Skip FX Save Area */ + sub eax, SIZEOF_FX_SAVE_AREA + + /* Disable interrupts */ + pushf + cli + + /* Adjust ESP0 */ + mov edx, [fs:KPCR_TSS] + mov ss:[edx+KTSS_ESP0], eax + + /* Enable interrupts and return */ + popf + ret 4 +.endfunc diff --git a/reactos/ntoskrnl/ke/i386/syscall.S b/reactos/ntoskrnl/ke/i386/syscall.S deleted file mode 100644 index 7d2ab15e141..00000000000 --- a/reactos/ntoskrnl/ke/i386/syscall.S +++ /dev/null @@ -1,584 +0,0 @@ -/* - * FILE: ntoskrnl/ke/i386/syscall.S - * COPYRIGHT: See COPYING in the top level directory - * PURPOSE: System Call Handler - * PROGRAMMER: Alex Ionescu (alex@relsoft.net) - */ - -#include -#include - -.globl _KiServiceExit -.globl _KiServiceExit2 -.globl _KiFastCallEntry -.globl _KiSystemService -.globl _KiDebugService -.globl _Kei386EoiHelper@0 -.globl _NtRaiseException@12 -.globl _NtContinue@8 -.intel_syntax noprefix - -/* - * FIXMEs: - * - Figure out why ES/DS gets messed up in VMWare, when doing KiServiceExit only, - * and only when called from user-mode, and returning to user-mode. - * - Merge with trap.S and document all traps. - * - Use MmProbe when copying arguments to syscall. - * - Add DR macro/save and VM macro/save. - * - Implement KiCallbackReturn, KiGetTickCount, KiRaiseAssertion - */ - -/* FUNCTIONS ***************************************************************/ - -.func KiSystemService -_KiSystemService: - - /* Enter the shared system call prolog */ - SYSCALL_PROLOG - - /* Jump to the actual handler */ - jmp SharedCode -.endfunc - -BadStack: - - /* Restore ESP0 stack */ - mov ecx, [fs:KPCR_TSS] - mov esp, ss:[ecx+KTSS_ESP0] - - /* Generate V86M Stack for Trap 6 */ - push 0 - push 0 - push 0 - push 0 - - /* Generate interrupt stack for Trap 6 */ - push KGDT_R3_DATA + RPL_MASK - push 0 - push 0x20202 - push KGDT_R3_CODE + RPL_MASK - push 0 - jmp _KiTrap6 - -.func KiFastCallEntry -_KiFastCallEntry: - - /* Set FS to PCR */ - mov ecx, KGDT_R0_PCR - mov fs, cx - - /* Set DS/ES to Kernel Selector */ - mov ecx, KGDT_R0_DATA - mov ds, cx - mov es, cx - - /* Set the current stack to Kernel Stack */ - mov ecx, [fs:KPCR_TSS] - mov esp, ss:[ecx+KTSS_ESP0] - - /* Set up a fake INT Stack. */ - push KGDT_R3_DATA + RPL_MASK - push edx /* Ring 3 SS:ESP */ - pushf /* Ring 3 EFLAGS */ - push 2 /* Ring 0 EFLAGS */ - add edx, 8 /* Skip user parameter list */ - popf /* Set our EFLAGS */ - or dword ptr [esp], EFLAGS_INTERRUPT_MASK /* Re-enable IRQs in EFLAGS, to fake INT */ - push KGDT_R3_CODE + RPL_MASK - push KUSER_SHARED_SYSCALL_RET - - /* Setup the Trap Frame stack */ - push 0 - push ebp - push ebx - push esi - push edi - push KGDT_R3_TEB + RPL_MASK - - /* Save pointer to our PCR */ - mov ebx, [fs:KPCR_SELF] - - /* Get a pointer to the current thread */ - mov esi, [ebx+KPCR_CURRENT_THREAD] - - /* Set the exception handler chain terminator */ - push [ebx+KPCR_EXCEPTION_LIST] - mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1 - - /* Use the thread's stack */ - mov ebp, [esi+KTHREAD_INITIAL_STACK] - - /* Push previous mode */ - push UserMode - - /* Skip the other registers */ - sub esp, 0x48 - - /* Hack: it seems that on VMWare someone damages ES/DS on exit. Investigate! */ - mov dword ptr [esp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK - mov dword ptr [esp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK - - /* Make space for us on the stack */ - sub ebp, 0x29C - - /* Write the previous mode */ - mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], UserMode - - /* Sanity check */ - cmp ebp, esp - jnz BadStack - - /* Flush DR7 */ - and dword ptr [ebp+KTRAP_FRAME_DR7], 0 - - /* Check if the thread was being debugged */ - test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF - - /* Set the thread's trap frame */ - mov [esi+KTHREAD_TRAP_FRAME], ebp - - /* Save DR registers if needed */ - //jnz Dr_FastCallDrSave - - /* Set the trap frame debug header */ - SET_TF_DEBUG_HEADER - -#ifdef DBG // FIXME: Is this for GDB? Can it be moved in the stub? - /* - * We want to know the address from where the syscall stub was called. - * If PrevMode is KernelMode, that address is stored in our own (kernel) - * stack, at location KTRAP_FRAME_ESP. - * If we're coming from UserMode, we load the usermode stack pointer - * and go back two frames (first frame is the syscall stub, second call - * is the caller of the stub). - */ - mov edi, [ebp+KTRAP_FRAME_ESP] - test byte ptr [esi+KTHREAD_PREVIOUS_MODE], 0x01 - jz PrevWasKernelMode - mov edi, [edi+4] -PrevWasKernelMode: - mov [ebp+KTRAP_FRAME_DEBUGEIP], edi -#endif - - /* Enable interrupts */ - sti - -SharedCode: - - /* - * Find out which table offset to use. Converts 0x1124 into 0x10. - * The offset is related to the Table Index as such: Offset = TableIndex x 10 - */ - mov edi, eax - shr edi, SERVICE_TABLE_SHIFT - and edi, SERVICE_TABLE_MASK - mov ecx, edi - - /* Now add the thread's base system table to the offset */ - add edi, [esi+KTHREAD_SERVICE_TABLE] - - /* Get the true syscall ID and check it */ - mov ebx, eax - and eax, SERVICE_NUMBER_MASK - cmp eax, [edi+SERVICE_DESCRIPTOR_LIMIT] - - /* Invalid ID, try to load Win32K Table */ - jnb KiBBTUnexpectedRange - -#if 0 // <== Disabled for two reasons: We don't save TEB in 0x18, but KPCR. - // <== We don't have a KeGdiFlushUserBatch callback yet (needs to be - // sent through the PsInitializeWin32Callouts structure) - /* Check if this was Win32K */ - cmp ecx, SERVICE_TABLE_TEST - jnz NotWin32K - - /* Get the TEB */ - mov ecx, [fs:KPCR_TEB] - - /* Check if we should flush the User Batch */ - xor ebx, ebx - or ebx, [ecx+TEB_GDI_BATCH_COUNT] - jz NoWin32K - - /* Flush it */ - push edx - push eax - call [_KeGdiFlushUserBatch] - pop eax - pop edx -#endif - -NotWin32K: - /* Increase total syscall count */ - inc dword ptr fs:[KPCR_SYSTEM_CALLS] - -#ifdef DBG - /* Increase per-syscall count */ - mov ecx, [edi+SERVICE_DESCRIPTOR_COUNT] - jecxz NoCountTable - inc dword ptr [ecx+eax*4] -#endif - - /* Users's current stack frame pointer is source */ -NoCountTable: - mov esi, edx - - /* Allocate room for argument list from kernel stack */ - mov ebx, [edi+SERVICE_DESCRIPTOR_NUMBER] - xor ecx, ecx - mov cl, [eax+ebx] - - /* Get pointer to function */ - mov edi, [edi+SERVICE_DESCRIPTOR_BASE] - mov ebx, [edi+eax*4] - - /* Allocate space on our stack */ - sub esp, ecx - - /* - * Copy the arguments from the user stack to our stack - * FIXME: This needs to be probed with MmSystemRangeStart - */ - shr ecx, 2 - mov edi, esp - rep movsd - -#ifdef DBG - - /* Make sure this isn't a user-mode call at elevated IRQL */ - test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK - jz SkipCheck - call _KeGetCurrentIrql@0 - or al, al - jnz InvalidIrql - - /* - * The following lines are for the benefit of GDB. It will see the return - * address of the "call ebx" below, find the last label before it and - * thinks that that's the start of the function. It will then check to see - * if it starts with a standard function prolog (push ebp, mov ebp,esp). - * When that standard function prolog is not found, it will stop the - * stack backtrace. Since we do want to backtrace into usermode, let's - * make GDB happy and create a standard prolog. - */ -SkipCheck: -KiSystemService: - push ebp - mov ebp,esp - pop ebp -#endif - - /* Do the System Call */ - call ebx - -#ifdef DBG - /* Make sure the user-mode call didn't return at elevated IRQL */ - test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK - jz SkipCheck2 - mov esi, eax /* We need to save the syscall's return val */ - call _KeGetCurrentIrql@0 - or al, al - jnz InvalidIrql - mov eax, esi /* Restore it */ - - /* Get our temporary current thread pointer for sanity check */ - mov ecx, fs:[KPCR_CURRENT_THREAD] - - /* Make sure that we are not attached and that APCs are not disabled */ - mov dl, [ecx+KTHREAD_APC_STATE_INDEX] - or dl, dl - jnz InvalidIndex - mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE] - or edx, edx - jnz InvalidIndex -#endif - -SkipCheck2: - - /* Deallocate the kernel stack frame */ - mov esp, ebp - -KeReturnFromSystemCall: - - /* Get the Current Thread */ - mov ecx, [fs:KPCR_CURRENT_THREAD] - - /* Restore the old trap frame pointer */ - mov edx, [ebp+KTRAP_FRAME_EDX] - mov [ecx+KTHREAD_TRAP_FRAME], edx -.endfunc - -.func KiServiceExit -_KiServiceExit: - /* Disable interrupts */ - cli - - /* Check for, and deliver, User-Mode APCs if needed */ - CHECK_FOR_APC_DELIVER 1 - - /* Hack for VMWare: Sometimes ES/DS seem to be invalid when returning to user-mode. Investigate! */ - mov es, [ebp+KTRAP_FRAME_ES] - mov ds, [ebp+KTRAP_FRAME_DS] - - /* Exit and cleanup */ - TRAP_EPILOG FromSystemCall, DoRestorePreviousMode, DoNotRestoreSegments, DoNotRestoreVolatiles, DoRestoreEverything -.endfunc - -KiBBTUnexpectedRange: - - /* If this isn't a Win32K call, fail */ - cmp ecx, 0x10 - jne InvalidCall - - /* Set up Win32K Table */ - push edx - push ebx - call _PsConvertToGuiThread@0 - - /* FIXME: Handle failure */ - pop eax - pop edx - - /* Reset trap frame address */ - mov ebp, esp - mov [esi+KTHREAD_TRAP_FRAME], ebp - - /* Try the Call again */ - jmp SharedCode - -InvalidCall: - - /* Invalid System Call */ - mov eax, STATUS_INVALID_SYSTEM_SERVICE - jmp KeReturnFromSystemCall - -#ifdef DBG -InvalidIrql: - /* Save current IRQL */ - push fs:[KPCR_IRQL] - - /* Set us at passive */ - mov dword ptr fs:[KPCR_IRQL], 0 - cli - - /* Bugcheck */ - push 0 - push 0 - push eax - push ebx - push IRQL_GT_ZERO_AT_SYSTEM_SERVICE - call _KeBugCheckEx@20 - -InvalidIndex: - - /* Get the index and APC state */ - movzx eax, byte ptr [ecx+KTHREAD_APC_STATE_INDEX] - mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE] - - /* Bugcheck */ - push 0 - push edx - push eax - push ebx - push APC_INDEX_MISMATCH - call _KeBugCheckEx@20 - ret -#endif - -.func KiServiceExit2 -_KiServiceExit2: - - /* Disable interrupts */ - cli - - /* Check for, and deliver, User-Mode APCs if needed */ - CHECK_FOR_APC_DELIVER 0 - - /* Exit and cleanup */ - TRAP_EPILOG NotFromSystemCall, DoRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything -.endfunc - -.func Kei386EoiHelper@0 -_Kei386EoiHelper@0: - - /* Disable interrupts */ - cli - - /* Check for, and deliver, User-Mode APCs if needed */ - CHECK_FOR_APC_DELIVER 0 - - /* Exit and cleanup */ - TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything -.endfunc - -V86_Exit: - /* Move to EDX position */ - add esp, KTRAP_FRAME_EDX - - /* Restore volatiles */ - pop edx - pop ecx - pop eax - - /* Move to non-volatiles */ - lea esp, [ebp+KTRAP_FRAME_EDI] - pop edi - pop esi - pop ebx - pop ebp - - /* Skip error code and return */ - add esp, 4 - iret - -AbiosExit: - /* Not yet supported */ - int 3 - -_KiDebugService: - - /* Push error code */ - push 0 - - /* Enter trap */ - TRAP_PROLOG(kids) - - /* Increase EIP so we skip the INT3 */ - //inc dword ptr [ebp+KTRAP_FRAME_EIP] - - /* Call debug service dispatcher */ - mov eax, [ebp+KTRAP_FRAME_EAX] - mov ecx, [ebp+KTRAP_FRAME_ECX] - mov edx, [ebp+KTRAP_FRAME_EAX] - - /* Check for V86 mode */ - test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK - jnz NotUserMode - - /* Check if this is kernel or user-mode */ - test byte ptr [ebp+KTRAP_FRAME_CS], 1 - jz CallDispatch - cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK - jnz NotUserMode - - /* Re-enable interrupts */ -VdmProc: - sti - - /* Call the debug routine */ -CallDispatch: - mov esi, ecx - mov edi, edx - mov edx, eax - mov ecx, 3 - push edi - push esi - push edx - call _KdpServiceDispatcher@12 - -NotUserMode: - - /* Get the current process */ - mov ebx, [fs:KPCR_CURRENT_THREAD] - mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS] - - /* Check if this is a VDM Process */ - //cmp dword ptr [ebx+KPROCESS_VDM_OBJECTS], 0 - //jz VdmProc - - /* Exit through common routine */ - jmp _Kei386EoiHelper@0 - -_NtRaiseException@12: - - /* NOTE: We -must- be called by Zw* to have the right frame! */ - /* Push the stack frame */ - push ebp - - /* Get the current thread and restore its trap frame */ - mov ebx, [fs:KPCR_CURRENT_THREAD] - mov edx, [ebp+KTRAP_FRAME_EDX] - mov [ebx+KTHREAD_TRAP_FRAME], edx - - /* Set up stack frame */ - mov ebp, esp - - /* Get the Trap Frame in EBX */ - mov ebx, [ebp+0] - - /* Get the exception list and restore */ - mov eax, [ebx+KTRAP_FRAME_EXCEPTION_LIST] - mov [fs:KPCR_EXCEPTION_LIST], eax - - /* Get the parameters */ - mov edx, [ebp+16] /* Search frames */ - mov ecx, [ebp+12] /* Context */ - mov eax, [ebp+8] /* Exception Record */ - - /* Raise the exception */ - push edx - push ebx - push 0 - push ecx - push eax - call _KiRaiseException@20 - - /* Restore trap frame in EBP */ - pop ebp - mov esp, ebp - - /* Check the result */ - or eax, eax - jz _KiServiceExit2 - - /* Restore debug registers too */ - jmp _KiServiceExit - -_NtContinue@8: - - /* NOTE: We -must- be called by Zw* to have the right frame! */ - /* Push the stack frame */ - push ebp - - /* Get the current thread and restore its trap frame */ - mov ebx, [fs:KPCR_CURRENT_THREAD] - mov edx, [ebp+KTRAP_FRAME_EDX] - mov [ebx+KTHREAD_TRAP_FRAME], edx - - /* Set up stack frame */ - mov ebp, esp - - /* Save the parameters */ - mov eax, [ebp+0] - mov ecx, [ebp+8] - - /* Call KiContinue */ - push eax - push 0 - push ecx - call _KiContinue@12 - - /* Check if we failed (bad context record) */ - or eax, eax - jnz Error - - /* Check if test alert was requested */ - cmp dword ptr [ebp+12], 0 - je DontTest - - /* Test alert for the thread */ - mov al, [ebx+KTHREAD_PREVIOUS_MODE] - push eax - call _KeTestAlertThread@4 - -DontTest: - /* Return to previous context */ - pop ebp - mov esp, ebp - jmp _KiServiceExit2 - -Error: - pop ebp - mov esp, ebp - jmp _KiServiceExit - diff --git a/reactos/ntoskrnl/ke/i386/trap.s b/reactos/ntoskrnl/ke/i386/trap.s index ac0540f5d08..43ec33971ef 100644 --- a/reactos/ntoskrnl/ke/i386/trap.s +++ b/reactos/ntoskrnl/ke/i386/trap.s @@ -1,31 +1,625 @@ /* - * PROJECT: ReactOS kernel - * FILE: ntoskrnl/ke/i386/trap.s - * PURPOSE: Exception handlers - * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) + * FILE: ntoskrnl/ke/i386/trap.S + * COPYRIGHT: See COPYING in the top level directory + * PURPOSE: System Traps, Entrypoints and Exitpoints + * PROGRAMMER: Alex Ionescu (alex@relsoft.net) + * NOTE: See asmmacro.S for the shared entry/exit code. */ /* INCLUDES ******************************************************************/ #include #include +.intel_syntax noprefix -/* NOTES: - * Why not share the epilogue? - * 1) An extra jmp is expensive (jmps are very costly) - * 2) Eventually V86 exit should be handled through ABIOS, and we - * handle ABIOS exit in the shared trap exit code already. - * Why not share the KiTrapHandler call? - * 1) Would make using the trap-prolog macro much harder. - * 2) Eventually some of these traps might be re-implemented in assembly - * to improve speed and depend less on the compiler and/or use features - * not present as C keywords. When that happens, less traps will use the - * shared C handler, so the shared-code would need to be un-shared. - */ +/* + * FIXMEs: + * - Figure out why ES/DS gets messed up in VMWare, when doing KiServiceExit only, + * and only when called from user-mode, and returning to user-mode. + * - Use MmProbe when copying arguments to syscall. + * - Handle failure after PsConvertToGuiThread. + * - Figure out what the DEBUGEIP hack is for and how it can be moved away. + * - Add DR macro/save and VM macro/save. + * - Add .func .endfunc to everything that doesn't have it yet. + * - Implement KiCallbackReturn, KiGetTickCount, KiRaiseAssertion. + */ -/* FUNCTIONS *****************************************************************/ +/* GLOBALS ******************************************************************/ + +/* This is the Software Interrupt Table that we handle in this file: */ +.globl _KiTrap0 /* INT 0: Divide Error (#DE) */ +.globl _KiTrap1 /* INT 1: Debug Exception (#DB) */ +.globl _KiTrap2 /* INT 2: NMI Interrupt */ +.globl _KiTrap3 /* INT 3: Breakpoint Exception (#BP) */ +.globl _KiTrap4 /* INT 4: Overflow Exception (#OF) */ +.globl _KiTrap5 /* INT 5: BOUND Range Exceeded (#BR) */ +.globl _KiTrap6 /* INT 6: Invalid Opcode Code (#UD) */ +.globl _KiTrap7 /* INT 7: Device Not Available (#NM) */ +.globl _KiTrap8 /* INT 8: Double Fault Exception (#DF) */ +.globl _KiTrap9 /* INT 9: RESERVED */ +.globl _KiTrap10 /* INT 10: Invalid TSS Exception (#TS) */ +.globl _KiTrap11 /* INT 11: Segment Not Present (#NP) */ +.globl _KiTrap12 /* INT 12: Stack Fault Exception (#SS) */ +.globl _KiTrap13 /* INT 13: General Protection (#GP) */ +.globl _KiTrap14 /* INT 14: Page-Fault Exception (#PF) */ +.globl _KiTrap15 /* INT 15: RESERVED */ +.globl _KiTrap16 /* INT 16: x87 FPU Error (#MF) */ +.globl _KiTrap17 /* INT 17: Align Check Exception (#AC) */ +.globl _KiTrap18 /* INT 18: Machine Check Exception (#MC)*/ +.globl _KiTrap19 /* INT 19: SIMD FPU Exception (#XF) */ +.globl _KiTrapUnknown /* INT 20-30: UNDEFINED INTERRUPTS */ +.globl _KiDebugService /* INT 31: Get Tick Count Handler */ +.globl _KiCallbackReturn /* INT 32: User-Mode Callback Return */ +.globl _KiRaiseAssertion /* INT 33: Debug Assertion Handler */ +.globl _KiDebugService /* INT 34: Debug Service Handler */ +.globl _KiSystemService /* INT 35: System Call Service Handler */ + +/* We also handle LSTAR Entry */ +.globl _KiFastCallEntry + +/* And special system-defined software traps */ +.globl _NtRaiseException@12 +.globl _NtContinue@8 + +/* We implement the following trap exit points: */ +.globl _KiServiceExit /* Exit from syscall */ +.globl _KiServiceExit2 /* Exit from syscall with complete frame*/ +.globl _Kei386EoiHelper@0 /* Exit from interrupt or H/W trap */ + +/* FUNCTIONS ****************************************************************/ + +.func KiSystemService +_KiSystemService: + + /* Enter the shared system call prolog */ + SYSCALL_PROLOG + + /* Jump to the actual handler */ + jmp SharedCode +.endfunc + +.func KiFastCallEntry +_KiFastCallEntry: + + /* Set FS to PCR */ + mov ecx, KGDT_R0_PCR + mov fs, cx + + /* Set DS/ES to Kernel Selector */ + mov ecx, KGDT_R0_DATA + mov ds, cx + mov es, cx + + /* Set the current stack to Kernel Stack */ + mov ecx, [fs:KPCR_TSS] + mov esp, ss:[ecx+KTSS_ESP0] + + /* Set up a fake INT Stack. */ + push KGDT_R3_DATA + RPL_MASK + push edx /* Ring 3 SS:ESP */ + pushf /* Ring 3 EFLAGS */ + push 2 /* Ring 0 EFLAGS */ + add edx, 8 /* Skip user parameter list */ + popf /* Set our EFLAGS */ + or dword ptr [esp], EFLAGS_INTERRUPT_MASK /* Re-enable IRQs in EFLAGS, to fake INT */ + push KGDT_R3_CODE + RPL_MASK + push KUSER_SHARED_SYSCALL_RET + + /* Setup the Trap Frame stack */ + push 0 + push ebp + push ebx + push esi + push edi + push KGDT_R3_TEB + RPL_MASK + + /* Save pointer to our PCR */ + mov ebx, [fs:KPCR_SELF] + + /* Get a pointer to the current thread */ + mov esi, [ebx+KPCR_CURRENT_THREAD] + + /* Set the exception handler chain terminator */ + push [ebx+KPCR_EXCEPTION_LIST] + mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1 + + /* Use the thread's stack */ + mov ebp, [esi+KTHREAD_INITIAL_STACK] + + /* Push previous mode */ + push UserMode + + /* Skip the other registers */ + sub esp, 0x48 + + /* Hack: it seems that on VMWare someone damages ES/DS on exit. Investigate! */ + mov dword ptr [esp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK + mov dword ptr [esp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK + + /* Make space for us on the stack */ + sub ebp, 0x29C + + /* Write the previous mode */ + mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], UserMode + + /* Sanity check */ + cmp ebp, esp + jnz BadStack + + /* Flush DR7 */ + and dword ptr [ebp+KTRAP_FRAME_DR7], 0 + + /* Check if the thread was being debugged */ + test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF + + /* Set the thread's trap frame */ + mov [esi+KTHREAD_TRAP_FRAME], ebp + + /* Save DR registers if needed */ + //jnz Dr_FastCallDrSave + + /* Set the trap frame debug header */ + SET_TF_DEBUG_HEADER + +#ifdef DBG // FIXME: Is this for GDB? Can it be moved in the stub? + /* + * We want to know the address from where the syscall stub was called. + * If PrevMode is KernelMode, that address is stored in our own (kernel) + * stack, at location KTRAP_FRAME_ESP. + * If we're coming from UserMode, we load the usermode stack pointer + * and go back two frames (first frame is the syscall stub, second call + * is the caller of the stub). + */ + mov edi, [ebp+KTRAP_FRAME_ESP] + test byte ptr [esi+KTHREAD_PREVIOUS_MODE], 0x01 + jz PrevWasKernelMode + mov edi, [edi+4] +PrevWasKernelMode: + mov [ebp+KTRAP_FRAME_DEBUGEIP], edi +#endif + + /* Enable interrupts */ + sti + +SharedCode: + + /* + * Find out which table offset to use. Converts 0x1124 into 0x10. + * The offset is related to the Table Index as such: Offset = TableIndex x 10 + */ + mov edi, eax + shr edi, SERVICE_TABLE_SHIFT + and edi, SERVICE_TABLE_MASK + mov ecx, edi + + /* Now add the thread's base system table to the offset */ + add edi, [esi+KTHREAD_SERVICE_TABLE] + + /* Get the true syscall ID and check it */ + mov ebx, eax + and eax, SERVICE_NUMBER_MASK + cmp eax, [edi+SERVICE_DESCRIPTOR_LIMIT] + + /* Invalid ID, try to load Win32K Table */ + jnb KiBBTUnexpectedRange + +#if 0 // <== Disabled for two reasons: We don't save TEB in 0x18, but KPCR. + // <== We don't have a KeGdiFlushUserBatch callback yet (needs to be + // sent through the PsInitializeWin32Callouts structure) + /* Check if this was Win32K */ + cmp ecx, SERVICE_TABLE_TEST + jnz NotWin32K + + /* Get the TEB */ + mov ecx, [fs:KPCR_TEB] + + /* Check if we should flush the User Batch */ + xor ebx, ebx + or ebx, [ecx+TEB_GDI_BATCH_COUNT] + jz NoWin32K + + /* Flush it */ + push edx + push eax + call [_KeGdiFlushUserBatch] + pop eax + pop edx +#endif + +NotWin32K: + /* Increase total syscall count */ + inc dword ptr fs:[KPCR_SYSTEM_CALLS] + +#ifdef DBG + /* Increase per-syscall count */ + mov ecx, [edi+SERVICE_DESCRIPTOR_COUNT] + jecxz NoCountTable + inc dword ptr [ecx+eax*4] +#endif + + /* Users's current stack frame pointer is source */ +NoCountTable: + mov esi, edx + + /* Allocate room for argument list from kernel stack */ + mov ebx, [edi+SERVICE_DESCRIPTOR_NUMBER] + xor ecx, ecx + mov cl, [eax+ebx] + + /* Get pointer to function */ + mov edi, [edi+SERVICE_DESCRIPTOR_BASE] + mov ebx, [edi+eax*4] + + /* Allocate space on our stack */ + sub esp, ecx + + /* + * Copy the arguments from the user stack to our stack + * FIXME: This needs to be probed with MmSystemRangeStart + */ + shr ecx, 2 + mov edi, esp + rep movsd + +#ifdef DBG + + /* Make sure this isn't a user-mode call at elevated IRQL */ + test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK + jz SkipCheck + call _KeGetCurrentIrql@0 + or al, al + jnz InvalidIrql + + /* + * The following lines are for the benefit of GDB. It will see the return + * address of the "call ebx" below, find the last label before it and + * thinks that that's the start of the function. It will then check to see + * if it starts with a standard function prolog (push ebp, mov ebp,esp). + * When that standard function prolog is not found, it will stop the + * stack backtrace. Since we do want to backtrace into usermode, let's + * make GDB happy and create a standard prolog. + */ +SkipCheck: +KiSystemService: + push ebp + mov ebp,esp + pop ebp +#endif + + /* Do the System Call */ + call ebx + +#ifdef DBG + /* Make sure the user-mode call didn't return at elevated IRQL */ + test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK + jz SkipCheck2 + mov esi, eax /* We need to save the syscall's return val */ + call _KeGetCurrentIrql@0 + or al, al + jnz InvalidIrql + mov eax, esi /* Restore it */ + + /* Get our temporary current thread pointer for sanity check */ + mov ecx, fs:[KPCR_CURRENT_THREAD] + + /* Make sure that we are not attached and that APCs are not disabled */ + mov dl, [ecx+KTHREAD_APC_STATE_INDEX] + or dl, dl + jnz InvalidIndex + mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE] + or edx, edx + jnz InvalidIndex +#endif + +SkipCheck2: + + /* Deallocate the kernel stack frame */ + mov esp, ebp + +KeReturnFromSystemCall: + + /* Get the Current Thread */ + mov ecx, [fs:KPCR_CURRENT_THREAD] + + /* Restore the old trap frame pointer */ + mov edx, [ebp+KTRAP_FRAME_EDX] + mov [ecx+KTHREAD_TRAP_FRAME], edx +.endfunc + +.func KiServiceExit +_KiServiceExit: + /* Disable interrupts */ + cli + + /* Check for, and deliver, User-Mode APCs if needed */ + CHECK_FOR_APC_DELIVER 1 + + /* Hack for VMWare: Sometimes ES/DS seem to be invalid when returning to user-mode. Investigate! */ + mov es, [ebp+KTRAP_FRAME_ES] + mov ds, [ebp+KTRAP_FRAME_DS] + + /* Exit and cleanup */ + TRAP_EPILOG FromSystemCall, DoRestorePreviousMode, DoNotRestoreSegments, DoNotRestoreVolatiles, DoRestoreEverything +.endfunc + +KiBBTUnexpectedRange: + + /* If this isn't a Win32K call, fail */ + cmp ecx, 0x10 + jne InvalidCall + + /* Set up Win32K Table */ + push edx + push ebx + call _PsConvertToGuiThread@0 + + /* FIXME: Handle failure */ + pop eax + pop edx + + /* Reset trap frame address */ + mov ebp, esp + mov [esi+KTHREAD_TRAP_FRAME], ebp + + /* Try the Call again */ + jmp SharedCode + +InvalidCall: + + /* Invalid System Call */ + mov eax, STATUS_INVALID_SYSTEM_SERVICE + jmp KeReturnFromSystemCall + +BadStack: + + /* Restore ESP0 stack */ + mov ecx, [fs:KPCR_TSS] + mov esp, ss:[ecx+KTSS_ESP0] + + /* Generate V86M Stack for Trap 6 */ + push 0 + push 0 + push 0 + push 0 + + /* Generate interrupt stack for Trap 6 */ + push KGDT_R3_DATA + RPL_MASK + push 0 + push 0x20202 + push KGDT_R3_CODE + RPL_MASK + push 0 + jmp _KiTrap6 + +#ifdef DBG +InvalidIrql: + /* Save current IRQL */ + push fs:[KPCR_IRQL] + + /* Set us at passive */ + mov dword ptr fs:[KPCR_IRQL], 0 + cli + + /* Bugcheck */ + push 0 + push 0 + push eax + push ebx + push IRQL_GT_ZERO_AT_SYSTEM_SERVICE + call _KeBugCheckEx@20 + +InvalidIndex: + + /* Get the index and APC state */ + movzx eax, byte ptr [ecx+KTHREAD_APC_STATE_INDEX] + mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE] + + /* Bugcheck */ + push 0 + push edx + push eax + push ebx + push APC_INDEX_MISMATCH + call _KeBugCheckEx@20 + ret +#endif + +.func KiServiceExit2 +_KiServiceExit2: + + /* Disable interrupts */ + cli + + /* Check for, and deliver, User-Mode APCs if needed */ + CHECK_FOR_APC_DELIVER 0 + + /* Exit and cleanup */ + TRAP_EPILOG NotFromSystemCall, DoRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything +.endfunc + +.func Kei386EoiHelper@0 +_Kei386EoiHelper@0: + + /* Disable interrupts */ + cli + + /* Check for, and deliver, User-Mode APCs if needed */ + CHECK_FOR_APC_DELIVER 0 + + /* Exit and cleanup */ + TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything +.endfunc + +V86_Exit: + /* Move to EDX position */ + add esp, KTRAP_FRAME_EDX + + /* Restore volatiles */ + pop edx + pop ecx + pop eax + + /* Move to non-volatiles */ + lea esp, [ebp+KTRAP_FRAME_EDI] + pop edi + pop esi + pop ebx + pop ebp + + /* Skip error code and return */ + add esp, 4 + iret + +AbiosExit: + /* Not yet supported */ + int 3 + +_KiDebugService: + + /* Push error code */ + push 0 + + /* Enter trap */ + TRAP_PROLOG(kids) + + /* Increase EIP so we skip the INT3 */ + //inc dword ptr [ebp+KTRAP_FRAME_EIP] + + /* Call debug service dispatcher */ + mov eax, [ebp+KTRAP_FRAME_EAX] + mov ecx, [ebp+KTRAP_FRAME_ECX] + mov edx, [ebp+KTRAP_FRAME_EAX] + + /* Check for V86 mode */ + test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK + jnz NotUserMode + + /* Check if this is kernel or user-mode */ + test byte ptr [ebp+KTRAP_FRAME_CS], 1 + jz CallDispatch + cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK + jnz NotUserMode + + /* Re-enable interrupts */ +VdmProc: + sti + + /* Call the debug routine */ +CallDispatch: + mov esi, ecx + mov edi, edx + mov edx, eax + mov ecx, 3 + push edi + push esi + push edx + call _KdpServiceDispatcher@12 + +NotUserMode: + + /* Get the current process */ + mov ebx, [fs:KPCR_CURRENT_THREAD] + mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS] + + /* Check if this is a VDM Process */ + //cmp dword ptr [ebx+KPROCESS_VDM_OBJECTS], 0 + //jz VdmProc + + /* Exit through common routine */ + jmp _Kei386EoiHelper@0 + +_NtRaiseException@12: + + /* NOTE: We -must- be called by Zw* to have the right frame! */ + /* Push the stack frame */ + push ebp + + /* Get the current thread and restore its trap frame */ + mov ebx, [fs:KPCR_CURRENT_THREAD] + mov edx, [ebp+KTRAP_FRAME_EDX] + mov [ebx+KTHREAD_TRAP_FRAME], edx + + /* Set up stack frame */ + mov ebp, esp + + /* Get the Trap Frame in EBX */ + mov ebx, [ebp+0] + + /* Get the exception list and restore */ + mov eax, [ebx+KTRAP_FRAME_EXCEPTION_LIST] + mov [fs:KPCR_EXCEPTION_LIST], eax + + /* Get the parameters */ + mov edx, [ebp+16] /* Search frames */ + mov ecx, [ebp+12] /* Context */ + mov eax, [ebp+8] /* Exception Record */ + + /* Raise the exception */ + push edx + push ebx + push 0 + push ecx + push eax + call _KiRaiseException@20 + + /* Restore trap frame in EBP */ + pop ebp + mov esp, ebp + + /* Check the result */ + or eax, eax + jz _KiServiceExit2 + + /* Restore debug registers too */ + jmp _KiServiceExit + +_NtContinue@8: + + /* NOTE: We -must- be called by Zw* to have the right frame! */ + /* Push the stack frame */ + push ebp + + /* Get the current thread and restore its trap frame */ + mov ebx, [fs:KPCR_CURRENT_THREAD] + mov edx, [ebp+KTRAP_FRAME_EDX] + mov [ebx+KTHREAD_TRAP_FRAME], edx + + /* Set up stack frame */ + mov ebp, esp + + /* Save the parameters */ + mov eax, [ebp+0] + mov ecx, [ebp+8] + + /* Call KiContinue */ + push eax + push 0 + push ecx + call _KiContinue@12 + + /* Check if we failed (bad context record) */ + or eax, eax + jnz Error + + /* Check if test alert was requested */ + cmp dword ptr [ebp+12], 0 + je DontTest + + /* Test alert for the thread */ + mov al, [ebx+KTHREAD_PREVIOUS_MODE] + push eax + call _KeTestAlertThread@4 + +DontTest: + /* Return to previous context */ + pop ebp + mov esp, ebp + jmp _KiServiceExit2 + +Error: + pop ebp + mov esp, ebp + jmp _KiServiceExit -.globl _KiTrap0 _KiTrap0: /* Push error code */ push 0 @@ -46,7 +640,6 @@ _KiTrap0: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrap1 _KiTrap1: /* Push error code */ push 0 @@ -67,7 +660,6 @@ _KiTrap1: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrap2 _KiTrap2: /* Push error code */ push 0 @@ -88,7 +680,6 @@ _KiTrap2: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrap3 _KiTrap3: /* Push error code */ push 0 @@ -109,7 +700,6 @@ _KiTrap3: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrap4 _KiTrap4: /* Push error code */ push 0 @@ -130,7 +720,6 @@ _KiTrap4: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrap5 _KiTrap5: /* Push error code */ push 0 @@ -151,7 +740,6 @@ _KiTrap5: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrap6 _KiTrap6: /* Push error code */ push 0 @@ -172,7 +760,6 @@ _KiTrap6: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrap7 _KiTrap7: /* Push error code */ push 0 @@ -193,12 +780,10 @@ _KiTrap7: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrap8 _KiTrap8: call _KiDoubleFaultHandler iret -.globl _KiTrap9 _KiTrap9: /* Push error code */ push 0 @@ -219,7 +804,6 @@ _KiTrap9: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrap10 _KiTrap10: /* Enter trap */ TRAP_PROLOG(10) @@ -237,7 +821,6 @@ _KiTrap10: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrap11 _KiTrap11: /* Enter trap */ TRAP_PROLOG(11) @@ -255,7 +838,6 @@ _KiTrap11: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrap12 _KiTrap12: /* Enter trap */ TRAP_PROLOG(12) @@ -273,7 +855,6 @@ _KiTrap12: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrap13 _KiTrap13: /* Enter trap */ TRAP_PROLOG(13) @@ -291,7 +872,6 @@ _KiTrap13: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrap14 _KiTrap14: /* Enter trap */ TRAP_PROLOG(14) @@ -309,7 +889,6 @@ _KiTrap14: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrap15 _KiTrap15: /* Push error code */ push 0 @@ -330,7 +909,6 @@ _KiTrap15: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrap16 _KiTrap16: /* Push error code */ push 0 @@ -351,7 +929,6 @@ _KiTrap16: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrap17 _KiTrap17: /* Push error code */ push 0 @@ -372,7 +949,6 @@ _KiTrap17: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrap18 _KiTrap18: /* Push error code */ push 0 @@ -393,7 +969,6 @@ _KiTrap18: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrap19 _KiTrap19: /* Push error code */ push 0 @@ -414,7 +989,6 @@ _KiTrap19: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiTrapUnknown _KiTrapUnknown: /* Push error code */ push 0 @@ -429,58 +1003,3 @@ _KiTrapUnknown: jne _Kei386EoiHelper@0 jmp _KiV86Complete -.globl _KiCoprocessorError@0 -_KiCoprocessorError@0: - - /* Get the NPX Thread's Initial stack */ - mov eax, [fs:KPCR_NPX_THREAD] - mov eax, [eax+KTHREAD_INITIAL_STACK] - - /* Make space for the FPU Save area */ - sub eax, SIZEOF_FX_SAVE_AREA - - /* Set the CR0 State */ - mov dword ptr [eax+FN_CR0_NPX_STATE], 8 - - /* Update it */ - mov eax, cr0 - or eax, 8 - mov cr0, eax - - /* Return to caller */ - ret - -.globl _Ki386AdjustEsp0@4 -_Ki386AdjustEsp0@4: - - /* Get the current thread */ - mov eax, [fs:KPCR_CURRENT_THREAD] - - /* Get trap frame and stack */ - mov edx, [esp+4] - mov eax, [eax+KTHREAD_INITIAL_STACK] - - /* Check if V86 */ - test dword ptr [edx+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK - jnz NoAdjust - - /* Bias the stack */ - sub eax, KTRAP_FRAME_V86_GS - KTRAP_FRAME_SS - -NoAdjust: - /* Skip FX Save Area */ - sub eax, SIZEOF_FX_SAVE_AREA - - /* Disable interrupts */ - pushf - cli - - /* Adjust ESP0 */ - mov edx, [fs:KPCR_TSS] - mov ss:[edx+KTSS_ESP0], eax - - /* Enable interrupts and return */ - popf - ret 4 - -/* EOF */ diff --git a/reactos/ntoskrnl/ntoskrnl.xml b/reactos/ntoskrnl/ntoskrnl.xml index 11c5aba5b07..ecfc96f1006 100644 --- a/reactos/ntoskrnl/ntoskrnl.xml +++ b/reactos/ntoskrnl/ntoskrnl.xml @@ -35,7 +35,6 @@ irqhand.s kernel.c ldt.c - syscall.S thread.c trap.s tss.c