Author: sir_richard Date: Tue Jan 19 07:34:15 2010 New Revision: 45141
URL: http://svn.reactos.org/svn/reactos?rev=45141&view=rev Log: [NTOS]: Implement KiServiceExit2, C Version. This is used for exiting to user-mode with full state restore (as in NtContinue, thread startup, NtRaiseException...). [NTOS]: Implement system service exit (for system calls or KiServiceExit2) in KiExitTrap. Both iret (for user calls), jmp (for kernel calls) and sysexit (for user fast calls) are implemented. [NTOS]: Implement KiThreadStartup in C instead of ASM. It is the first caller of the new KiServiceExit2. Threads now start up in C!
Modified: trunk/reactos/ntoskrnl/include/internal/i386/ke.h trunk/reactos/ntoskrnl/include/internal/ke.h trunk/reactos/ntoskrnl/include/internal/trap_x.h trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S trunk/reactos/ntoskrnl/ke/i386/thrdini.c trunk/reactos/ntoskrnl/ke/i386/traphdlr.c
Modified: trunk/reactos/ntoskrnl/include/internal/i386/ke.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/i... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/i386/ke.h [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/include/internal/i386/ke.h [iso-8859-1] Tue Jan 19 07:34:15 2010 @@ -5,8 +5,6 @@
#include "intrin_i.h" #include "v86m.h" - -extern ULONG Ke386CacheAlignment;
// // Thread Dispatcher Header DebugActive Mask @@ -288,15 +286,9 @@ NTAPI KiGetFeatureBits(VOID);
-#ifdef _NTOSKRNL_ /* FIXME: Move flags above to NDK instead of here */ -VOID -NTAPI -KiThreadStartup(PKSYSTEM_ROUTINE SystemRoutine, - PKSTART_ROUTINE StartRoutine, - PVOID StartContext, - BOOLEAN UserThread, - KTRAP_FRAME TrapFrame); -#endif +VOID +NTAPI +KiThreadStartup(VOID);
NTSTATUS NTAPI @@ -438,6 +430,8 @@ extern ULONG KiMXCsrMask; extern ULONG KeI386CpuType; extern ULONG KeI386CpuStep; +extern ULONG Ke386CacheAlignment; +extern ULONG KiFastSystemCallDisable; extern UCHAR KiDebugRegisterTrapOffsets[9]; extern UCHAR KiDebugRegisterContextOffsets[9]; extern VOID __cdecl KiTrap02(VOID);
Modified: trunk/reactos/ntoskrnl/include/internal/ke.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/k... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/ke.h [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/include/internal/ke.h [iso-8859-1] Tue Jan 19 07:34:15 2010 @@ -932,6 +932,12 @@ VOID );
+VOID +FASTCALL +KiServiceExit2( + IN PKTRAP_FRAME TrapFrame +); + #ifndef HAL_INTERRUPT_SUPPORT_IN_C VOID NTAPI
Modified: trunk/reactos/ntoskrnl/include/internal/trap_x.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/t... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/trap_x.h [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/include/internal/trap_x.h [iso-8859-1] Tue Jan 19 07:34:15 2010 @@ -207,6 +207,93 @@
FORCEINLINE VOID +KiSystemCallReturn(IN PKTRAP_FRAME TrapFrame) +{ + /* Restore nonvolatiles, EAX, and do a "jump" back to the kernel caller */ + __asm__ __volatile__ + ( + "movl %0, %%esp\n" + "movl %c[b](%%esp), %%ebx\n" + "movl %c[s](%%esp), %%esi\n" + "movl %c[i](%%esp), %%edi\n" + "movl %c[p](%%esp), %%ebp\n" + "movl %c[a](%%esp), %%eax\n" + "movl %c[e](%%esp), %%edx\n" + "addl $%c[v],%%esp\n" /* A WHOLE *KERNEL* frame since we're not IRET'ing */ + "jmp *%%edx\n" + : + : "r"(TrapFrame), + [b] "i"(KTRAP_FRAME_EBX), + [s] "i"(KTRAP_FRAME_ESI), + [i] "i"(KTRAP_FRAME_EDI), + [p] "i"(KTRAP_FRAME_EBP), + [a] "i"(KTRAP_FRAME_EAX), + [e] "i"(KTRAP_FRAME_EIP), + [v] "i"(KTRAP_FRAME_ESP) + : "%esp" + ); +} + +FORCEINLINE +VOID +KiSystemCallTrapReturn(IN PKTRAP_FRAME TrapFrame) +{ + /* Regular interrupt exit, but we only restore EAX as a volatile */ + __asm__ __volatile__ + ( + "movl %0, %%esp\n" + "movl %c[b](%%esp), %%ebx\n" + "movl %c[s](%%esp), %%esi\n" + "movl %c[i](%%esp), %%edi\n" + "movl %c[p](%%esp), %%ebp\n" + "movl %c[a](%%esp), %%eax\n" + "addl $%c[e],%%esp\n" + "iret\n" + : + : "r"(TrapFrame), + [b] "i"(KTRAP_FRAME_EBX), + [s] "i"(KTRAP_FRAME_ESI), + [i] "i"(KTRAP_FRAME_EDI), + [p] "i"(KTRAP_FRAME_EBP), + [a] "i"(KTRAP_FRAME_EAX), + [e] "i"(KTRAP_FRAME_EIP) + : "%esp" + ); +} + +FORCEINLINE +VOID +KiSystemCallSysExitReturn(IN PKTRAP_FRAME TrapFrame) +{ + /* Restore nonvolatiles, EAX, and do a SYSEXIT back to the user caller */ + __asm__ __volatile__ + ( + "movl %0, %%esp\n" + "movl %c[s](%%esp), %%esi\n" + "movl %c[b](%%esp), %%ebx\n" + "movl %c[i](%%esp), %%edi\n" + "movl %c[p](%%esp), %%ebp\n" + "movl %c[a](%%esp), %%eax\n" + "movl %c[e](%%esp), %%edx\n" /* SYSEXIT says EIP in EDX */ + "movl %c[x](%%esp), %%ecx\n" /* SYSEXIT says ESP in ECX */ + "addl $%c[v],%%esp\n" /* A WHOLE *USER* frame since we're not IRET'ing */ + "sti\nsysexit\n" + : + : "r"(TrapFrame), + [b] "i"(KTRAP_FRAME_EBX), + [s] "i"(KTRAP_FRAME_ESI), + [i] "i"(KTRAP_FRAME_EDI), + [p] "i"(KTRAP_FRAME_EBP), + [a] "i"(KTRAP_FRAME_EAX), + [e] "i"(KTRAP_FRAME_EIP), + [x] "i"(KTRAP_FRAME_ESP), + [v] "i"(KTRAP_FRAME_V86_ES) + : "%esp" + ); +} + +FORCEINLINE +VOID KiTrapReturn(IN PKTRAP_FRAME TrapFrame) { /* Regular interrupt exit */
Modified: trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/ctxswitch.... ============================================================================== --- trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S [iso-8859-1] Tue Jan 19 07:34:15 2010 @@ -249,77 +249,6 @@ .endfunc
/*++ - * KiThreadStartup - * - * The KiThreadStartup routine is the beginning of any thread. - * - * Params: - * SystemRoutine - Pointer to the System Startup Routine. Either - * PspUserThreadStartup or PspSystemThreadStartup - * - * StartRoutine - For Kernel Threads only, specifies the starting execution - * point of the new thread. - * - * StartContext - For Kernel Threads only, specifies a pointer to variable - * context data to be sent to the StartRoutine above. - * - * UserThread - Indicates whether or not this is a user thread. This tells - * us if the thread has a context or not. - * - * TrapFrame - Pointer to the KTHREAD to which the caller wishes to - * switch from. - * - * Returns: - * Should never return for a system thread. Returns through the System Call - * Exit Dispatcher for a user thread. - * - * Remarks: - * If a return from a system thread is detected, a bug check will occur. - * - *--*/ - .func KiThreadStartup@156 -.globl _KiThreadStartup@156 -_KiThreadStartup@156: - - /* - * Clear all the non-volatile registers, so the thread won't be tempted to - * expect any static data (like some badly coded usermode/win9x apps do) - */ - xor ebx, ebx - xor esi, esi - xor edi, edi - xor ebp, ebp - - /* It's now safe to go to APC */ - mov ecx, APC_LEVEL - call @KfLowerIrql@4 - - /* - * Call the System Routine which is right on our stack now. - * After we pop the pointer, the Start Routine/Context will be on the - * stack, as parameters to the System Routine - */ - pop eax - call eax - - /* The thread returned... was it a user-thread? */ - pop ecx - or ecx, ecx - jz BadThread - - /* Yes it was, set our trapframe for the System Call Exit Dispatcher */ - mov ebp, esp - - /* Exit back to user-mode */ - jmp _KiServiceExit2 - -BadThread: - - /* A system thread returned...this is very bad! */ - int 3 -.endfunc - -/*++ * KiSwapContextInternal * * The KiSwapContextInternal routine switches context to another thread.
Modified: trunk/reactos/ntoskrnl/ke/i386/thrdini.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/thrdini.c?... ============================================================================== --- trunk/reactos/ntoskrnl/ke/i386/thrdini.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/i386/thrdini.c [iso-8859-1] Tue Jan 19 07:34:15 2010 @@ -43,6 +43,32 @@ } KKINIT_FRAME, *PKKINIT_FRAME;
/* FUNCTIONS *****************************************************************/ + +VOID +NTAPI +KiThreadStartup(VOID) +{ + PKTRAP_FRAME TrapFrame; + PKSTART_FRAME StartFrame; + PKUINIT_FRAME InitFrame; + + /* Get the start and trap frames */ + InitFrame = KeGetCurrentThread()->KernelStack; + StartFrame = &InitFrame->StartFrame; + TrapFrame = &InitFrame->TrapFrame; + + /* Lower to APC level */ + KfLowerIrql(APC_LEVEL); + + /* Call the system routine */ + StartFrame->SystemRoutine(StartFrame->StartRoutine, StartFrame->StartContext); + + /* If we returned, we better be a user thread */ + if (!StartFrame->UserThread) DbgBreakPoint(); + + /* Exit to user-mode */ + KiServiceExit2(TrapFrame); +}
VOID NTAPI
Modified: trunk/reactos/ntoskrnl/ke/i386/traphdlr.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/traphdlr.c... ============================================================================== --- trunk/reactos/ntoskrnl/ke/i386/traphdlr.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/i386/traphdlr.c [iso-8859-1] Tue Jan 19 07:34:15 2010 @@ -62,27 +62,30 @@ /* Check if the previous mode must be restored */ if (__builtin_expect(!SkipBits.SkipPreviousMode, 0)) /* More INTS than SYSCALLs */ { + /* Restore it */ + KeGetCurrentThread()->PreviousMode = TrapFrame->PreviousPreviousMode; + } + + /* Check if there are active debug registers */ + if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0)) + { /* Not handled yet */ UNIMPLEMENTED; + DbgBreakPoint(); + KiDumpTrapFrame(TrapFrame); while (TRUE); } - - /* Check if there are active debug registers */ - if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0)) + + /* Check if this was a V8086 trap */ + if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 0)) KiTrapReturn(TrapFrame); + + /* Check if the trap frame was edited */ + if (__builtin_expect(!(TrapFrame->SegCs & FRAME_EDITED), 0)) { /* Not handled yet */ UNIMPLEMENTED; - while (TRUE); - } - - /* Check if this was a V8086 trap */ - if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 0)) KiTrapReturn(TrapFrame); - - /* Check if the trap frame was edited */ - if (__builtin_expect(!(TrapFrame->SegCs & FRAME_EDITED), 0)) - { - /* Not handled yet */ - UNIMPLEMENTED; + KiDumpTrapFrame(TrapFrame); + DbgBreakPoint(); while (TRUE); }
@@ -114,13 +117,37 @@ /* Check for system call -- a system call skips volatiles! */ if (__builtin_expect(SkipBits.SkipVolatiles, 0)) /* More INTs than SYSCALLs */ { - /* Not handled yet */ - /* - * When we do the system call handler through this path, we need - * to have some sort to restore the kernel EAX instead of pushing - * back the user EAX. We'll figure it out... - */ - DPRINT1("Warning: caller doesn't want volatiles restored\n"); + /* Kernel call or user call? */ + if (__builtin_expect(KiUserTrap(TrapFrame), 1)) /* More Ring 3 than 0 */ + { + /* Is SYSENTER supported and/or enabled, or are we stepping code? */ + if (__builtin_expect((KiFastSystemCallDisable) || + (TrapFrame->EFlags & EFLAGS_TF), 0)) + { + /* Exit normally */ + KiSystemCallTrapReturn(TrapFrame); + } + else + { + /* Restore user FS */ + Ke386SetFs(KGDT_R3_TEB | RPL_MASK); + + /* Remove interrupt flag */ + TrapFrame->EFlags &= ~EFLAGS_INTERRUPT_MASK; + __writeeflags(TrapFrame->EFlags); + + /* Exit through SYSEXIT */ + KiSystemCallSysExitReturn(TrapFrame); + } + } + else + { + /* Restore EFLags */ + __writeeflags(TrapFrame->EFlags); + + /* Call is kernel, so do a jump back since this wasn't a real INT */ + KiSystemCallReturn(TrapFrame); + } } else { @@ -185,6 +212,20 @@
/* Now exit the trap for real */ KiExitTrap(TrapFrame, KTE_SKIP_PM_BIT); +} + +VOID +FASTCALL +KiServiceExit2(IN PKTRAP_FRAME TrapFrame) +{ + /* Disable interrupts until we return */ + _disable(); + + /* Check for APC delivery */ + KiCheckForApcDelivery(TrapFrame); + + /* Now exit the trap for real */ + KiExitTrap(TrapFrame, 0); }
/* TRAP ENTRY CODE ************************************************************/