- 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
This commit is contained in:
Alex Ionescu 2006-01-17 06:36:35 +00:00
parent 93c504407b
commit f2414f3c2c
5 changed files with 669 additions and 678 deletions

View file

@ -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

View file

@ -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

View file

@ -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 <asm.h>
#include <internal/i386/asmmacro.S>
.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

View file

@ -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 <asm.h>
#include <internal/i386/asmmacro.S>
.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 */

View file

@ -35,7 +35,6 @@
<file>irqhand.s</file>
<file>kernel.c</file>
<file>ldt.c</file>
<file>syscall.S</file>
<file>thread.c</file>
<file>trap.s</file>
<file>tss.c</file>