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 Modified: trunk/reactos/ntoskrnl/Makefile Modified: trunk/reactos/ntoskrnl/include/internal/i386/fpu.h Modified: trunk/reactos/ntoskrnl/include/internal/i386/ps.h Modified: trunk/reactos/ntoskrnl/include/internal/ntoskrnl.h Added: trunk/reactos/ntoskrnl/ke/i386/usercall.S Deleted: trunk/reactos/ntoskrnl/ke/i386/usercall.c Added: trunk/reactos/ntoskrnl/ke/usercall.c Modified: trunk/reactos/ntoskrnl/ldr/sysdll.c Deleted: trunk/reactos/ntoskrnl/ps/w32call.c Modified: trunk/reactos/ntoskrnl/ps/win32.c _____
Modified: trunk/reactos/ntoskrnl/Makefile --- trunk/reactos/ntoskrnl/Makefile 2005-03-19 19:52:36 UTC (rev 14198) +++ trunk/reactos/ntoskrnl/Makefile 2005-03-19 20:26:46 UTC (rev 14199) @@ -111,6 +111,7 @@
ke/sem.o \ ke/spinlock.o \ ke/timer.o \ + ke/usercall.o \ ke/wait.o
# Memory Manager (Mm) @@ -230,8 +231,7 @@ ps/security.o \ ps/suspend.o \ ps/thread.o \ - ps/win32.o \ - ps/w32call.o + ps/win32.o
# Executive Subsystem (Ex) OBJECTS_EX = \ _____
Modified: trunk/reactos/ntoskrnl/include/internal/i386/fpu.h --- trunk/reactos/ntoskrnl/include/internal/i386/fpu.h 2005-03-19 19:52:36 UTC (rev 14198) +++ trunk/reactos/ntoskrnl/include/internal/i386/fpu.h 2005-03-19 20:26:46 UTC (rev 14199) @@ -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__ _____
Modified: trunk/reactos/ntoskrnl/include/internal/i386/ps.h --- trunk/reactos/ntoskrnl/include/internal/i386/ps.h 2005-03-19 19:52:36 UTC (rev 14198) +++ trunk/reactos/ntoskrnl/include/internal/i386/ps.h 2005-03-19 20:26:46 UTC (rev 14199) @@ -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 _____
Modified: trunk/reactos/ntoskrnl/include/internal/ntoskrnl.h --- trunk/reactos/ntoskrnl/include/internal/ntoskrnl.h 2005-03-19 19:52:36 UTC (rev 14198) +++ trunk/reactos/ntoskrnl/include/internal/ntoskrnl.h 2005-03-19 20:26:46 UTC (rev 14199) @@ -66,6 +66,6 @@
/* * */ -#define MM_STACK_SIZE (3*4096) +#define MM_STACK_SIZE (12*4096)
#endif /* INCLUDE_INTERNAL_NTOSKRNL_H */ _____
Added: trunk/reactos/ntoskrnl/ke/i386/usercall.S --- trunk/reactos/ntoskrnl/ke/i386/usercall.S 2005-03-19 19:52:36 UTC (rev 14198) +++ trunk/reactos/ntoskrnl/ke/i386/usercall.S 2005-03-19 20:26:46 UTC (rev 14199) @@ -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 + + _____
Deleted: trunk/reactos/ntoskrnl/ke/i386/usercall.c --- trunk/reactos/ntoskrnl/ke/i386/usercall.c 2005-03-19 19:52:36 UTC (rev 14198) +++ trunk/reactos/ntoskrnl/ke/i386/usercall.c 2005-03-19 20:26:46 UTC (rev 14199) @@ -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 */ _____
Added: trunk/reactos/ntoskrnl/ke/usercall.c --- trunk/reactos/ntoskrnl/ke/usercall.c 2005-03-19 19:52:36 UTC (rev 14198) +++ trunk/reactos/ntoskrnl/ke/usercall.c 2005-03-19 20:26:46 UTC (rev 14199) @@ -0,0 +1,253 @@
+/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/ke/usercall.c + * PURPOSE: User-Mode callbacks. Portable part. + * + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) + */ + +/* INCLUDES ******************************************************************/ + +#include <ntoskrnl.h> +#define NDEBUG +#include <internal/debug.h> + +/* FUNCTIONS *****************************************************************/ + +#if ALEX_CB_REWRITE + +NTSTATUS +STDCALL +KiSwitchToUserMode(IN PVOID *OutputBuffer, + IN PULONG OutputLength); + +#else + +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; + +typedef struct +{ + PVOID BaseAddress; + LIST_ENTRY ListEntry; +} NTW32CALL_CALLBACK_STACK, *PNTW32CALL_CALLBACK_STACK; + +KSPIN_LOCK CallbackStackListLock; +static LIST_ENTRY CallbackStackListHead; + +VOID INIT_FUNCTION +PsInitialiseW32Call(VOID) +{ + InitializeListHead(&CallbackStackListHead); + KeInitializeSpinLock(&CallbackStackListLock); +} + +VOID STATIC +PsFreeCallbackStackPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, + PFN_TYPE Page, SWAPENTRY SwapEntry, + BOOLEAN Dirty) +{ + ASSERT(SwapEntry == 0); + if (Page != 0) + { + MmReleasePageMemoryConsumer(MC_NPPOOL, Page); + } +} + +VOID STATIC +PsFreeCallbackStack(PVOID StackLimit) +{ + MmLockAddressSpace(MmGetKernelAddressSpace()); + MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(), + StackLimit, + PsFreeCallbackStackPage, + NULL); + MmUnlockAddressSpace(MmGetKernelAddressSpace()); +} + +VOID +PsFreeCallbackStacks(VOID) +{ + PLIST_ENTRY CurrentListEntry; + PNTW32CALL_CALLBACK_STACK Current; + + while (!IsListEmpty(&CallbackStackListHead)) + { + CurrentListEntry = RemoveHeadList(&CallbackStackListHead); + Current = CONTAINING_RECORD(CurrentListEntry, NTW32CALL_CALLBACK_STACK, + ListEntry); + PsFreeCallbackStack(Current->BaseAddress); + ExFreePool(Current); + } +} + +PVOID STATIC +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)); + + + 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)) + { + DPRINT("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); + } + return(KernelStack); +} +#endif + +/* + * @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; + PKTRAP_FRAME NewFrame; + PULONG UserEsp; + KIRQL oldIrql; + NTSTATUS CallbackStatus; + NTW32CALL_SAVED_STATE SavedState; + PNTW32CALL_CALLBACK_STACK AssignedStack; + + PAGED_CODE(); + + DPRINT("KeUserModeCallback(RoutineIndex %d, Argument %X, ArgumentLength %d)\n", + RoutineIndex, Argument, ArgumentLength); + + Thread = PsGetCurrentThread(); + + /* Set up the new kernel and user environment. */ + StackSize = (ULONG_PTR)Thread->Tcb.StackBase - Thread->Tcb.StackLimit; + KeAcquireSpinLock(&CallbackStackListLock, &oldIrql); + if (IsListEmpty(&CallbackStackListHead)) + { + KeReleaseSpinLock(&CallbackStackListLock, oldIrql); + NewStack = PsAllocateCallbackStack(StackSize); + AssignedStack = ExAllocatePool(NonPagedPool, + sizeof(NTW32CALL_CALLBACK_STACK)); + AssignedStack->BaseAddress = NewStack; + } + else + { + PLIST_ENTRY StackEntry; + + StackEntry = RemoveHeadList(&CallbackStackListHead); + KeReleaseSpinLock(&CallbackStackListLock, oldIrql); + AssignedStack = CONTAINING_RECORD(StackEntry, NTW32CALL_CALLBACK_STACK, + ListEntry); + NewStack = AssignedStack->BaseAddress; + RtlZeroMemory(NewStack, StackSize); + } + /* FIXME: Need to check whether we were interrupted from v86 mode. */ + RtlCopyMemory((char*)NewStack + StackSize - sizeof(KTRAP_FRAME) - sizeof(FX_SAVE_AREA), + Thread->Tcb.TrapFrame, sizeof(KTRAP_FRAME) - (4 * sizeof(DWORD))); + NewFrame = (PKTRAP_FRAME)((char*)NewStack + StackSize - sizeof(KTRAP_FRAME) - sizeof(FX_SAVE_AREA)); + /* We need the stack pointer to remain 4-byte aligned */ + NewFrame->Esp -= (((ArgumentLength + 3) & (~ 0x3)) + (4 * sizeof(ULONG))); + NewFrame->Eip = (ULONG)LdrpGetSystemDllCallbackDispatcher(); + UserEsp = (PULONG)NewFrame->Esp; + UserEsp[0] = 0; /* Return address. */ + UserEsp[1] = RoutineIndex; + UserEsp[2] = (ULONG)&UserEsp[4]; + UserEsp[3] = ArgumentLength; + RtlCopyMemory((PVOID)&UserEsp[4], Argument, ArgumentLength); + + /* Switch to the new environment and return to user-mode. */ + KeRaiseIrql(HIGH_LEVEL, &oldIrql); + SavedState.SavedStackLimit = Thread->Tcb.StackLimit; + SavedState.SavedStackBase = Thread->Tcb.StackBase; + SavedState.SavedInitialStack = Thread->Tcb.InitialStack; + SavedState.CallerResult = Result; + SavedState.CallerResultLength = ResultLength; + SavedState.CallbackStatus = &CallbackStatus; + SavedState.SavedTrapFrame = Thread->Tcb.TrapFrame; + SavedState.SavedCallbackStack = Thread->Tcb.CallbackStack; + SavedState.SavedExceptionStack = (PVOID)KeGetCurrentKPCR()->TSS->Esp0; + if ((Thread->Tcb.NpxState & NPX_STATE_VALID) && + ETHREAD_TO_KTHREAD(Thread) != KeGetCurrentPrcb()->NpxThread) + { + RtlCopyMemory((char*)NewStack + StackSize - sizeof(FX_SAVE_AREA), + (char*)SavedState.SavedInitialStack - sizeof(FX_SAVE_AREA), + sizeof(FX_SAVE_AREA)); + } + Thread->Tcb.InitialStack = Thread->Tcb.StackBase = (char*)NewStack + StackSize; + Thread->Tcb.StackLimit = (ULONG)NewStack; + Thread->Tcb.KernelStack = (char*)NewStack + StackSize - sizeof(KTRAP_FRAME) - sizeof(FX_SAVE_AREA); + KeGetCurrentKPCR()->TSS->Esp0 = (ULONG)Thread->Tcb.InitialStack - sizeof(FX_SAVE_AREA); + KePushAndStackSwitchAndSysRet((ULONG)&SavedState, Thread->Tcb.KernelStack); + + /* + * The callback return will have already restored most of the state we + * modified. + */ + KeLowerIrql(DISPATCH_LEVEL); + KeAcquireSpinLockAtDpcLevel(&CallbackStackListLock); + InsertTailList(&CallbackStackListHead, &AssignedStack->ListEntry); + KeReleaseSpinLock(&CallbackStackListLock, PASSIVE_LEVEL); + return(CallbackStatus); +} + +/* EOF */ _____
Modified: trunk/reactos/ntoskrnl/ldr/sysdll.c --- trunk/reactos/ntoskrnl/ldr/sysdll.c 2005-03-19 19:52:36 UTC (rev 14198) +++ trunk/reactos/ntoskrnl/ldr/sysdll.c 2005-03-19 20:26:46 UTC (rev 14199) @@ -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 *****************************************************************/
_____
Deleted: trunk/reactos/ntoskrnl/ps/w32call.c --- trunk/reactos/ntoskrnl/ps/w32call.c 2005-03-19 19:52:36 UTC (rev 14198) +++ trunk/reactos/ntoskrnl/ps/w32call.c 2005-03-19 20:26:46 UTC (rev 14199) @@ -1,343 +0,0 @@
-/* $Id$ - * - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: ntoskrnl/ps/w32call.c - * PURPOSE: Thread managment - * - * PROGRAMMERS: David Welch (welch@mcmail.com) - * Phillip Susi - */ - -/* - * NOTE: - * - * All of the routines that manipulate the thread queue synchronize on - * a single spinlock - * - */ - -/* 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 - -/* TYPES *******************************************************************/ - -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; - -typedef struct -{ - PVOID BaseAddress; - LIST_ENTRY ListEntry; -} NTW32CALL_CALLBACK_STACK, *PNTW32CALL_CALLBACK_STACK; - -KSPIN_LOCK CallbackStackListLock; -static LIST_ENTRY CallbackStackListHead; - -/* FUNCTIONS ***************************************************************/ - -VOID INIT_FUNCTION -PsInitialiseW32Call(VOID) -{ - InitializeListHead(&CallbackStackListHead); - 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, - BOOLEAN Dirty) -{ - ASSERT(SwapEntry == 0); - if (Page != 0) - { - MmReleasePageMemoryConsumer(MC_NPPOOL, Page); - } -} - -VOID STATIC -PsFreeCallbackStack(PVOID StackLimit) -{ - MmLockAddressSpace(MmGetKernelAddressSpace()); - MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(), - StackLimit, - PsFreeCallbackStackPage, - NULL); - MmUnlockAddressSpace(MmGetKernelAddressSpace()); -} - -VOID -PsFreeCallbackStacks(VOID) -{ - PLIST_ENTRY CurrentListEntry; - PNTW32CALL_CALLBACK_STACK Current; - - while (!IsListEmpty(&CallbackStackListHead)) - { - CurrentListEntry = RemoveHeadList(&CallbackStackListHead); - Current = CONTAINING_RECORD(CurrentListEntry, NTW32CALL_CALLBACK_STACK, - ListEntry); - PsFreeCallbackStack(Current->BaseAddress); - ExFreePool(Current); - } -} - -PVOID STATIC -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)); - - - 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)) - { - DPRINT("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); - } - return(KernelStack); -} - -NTSTATUS STDCALL -NtW32Call (IN ULONG RoutineIndex, - IN PVOID Argument, - IN ULONG ArgumentLength, - OUT PVOID* Result OPTIONAL, - OUT PULONG ResultLength OPTIONAL) -{ - PETHREAD Thread; - PVOID NewStack; - ULONG_PTR StackSize; - PKTRAP_FRAME NewFrame; - PULONG UserEsp; - KIRQL oldIrql; - NTSTATUS CallbackStatus; - NTW32CALL_SAVED_STATE SavedState; - PNTW32CALL_CALLBACK_STACK AssignedStack; - - PAGED_CODE(); - - DPRINT("NtW32Call(RoutineIndex %d, Argument %X, ArgumentLength %d)\n", - RoutineIndex, Argument, ArgumentLength); - - Thread = PsGetCurrentThread(); - - /* Set up the new kernel and user environment. */ - StackSize = (ULONG_PTR)Thread->Tcb.StackBase - Thread->Tcb.StackLimit; - KeAcquireSpinLock(&CallbackStackListLock, &oldIrql); - if (IsListEmpty(&CallbackStackListHead)) - { - KeReleaseSpinLock(&CallbackStackListLock, oldIrql); - NewStack = PsAllocateCallbackStack(StackSize); - AssignedStack = ExAllocatePool(NonPagedPool, - sizeof(NTW32CALL_CALLBACK_STACK)); - AssignedStack->BaseAddress = NewStack; - } - else - { - PLIST_ENTRY StackEntry; - - StackEntry = RemoveHeadList(&CallbackStackListHead); - KeReleaseSpinLock(&CallbackStackListLock, oldIrql); - AssignedStack = CONTAINING_RECORD(StackEntry, NTW32CALL_CALLBACK_STACK, - ListEntry); - NewStack = AssignedStack->BaseAddress; - RtlZeroMemory(NewStack, StackSize); - } - /* FIXME: Need to check whether we were interrupted from v86 mode. */ - RtlCopyMemory((char*)NewStack + StackSize - sizeof(KTRAP_FRAME) - sizeof(FX_SAVE_AREA), - Thread->Tcb.TrapFrame, sizeof(KTRAP_FRAME) - (4 * sizeof(DWORD))); - NewFrame = (PKTRAP_FRAME)((char*)NewStack + StackSize - sizeof(KTRAP_FRAME) - sizeof(FX_SAVE_AREA)); - /* We need the stack pointer to remain 4-byte aligned */ - NewFrame->Esp -= (((ArgumentLength + 3) & (~ 0x3)) + (4 * sizeof(ULONG))); - NewFrame->Eip = (ULONG)LdrpGetSystemDllCallbackDispatcher(); - UserEsp = (PULONG)NewFrame->Esp; - UserEsp[0] = 0; /* Return address. */ - UserEsp[1] = RoutineIndex; - UserEsp[2] = (ULONG)&UserEsp[4]; - UserEsp[3] = ArgumentLength; - RtlCopyMemory((PVOID)&UserEsp[4], Argument, ArgumentLength); - - /* Switch to the new environment and return to user-mode. */ - KeRaiseIrql(HIGH_LEVEL, &oldIrql); - SavedState.SavedStackLimit = Thread->Tcb.StackLimit; - SavedState.SavedStackBase = Thread->Tcb.StackBase; - SavedState.SavedInitialStack = Thread->Tcb.InitialStack; - SavedState.CallerResult = Result; - SavedState.CallerResultLength = ResultLength; - SavedState.CallbackStatus = &CallbackStatus; - SavedState.SavedTrapFrame = Thread->Tcb.TrapFrame; - SavedState.SavedCallbackStack = Thread->Tcb.CallbackStack; - SavedState.SavedExceptionStack = (PVOID)KeGetCurrentKPCR()->TSS->Esp0; - if ((Thread->Tcb.NpxState & NPX_STATE_VALID) && - ETHREAD_TO_KTHREAD(Thread) != KeGetCurrentPrcb()->NpxThread) - { - RtlCopyMemory((char*)NewStack + StackSize - sizeof(FX_SAVE_AREA), - (char*)SavedState.SavedInitialStack - sizeof(FX_SAVE_AREA), - sizeof(FX_SAVE_AREA)); - } - Thread->Tcb.InitialStack = Thread->Tcb.StackBase = (char*)NewStack + StackSize; - Thread->Tcb.StackLimit = (ULONG)NewStack; - Thread->Tcb.KernelStack = (char*)NewStack + StackSize - sizeof(KTRAP_FRAME) - sizeof(FX_SAVE_AREA); - KeGetCurrentKPCR()->TSS->Esp0 = (ULONG)Thread->Tcb.InitialStack - sizeof(FX_SAVE_AREA); - KePushAndStackSwitchAndSysRet((ULONG)&SavedState, Thread->Tcb.KernelStack); - - /* - * The callback return will have already restored most of the state we - * modified. - */ - KeLowerIrql(DISPATCH_LEVEL); - KeAcquireSpinLockAtDpcLevel(&CallbackStackListLock); - InsertTailList(&CallbackStackListHead, &AssignedStack->ListEntry); - KeReleaseSpinLock(&CallbackStackListLock, PASSIVE_LEVEL); - return(CallbackStatus); -} - -/* EOF */ _____
Modified: trunk/reactos/ntoskrnl/ps/win32.c --- trunk/reactos/ntoskrnl/ps/win32.c 2005-03-19 19:52:36 UTC (rev 14198) +++ trunk/reactos/ntoskrnl/ps/win32.c 2005-03-19 20:26:46 UTC (rev 14199) @@ -11,9 +11,9 @@
/* INCLUDES ****************************************************************/
#include <ntoskrnl.h> +#define NDEBUG +#include <internal/debug.h>
-/* TYPES *******************************************************************/ - /* GLOBALS ******************************************************************/
static PW32_PROCESS_CALLBACK PspWin32ProcessCallback = NULL; @@ -28,6 +28,21 @@ 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 @@ } }
+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)); [truncated at 1000 lines; 15 more skipped]