diff --git a/reactos/ntoskrnl/Makefile b/reactos/ntoskrnl/Makefile index 43a1e1774b7..59134f10392 100644 --- a/reactos/ntoskrnl/Makefile +++ b/reactos/ntoskrnl/Makefile @@ -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 = \ diff --git a/reactos/ntoskrnl/include/internal/i386/fpu.h b/reactos/ntoskrnl/include/internal/i386/fpu.h index 14475e2b43b..30267a828de 100644 --- a/reactos/ntoskrnl/include/internal/i386/fpu.h +++ b/reactos/ntoskrnl/include/internal/i386/fpu.h @@ -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__ diff --git a/reactos/ntoskrnl/include/internal/i386/ps.h b/reactos/ntoskrnl/include/internal/i386/ps.h index 5d328917b17..6eb1c4125fb 100644 --- a/reactos/ntoskrnl/include/internal/i386/ps.h +++ b/reactos/ntoskrnl/include/internal/i386/ps.h @@ -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 diff --git a/reactos/ntoskrnl/include/internal/ntoskrnl.h b/reactos/ntoskrnl/include/internal/ntoskrnl.h index 972b42a09e8..d82617b58cc 100644 --- a/reactos/ntoskrnl/include/internal/ntoskrnl.h +++ b/reactos/ntoskrnl/include/internal/ntoskrnl.h @@ -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 */ diff --git a/reactos/ntoskrnl/ke/i386/usercall.S b/reactos/ntoskrnl/ke/i386/usercall.S new file mode 100644 index 00000000000..ad5dd5fbe5d --- /dev/null +++ b/reactos/ntoskrnl/ke/i386/usercall.S @@ -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 +#include +#include +#include +#include +#include +#include +.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 + + diff --git a/reactos/ntoskrnl/ke/i386/usercall.c b/reactos/ntoskrnl/ke/i386/usercall.c deleted file mode 100644 index 46aa853ef50..00000000000 --- a/reactos/ntoskrnl/ke/i386/usercall.c +++ /dev/null @@ -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 -#define NDEBUG -#include - -/* FUNCTIONS *****************************************************************/ - -/* - * @unimplemented - */ -NTSTATUS -STDCALL -KeUserModeCallback( - IN ULONG FunctionID, - IN PVOID InputBuffer, - IN ULONG InputLength, - OUT PVOID *OutputBuffer, - OUT PULONG OutputLength -) -{ - UNIMPLEMENTED; - return 0; -} - -/* EOF */ diff --git a/reactos/ntoskrnl/ps/w32call.c b/reactos/ntoskrnl/ke/usercall.c similarity index 68% rename from reactos/ntoskrnl/ps/w32call.c rename to reactos/ntoskrnl/ke/usercall.c index c009883f381..02573bfad44 100644 --- a/reactos/ntoskrnl/ps/w32call.c +++ b/reactos/ntoskrnl/ke/usercall.c @@ -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 #define NDEBUG #include -#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,14 +149,19 @@ 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; ULONG_PTR StackSize; @@ -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(); @@ -338,6 +248,6 @@ NtW32Call (IN ULONG RoutineIndex, InsertTailList(&CallbackStackListHead, &AssignedStack->ListEntry); KeReleaseSpinLock(&CallbackStackListLock, PASSIVE_LEVEL); return(CallbackStatus); -} - +} + /* EOF */ diff --git a/reactos/ntoskrnl/ldr/sysdll.c b/reactos/ntoskrnl/ldr/sysdll.c index 0785e16462c..7e20b6b892b 100644 --- a/reactos/ntoskrnl/ldr/sysdll.c +++ b/reactos/ntoskrnl/ldr/sysdll.c @@ -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 *****************************************************************/ diff --git a/reactos/ntoskrnl/ps/win32.c b/reactos/ntoskrnl/ps/win32.c index c3f15ad102e..29b31923060 100644 --- a/reactos/ntoskrnl/ps/win32.c +++ b/reactos/ntoskrnl/ps/win32.c @@ -11,8 +11,8 @@ /* INCLUDES ****************************************************************/ #include - -/* TYPES *******************************************************************/ +#define NDEBUG +#include /* 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 */