[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!

svn path=/trunk/; revision=45141
This commit is contained in:
Sir Richard 2010-01-19 06:34:15 +00:00
parent bf8b9467dc
commit aba18024bd
6 changed files with 173 additions and 90 deletions

View file

@ -6,8 +6,6 @@
#include "intrin_i.h"
#include "v86m.h"
extern ULONG Ke386CacheAlignment;
//
// Thread Dispatcher Header DebugActive Mask
//
@ -288,15 +286,9 @@ ULONG
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
KiThreadStartup(VOID);
NTSTATUS
NTAPI
@ -438,6 +430,8 @@ extern ULONG KeI386FxsrPresent;
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);

View file

@ -932,6 +932,12 @@ KiEndUnexpectedRange(
VOID
);
VOID
FASTCALL
KiServiceExit2(
IN PKTRAP_FRAME TrapFrame
);
#ifndef HAL_INTERRUPT_SUPPORT_IN_C
VOID
NTAPI

View file

@ -205,6 +205,93 @@ KiDispatchException2Args(IN NTSTATUS Code,
KiDispatchExceptionFromTrapFrame(Code, Address, 2, P1, P2, 0, TrapFrame);
}
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)

View file

@ -248,77 +248,6 @@ Return:
.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
*

View file

@ -44,6 +44,32 @@ typedef struct _KKINIT_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
KiInitializeContextThread(IN PKTHREAD Thread,

View file

@ -62,9 +62,8 @@ KiExitTrap(IN PKTRAP_FRAME TrapFrame,
/* Check if the previous mode must be restored */
if (__builtin_expect(!SkipBits.SkipPreviousMode, 0)) /* More INTS than SYSCALLs */
{
/* Not handled yet */
UNIMPLEMENTED;
while (TRUE);
/* Restore it */
KeGetCurrentThread()->PreviousMode = TrapFrame->PreviousPreviousMode;
}
/* Check if there are active debug registers */
@ -72,6 +71,8 @@ KiExitTrap(IN PKTRAP_FRAME TrapFrame,
{
/* Not handled yet */
UNIMPLEMENTED;
DbgBreakPoint();
KiDumpTrapFrame(TrapFrame);
while (TRUE);
}
@ -83,6 +84,8 @@ KiExitTrap(IN PKTRAP_FRAME TrapFrame,
{
/* Not handled yet */
UNIMPLEMENTED;
KiDumpTrapFrame(TrapFrame);
DbgBreakPoint();
while (TRUE);
}
@ -114,13 +117,37 @@ KiExitTrap(IN PKTRAP_FRAME TrapFrame,
/* 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
{
@ -187,6 +214,20 @@ KiEoiHelper(IN PKTRAP_FRAME TrapFrame)
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 ************************************************************/
VOID