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:
Alex Ionescu 2005-03-19 20:26:46 +00:00
parent 52a70e745d
commit 396ff5690c
9 changed files with 297 additions and 165 deletions

View file

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

View file

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

View file

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

View file

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

View 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

View file

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

View file

@ -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();

View file

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

View file

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