mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
Correct NtW32call to call correct kernel function, add placeholder for SEH, implement KeUserModeCallback (right now a copy of the old code). Part I of an incomplete W32Callback rewrite, just to set up the groundwork to make testing easier. Might look ugly/messy now but it'll be clean soon
svn path=/trunk/; revision=14199
This commit is contained in:
parent
52a70e745d
commit
396ff5690c
9 changed files with 297 additions and 165 deletions
|
@ -111,6 +111,7 @@ OBJECTS_KE = \
|
|||
ke/sem.o \
|
||||
ke/spinlock.o \
|
||||
ke/timer.o \
|
||||
ke/usercall.o \
|
||||
ke/wait.o
|
||||
|
||||
# Memory Manager (Mm)
|
||||
|
@ -230,8 +231,7 @@ OBJECTS_PS = \
|
|||
ps/security.o \
|
||||
ps/suspend.o \
|
||||
ps/thread.o \
|
||||
ps/win32.o \
|
||||
ps/w32call.o
|
||||
ps/win32.o
|
||||
|
||||
# Executive Subsystem (Ex)
|
||||
OBJECTS_EX = \
|
||||
|
|
|
@ -20,6 +20,11 @@
|
|||
#ifndef __NTOSKRNL_INCLUDE_INTERNAL_I386_FPU_H
|
||||
#define __NTOSKRNL_INCLUDE_INTERNAL_I386_FPU_H
|
||||
|
||||
#define FN_CONTROL_WORD 0x0
|
||||
#define FN_STATUS_WORD 0x4
|
||||
#define FN_TAG_WORD 0x8
|
||||
#define FN_DATA_SELECTOR 0x18
|
||||
#define FN_CR0_NPX_STATE 0x20C
|
||||
#define SIZEOF_FX_SAVE_AREA 528
|
||||
|
||||
#ifndef __ASM__
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#define KPCR_BASE 0xFF000000
|
||||
|
||||
#define KPCR_EXCEPTION_LIST 0x0
|
||||
#define KPCR_INITIAL_STACK 0x4
|
||||
#define KPCR_SELF 0x1C
|
||||
#define KPCR_TSS 0x40
|
||||
#define KPCR_CURRENT_THREAD 0x124
|
||||
|
|
|
@ -66,6 +66,6 @@ VOID KdInitSystem(ULONG Reserved, PLOADER_PARAMETER_BLOCK LoaderBlock);
|
|||
/*
|
||||
*
|
||||
*/
|
||||
#define MM_STACK_SIZE (3*4096)
|
||||
#define MM_STACK_SIZE (12*4096)
|
||||
|
||||
#endif /* INCLUDE_INTERNAL_NTOSKRNL_H */
|
||||
|
|
59
reactos/ntoskrnl/ke/i386/usercall.S
Normal file
59
reactos/ntoskrnl/ke/i386/usercall.S
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/ke/i386s/usercall.S
|
||||
* PURPOSE: User-Mode callbacks and return.
|
||||
*
|
||||
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
|
||||
*/
|
||||
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
||||
#include <roscfg.h>
|
||||
#include <internal/i386/segment.h>
|
||||
#include <internal/i386/ke.h>
|
||||
#include <internal/i386/fpu.h>
|
||||
#include <internal/ps.h>
|
||||
#include <ntos/tss.h>
|
||||
#include <internal/ntoskrnl.h>
|
||||
.intel_syntax noprefix
|
||||
|
||||
/* GLOBALS ****************************************************************/
|
||||
.extern PVOID _SystemDllCallbackDispatcher
|
||||
|
||||
#define CBSTACK_BUFFER_ADDRESS 0x20
|
||||
#define CBSTACK_BUFFER_LENGTH 0x24
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
||||
/*++
|
||||
* KiSwitchToUserMode
|
||||
*
|
||||
* The KiSwitchToUserMode routine sets up a Trap Frame and a Callback stack
|
||||
* for the purpose of switching to user mode. The actual final jump is done
|
||||
* by KiServiceExit which will treat this as a syscall return.
|
||||
*
|
||||
* Params:
|
||||
* OutputBuffer - Pointer to a caller-allocated buffer where to receive
|
||||
* the return data from the user-mode function
|
||||
*
|
||||
* OutputLength - Size of the Output Buffer described above.
|
||||
*
|
||||
* Returns:
|
||||
* Jumps into KiServiceExit.
|
||||
*
|
||||
* Remarks:
|
||||
* If there is not enough Kernel Stack space, the routine will increase the
|
||||
* Kernel Stack.
|
||||
*
|
||||
* User mode execution resumes at ntdll!KiUserCallbackDispatcher.
|
||||
*
|
||||
* This call MUST be paired by interrupt 0x2B or NtCallbackReturn.
|
||||
*
|
||||
*--*/
|
||||
.globl _KiSwitchToUserMode@8
|
||||
.func KiSwitchToUserMode@8
|
||||
_KiSwitchToUserMode@8:
|
||||
|
||||
.endfunc
|
||||
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/* $Id$
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/ke/i386/usercall.c
|
||||
* PURPOSE: 2E interrupt handler
|
||||
*
|
||||
* PROGRAMMERS: David Welch (david.welch@seh.ox.ac.uk)
|
||||
*/
|
||||
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
KeUserModeCallback(
|
||||
IN ULONG FunctionID,
|
||||
IN PVOID InputBuffer,
|
||||
IN ULONG InputLength,
|
||||
OUT PVOID *OutputBuffer,
|
||||
OUT PULONG OutputLength
|
||||
)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* EOF */
|
|
@ -1,37 +1,28 @@
|
|||
/* $Id$
|
||||
*
|
||||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/ps/w32call.c
|
||||
* PURPOSE: Thread managment
|
||||
* FILE: ntoskrnl/ke/usercall.c
|
||||
* PURPOSE: User-Mode callbacks. Portable part.
|
||||
*
|
||||
* PROGRAMMERS: David Welch (welch@mcmail.com)
|
||||
* Phillip Susi
|
||||
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
*
|
||||
* All of the routines that manipulate the thread queue synchronize on
|
||||
* a single spinlock
|
||||
*
|
||||
*/
|
||||
|
||||
/* INCLUDES ****************************************************************/
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
#if defined(__GNUC__)
|
||||
/* void * alloca(size_t size); */
|
||||
#elif defined(_MSC_VER)
|
||||
void* _alloca(size_t size);
|
||||
#else
|
||||
#error Unknown compiler for alloca intrinsic stack allocation "function"
|
||||
#endif
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
/* TYPES *******************************************************************/
|
||||
#if ALEX_CB_REWRITE
|
||||
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
KiSwitchToUserMode(IN PVOID *OutputBuffer,
|
||||
IN PULONG OutputLength);
|
||||
|
||||
#else
|
||||
|
||||
typedef struct _NTW32CALL_SAVED_STATE
|
||||
{
|
||||
|
@ -55,8 +46,6 @@ typedef struct
|
|||
KSPIN_LOCK CallbackStackListLock;
|
||||
static LIST_ENTRY CallbackStackListHead;
|
||||
|
||||
/* FUNCTIONS ***************************************************************/
|
||||
|
||||
VOID INIT_FUNCTION
|
||||
PsInitialiseW32Call(VOID)
|
||||
{
|
||||
|
@ -64,90 +53,6 @@ PsInitialiseW32Call(VOID)
|
|||
KeInitializeSpinLock(&CallbackStackListLock);
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NtCallbackReturn (PVOID Result,
|
||||
ULONG ResultLength,
|
||||
NTSTATUS Status)
|
||||
{
|
||||
PULONG OldStack;
|
||||
PETHREAD Thread;
|
||||
PNTSTATUS CallbackStatus;
|
||||
PULONG CallerResultLength;
|
||||
PVOID* CallerResult;
|
||||
PVOID InitialStack;
|
||||
PVOID StackBase;
|
||||
ULONG_PTR StackLimit;
|
||||
KIRQL oldIrql;
|
||||
PNTW32CALL_SAVED_STATE State;
|
||||
PKTRAP_FRAME SavedTrapFrame;
|
||||
PVOID SavedCallbackStack;
|
||||
PVOID SavedExceptionStack;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
Thread = PsGetCurrentThread();
|
||||
if (Thread->Tcb.CallbackStack == NULL)
|
||||
{
|
||||
return(STATUS_NO_CALLBACK_ACTIVE);
|
||||
}
|
||||
|
||||
OldStack = (PULONG)Thread->Tcb.CallbackStack;
|
||||
|
||||
/*
|
||||
* Get the values that NtW32Call left on the inactive stack for us.
|
||||
*/
|
||||
State = (PNTW32CALL_SAVED_STATE)OldStack[0];
|
||||
CallbackStatus = State->CallbackStatus;
|
||||
CallerResultLength = State->CallerResultLength;
|
||||
CallerResult = State->CallerResult;
|
||||
InitialStack = State->SavedInitialStack;
|
||||
StackBase = State->SavedStackBase;
|
||||
StackLimit = State->SavedStackLimit;
|
||||
SavedTrapFrame = State->SavedTrapFrame;
|
||||
SavedCallbackStack = State->SavedCallbackStack;
|
||||
SavedExceptionStack = State->SavedExceptionStack;
|
||||
|
||||
/*
|
||||
* Copy the callback status and the callback result to NtW32Call
|
||||
*/
|
||||
*CallbackStatus = Status;
|
||||
if (CallerResult != NULL && CallerResultLength != NULL)
|
||||
{
|
||||
if (Result == NULL)
|
||||
{
|
||||
*CallerResultLength = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*CallerResultLength = min(ResultLength, *CallerResultLength);
|
||||
RtlCopyMemory(*CallerResult, Result, *CallerResultLength);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore the old stack.
|
||||
*/
|
||||
KeRaiseIrql(HIGH_LEVEL, &oldIrql);
|
||||
if ((Thread->Tcb.NpxState & NPX_STATE_VALID) &&
|
||||
ETHREAD_TO_KTHREAD(Thread) != KeGetCurrentPrcb()->NpxThread)
|
||||
{
|
||||
RtlCopyMemory((char*)InitialStack - sizeof(FX_SAVE_AREA),
|
||||
(char*)Thread->Tcb.InitialStack - sizeof(FX_SAVE_AREA),
|
||||
sizeof(FX_SAVE_AREA));
|
||||
}
|
||||
Thread->Tcb.InitialStack = InitialStack;
|
||||
Thread->Tcb.StackBase = StackBase;
|
||||
Thread->Tcb.StackLimit = StackLimit;
|
||||
Thread->Tcb.TrapFrame = SavedTrapFrame;
|
||||
Thread->Tcb.CallbackStack = SavedCallbackStack;
|
||||
KeGetCurrentKPCR()->TSS->Esp0 = (ULONG)SavedExceptionStack;
|
||||
KeStackSwitchAndRet((PVOID)(OldStack + 1));
|
||||
|
||||
/* Should never return. */
|
||||
KEBUGCHECK(0);
|
||||
return(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
VOID STATIC
|
||||
PsFreeCallbackStackPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
|
||||
PFN_TYPE Page, SWAPENTRY SwapEntry,
|
||||
|
@ -244,13 +149,18 @@ PsAllocateCallbackStack(ULONG StackSize)
|
|||
}
|
||||
return(KernelStack);
|
||||
}
|
||||
#endif
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NtW32Call (IN ULONG RoutineIndex,
|
||||
IN PVOID Argument,
|
||||
IN ULONG ArgumentLength,
|
||||
OUT PVOID* Result OPTIONAL,
|
||||
OUT PULONG ResultLength OPTIONAL)
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
KeUserModeCallback(IN ULONG RoutineIndex,
|
||||
IN PVOID Argument,
|
||||
IN ULONG ArgumentLength,
|
||||
OUT PVOID *Result,
|
||||
OUT PULONG ResultLength)
|
||||
{
|
||||
PETHREAD Thread;
|
||||
PVOID NewStack;
|
||||
|
@ -264,7 +174,7 @@ NtW32Call (IN ULONG RoutineIndex,
|
|||
|
||||
PAGED_CODE();
|
||||
|
||||
DPRINT("NtW32Call(RoutineIndex %d, Argument %X, ArgumentLength %d)\n",
|
||||
DPRINT("KeUserModeCallback(RoutineIndex %d, Argument %X, ArgumentLength %d)\n",
|
||||
RoutineIndex, Argument, ArgumentLength);
|
||||
|
||||
Thread = PsGetCurrentThread();
|
|
@ -18,11 +18,11 @@
|
|||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
static PVOID SystemDllEntryPoint = NULL;
|
||||
static PVOID SystemDllApcDispatcher = NULL;
|
||||
static PVOID SystemDllCallbackDispatcher = NULL;
|
||||
static PVOID SystemDllExceptionDispatcher = NULL;
|
||||
static PVOID SystemDllRaiseExceptionDispatcher = NULL;
|
||||
PVOID SystemDllEntryPoint = NULL;
|
||||
PVOID SystemDllApcDispatcher = NULL;
|
||||
PVOID SystemDllCallbackDispatcher = NULL;
|
||||
PVOID SystemDllExceptionDispatcher = NULL;
|
||||
PVOID SystemDllRaiseExceptionDispatcher = NULL;
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
/* INCLUDES ****************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
|
||||
/* TYPES *******************************************************************/
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* GLOBALS ******************************************************************/
|
||||
|
||||
|
@ -28,6 +28,21 @@ extern OBJECT_FIND_ROUTINE ExpWindowStationObjectFind;
|
|||
extern OBJECT_CREATE_ROUTINE ExpDesktopObjectCreate;
|
||||
extern OBJECT_DELETE_ROUTINE ExpDesktopObjectDelete;
|
||||
|
||||
#ifndef ALEX_CB_REWRITE
|
||||
typedef struct _NTW32CALL_SAVED_STATE
|
||||
{
|
||||
ULONG_PTR SavedStackLimit;
|
||||
PVOID SavedStackBase;
|
||||
PVOID SavedInitialStack;
|
||||
PVOID CallerResult;
|
||||
PULONG CallerResultLength;
|
||||
PNTSTATUS CallbackStatus;
|
||||
PKTRAP_FRAME SavedTrapFrame;
|
||||
PVOID SavedCallbackStack;
|
||||
PVOID SavedExceptionStack;
|
||||
} NTW32CALL_SAVED_STATE, *PNTW32CALL_SAVED_STATE;
|
||||
#endif
|
||||
|
||||
/* FUNCTIONS ***************************************************************/
|
||||
|
||||
PW32THREAD STDCALL
|
||||
|
@ -162,4 +177,182 @@ PsTerminateWin32Thread (PETHREAD Thread)
|
|||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
STDCALL
|
||||
DumpEspData(ULONG Esp, ULONG ThLimit, ULONG ThStack, ULONG PcrLimit, ULONG PcrStack, ULONG Esp0)
|
||||
{
|
||||
DPRINT1("Current Esp: %p\n Thread Stack Limit: %p\n Thread Stack: %p\n Pcr Limit: %p, Pcr Stack: %p\n Esp0 :%p\n",Esp, ThLimit, ThStack, PcrLimit, PcrStack, Esp0) ;
|
||||
}
|
||||
|
||||
PVOID
|
||||
STDCALL
|
||||
PsAllocateCallbackStack(ULONG StackSize)
|
||||
{
|
||||
PVOID KernelStack = NULL;
|
||||
NTSTATUS Status;
|
||||
PMEMORY_AREA StackArea;
|
||||
ULONG i, j;
|
||||
PHYSICAL_ADDRESS BoundaryAddressMultiple;
|
||||
PPFN_TYPE Pages = alloca(sizeof(PFN_TYPE) * (StackSize /PAGE_SIZE));
|
||||
|
||||
DPRINT1("PsAllocateCallbackStack\n");
|
||||
BoundaryAddressMultiple.QuadPart = 0;
|
||||
StackSize = PAGE_ROUND_UP(StackSize);
|
||||
MmLockAddressSpace(MmGetKernelAddressSpace());
|
||||
Status = MmCreateMemoryArea(NULL,
|
||||
MmGetKernelAddressSpace(),
|
||||
MEMORY_AREA_KERNEL_STACK,
|
||||
&KernelStack,
|
||||
StackSize,
|
||||
0,
|
||||
&StackArea,
|
||||
FALSE,
|
||||
FALSE,
|
||||
BoundaryAddressMultiple);
|
||||
MmUnlockAddressSpace(MmGetKernelAddressSpace());
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to create thread stack\n");
|
||||
return(NULL);
|
||||
}
|
||||
for (i = 0; i < (StackSize / PAGE_SIZE); i++)
|
||||
{
|
||||
Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Pages[i]);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
for (j = 0; j < i; j++)
|
||||
{
|
||||
MmReleasePageMemoryConsumer(MC_NPPOOL, Pages[j]);
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
Status = MmCreateVirtualMapping(NULL,
|
||||
KernelStack,
|
||||
PAGE_READWRITE,
|
||||
Pages,
|
||||
StackSize / PAGE_SIZE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
for (i = 0; i < (StackSize / PAGE_SIZE); i++)
|
||||
{
|
||||
MmReleasePageMemoryConsumer(MC_NPPOOL, Pages[i]);
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
DPRINT1("PsAllocateCallbackStack %x\n", KernelStack);
|
||||
return(KernelStack);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
NtW32Call(IN ULONG RoutineIndex,
|
||||
IN PVOID Argument,
|
||||
IN ULONG ArgumentLength,
|
||||
OUT PVOID* Result OPTIONAL,
|
||||
OUT PULONG ResultLength OPTIONAL)
|
||||
{
|
||||
NTSTATUS CallbackStatus;
|
||||
|
||||
DPRINT("NtW32Call(RoutineIndex %d, Argument %X, ArgumentLength %d)\n",
|
||||
RoutineIndex, Argument, ArgumentLength);
|
||||
|
||||
/* FIXME: SEH!!! */
|
||||
|
||||
/* Call kernel function */
|
||||
CallbackStatus = KeUserModeCallback(RoutineIndex,
|
||||
Argument,
|
||||
ArgumentLength,
|
||||
Result,
|
||||
ResultLength);
|
||||
|
||||
/* Return the result */
|
||||
return(CallbackStatus);
|
||||
}
|
||||
|
||||
#ifndef ALEX_CB_REWRITE
|
||||
NTSTATUS STDCALL
|
||||
NtCallbackReturn (PVOID Result,
|
||||
ULONG ResultLength,
|
||||
NTSTATUS Status)
|
||||
{
|
||||
PULONG OldStack;
|
||||
PETHREAD Thread;
|
||||
PNTSTATUS CallbackStatus;
|
||||
PULONG CallerResultLength;
|
||||
PVOID* CallerResult;
|
||||
PVOID InitialStack;
|
||||
PVOID StackBase;
|
||||
ULONG_PTR StackLimit;
|
||||
KIRQL oldIrql;
|
||||
PNTW32CALL_SAVED_STATE State;
|
||||
PKTRAP_FRAME SavedTrapFrame;
|
||||
PVOID SavedCallbackStack;
|
||||
PVOID SavedExceptionStack;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
Thread = PsGetCurrentThread();
|
||||
if (Thread->Tcb.CallbackStack == NULL)
|
||||
{
|
||||
return(STATUS_NO_CALLBACK_ACTIVE);
|
||||
}
|
||||
|
||||
OldStack = (PULONG)Thread->Tcb.CallbackStack;
|
||||
|
||||
/*
|
||||
* Get the values that NtW32Call left on the inactive stack for us.
|
||||
*/
|
||||
State = (PNTW32CALL_SAVED_STATE)OldStack[0];
|
||||
CallbackStatus = State->CallbackStatus;
|
||||
CallerResultLength = State->CallerResultLength;
|
||||
CallerResult = State->CallerResult;
|
||||
InitialStack = State->SavedInitialStack;
|
||||
StackBase = State->SavedStackBase;
|
||||
StackLimit = State->SavedStackLimit;
|
||||
SavedTrapFrame = State->SavedTrapFrame;
|
||||
SavedCallbackStack = State->SavedCallbackStack;
|
||||
SavedExceptionStack = State->SavedExceptionStack;
|
||||
|
||||
/*
|
||||
* Copy the callback status and the callback result to NtW32Call
|
||||
*/
|
||||
*CallbackStatus = Status;
|
||||
if (CallerResult != NULL && CallerResultLength != NULL)
|
||||
{
|
||||
if (Result == NULL)
|
||||
{
|
||||
*CallerResultLength = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*CallerResultLength = min(ResultLength, *CallerResultLength);
|
||||
RtlCopyMemory(*CallerResult, Result, *CallerResultLength);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore the old stack.
|
||||
*/
|
||||
KeRaiseIrql(HIGH_LEVEL, &oldIrql);
|
||||
if ((Thread->Tcb.NpxState & NPX_STATE_VALID) &&
|
||||
ETHREAD_TO_KTHREAD(Thread) != KeGetCurrentPrcb()->NpxThread)
|
||||
{
|
||||
RtlCopyMemory((char*)InitialStack - sizeof(FX_SAVE_AREA),
|
||||
(char*)Thread->Tcb.InitialStack - sizeof(FX_SAVE_AREA),
|
||||
sizeof(FX_SAVE_AREA));
|
||||
}
|
||||
Thread->Tcb.InitialStack = InitialStack;
|
||||
Thread->Tcb.StackBase = StackBase;
|
||||
Thread->Tcb.StackLimit = StackLimit;
|
||||
Thread->Tcb.TrapFrame = SavedTrapFrame;
|
||||
Thread->Tcb.CallbackStack = SavedCallbackStack;
|
||||
KeGetCurrentKPCR()->TSS->Esp0 = (ULONG)SavedExceptionStack;
|
||||
KeStackSwitchAndRet((PVOID)(OldStack + 1));
|
||||
|
||||
/* Should never return. */
|
||||
KEBUGCHECK(0);
|
||||
return(STATUS_UNSUCCESSFUL);
|
||||
#endif
|
||||
}
|
||||
/* EOF */
|
||||
|
|
Loading…
Reference in a new issue