-/*
- * ReactOS kernel
- * Copyright (C) 2002 ReactOS Team
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+/* $Id$
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/* $Id: win32.c,v 1.6 2003/06/20 16:22:20 ekohl Exp $
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * FILE: ntoskrnl/ps/win32.c
+ * PURPOSE: win32k support
*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
- * FILE: ntoskrnl/ps/win32.c
- * PURPOSE: win32k support
- * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
- * REVISION HISTORY:
- * 04/01/2002: Created
+ * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
*/
/* INCLUDES ****************************************************************/
-#include <ddk/ntddk.h>
-#include <internal/ps.h>
-#include <napi/win32.h>
-
-/* TYPES *******************************************************************/
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <internal/debug.h>
/* GLOBALS ******************************************************************/
static PW32_PROCESS_CALLBACK PspWin32ProcessCallback = NULL;
static PW32_THREAD_CALLBACK PspWin32ThreadCallback = NULL;
-static ULONG PspWin32ProcessSize = 0;
-static ULONG PspWin32ThreadSize = 0;
-
-/* FUNCTIONS ***************************************************************/
-
-PW32THREAD STDCALL
-PsGetWin32Thread(VOID)
-{
- return(PsGetCurrentThread()->Win32Thread);
-}
-PW32PROCESS STDCALL
-PsGetWin32Process(VOID)
-{
- return(PsGetCurrentProcess()->Win32Process);
-}
+extern OB_OPEN_METHOD ExpWindowStationObjectOpen;
+extern OB_PARSE_METHOD ExpWindowStationObjectParse;
+extern OB_DELETE_METHOD ExpWindowStationObjectDelete;
+extern OB_FIND_METHOD ExpWindowStationObjectFind;
+extern OB_CREATE_METHOD ExpDesktopObjectCreate;
+extern OB_DELETE_METHOD ExpDesktopObjectDelete;
-NTSTATUS STDCALL
-PsCreateWin32Process(PEPROCESS Process)
+#ifndef ALEX_CB_REWRITE
+typedef struct _NTW32CALL_SAVED_STATE
{
- if (Process->Win32Process != NULL)
- return(STATUS_SUCCESS);
-
- Process->Win32Process = ExAllocatePool(NonPagedPool,
- PspWin32ProcessSize);
- if (Process->Win32Process == NULL)
- return(STATUS_NO_MEMORY);
-
- RtlZeroMemory(Process->Win32Process,
- PspWin32ProcessSize);
-
- return(STATUS_SUCCESS);
-}
+ 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
+
+PVOID
+STDCALL
+KeSwitchKernelStack(
+ IN PVOID StackBase,
+ IN PVOID StackLimit
+);
+/* FUNCTIONS ***************************************************************/
-VOID STDCALL
-PsEstablishWin32Callouts (PW32_PROCESS_CALLBACK W32ProcessCallback,
- PW32_THREAD_CALLBACK W32ThreadCallback,
- PVOID Param3,
- PVOID Param4,
- ULONG W32ThreadSize,
- ULONG W32ProcessSize)
+/*
+ * @implemented
+ */
+VOID
+STDCALL
+PsEstablishWin32Callouts(PW32_CALLOUT_DATA CalloutData)
{
- PspWin32ProcessCallback = W32ProcessCallback;
- PspWin32ThreadCallback = W32ThreadCallback;
-
- PspWin32ProcessSize = W32ProcessSize;
- PspWin32ThreadSize = W32ThreadSize;
+ PspWin32ProcessCallback = CalloutData->W32ProcessCallout;
+ PspWin32ThreadCallback = CalloutData->W32ThreadCallout;
+ ExpWindowStationObjectOpen = CalloutData->WinStaCreate;
+ ExpWindowStationObjectParse = CalloutData->WinStaParse;
+ ExpWindowStationObjectDelete = CalloutData->WinStaDelete;
+ ExpWindowStationObjectFind = CalloutData->WinStaFind;
+ ExpDesktopObjectCreate = CalloutData->DesktopCreate;
+ ExpDesktopObjectDelete = CalloutData->DesktopDelete;
}
-
NTSTATUS
-PsInitWin32Thread (PETHREAD Thread)
+NTAPI
+PsConvertToGuiThread(VOID)
{
- PEPROCESS Process;
-
- Process = Thread->ThreadsProcess;
+ PVOID NewStack, OldStack;
+ PETHREAD Thread = PsGetCurrentThread();
+ PEPROCESS Process = PsGetCurrentProcess();
+ NTSTATUS Status;
+ PAGED_CODE();
+
+ /* Validate the previous mode */
+ if (KeGetPreviousMode() == KernelMode)
+ {
+ DPRINT1("Danger: win32k call being made in kernel-mode?!\n");
+ return STATUS_INVALID_PARAMETER;
+ }
- if (Process->Win32Process == NULL)
+ /* Make sure win32k is here */
+ if (!PspWin32ProcessCallback)
{
- Process->Win32Process = ExAllocatePool (NonPagedPool,
- PspWin32ProcessSize);
- if (Process->Win32Process == NULL)
- return STATUS_NO_MEMORY;
+ DPRINT1("Danger: Win32K call attempted but Win32k not ready!\n");
+ return STATUS_ACCESS_DENIED;
+ }
- RtlZeroMemory (Process->Win32Process,
- PspWin32ProcessSize);
+ /* Make sure it's not already win32 */
+ if (Thread->Tcb.ServiceTable != KeServiceDescriptorTable)
+ {
+ DPRINT1("Danger: Thread is already a win32 thread. Limit bypassed?\n");
+ return STATUS_ALREADY_WIN32;
+ }
- if (PspWin32ProcessCallback != NULL)
- {
- PspWin32ProcessCallback (Process, TRUE);
- }
+ /* Check if we don't already have a kernel-mode stack */
+ if (!Thread->Tcb.LargeStack)
+ {
+ /* We don't create one */
+ NewStack = MmCreateKernelStack(TRUE);
+ if (!NewStack)
+ {
+ /* Panic in user-mode */
+ NtCurrentTeb()->LastErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ return STATUS_NO_MEMORY;
+ }
+
+ /* We're about to switch stacks. Enter a critical region */
+ KeEnterCriticalRegion();
+
+ /* Switch stacks */
+ OldStack = KeSwitchKernelStack((PVOID)((ULONG_PTR)NewStack + 0x3000),
+ NewStack);
+
+ /* Leave the critical region */
+ KeLeaveCriticalRegion();
+
+ /* Delete the old stack */
+ //MmDeleteKernelStack(OldStack, FALSE);
}
- if (Thread->Win32Thread == NULL)
+ /* This check is bizare. Check out win32k later */
+ if (!Process->Win32Process)
{
- Thread->Win32Thread = ExAllocatePool (NonPagedPool,
- PspWin32ThreadSize);
- if (Thread->Win32Thread == NULL)
- return STATUS_NO_MEMORY;
+ /* Now tell win32k about us */
+ Status = PspWin32ProcessCallback(Process, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Danger: Win32k wasn't happy about us!\n");
+ return Status;
+ }
+ }
- RtlZeroMemory (Thread->Win32Thread,
- PspWin32ThreadSize);
+ /* Set the new service table */
+ Thread->Tcb.ServiceTable = KeServiceDescriptorTableShadow;
+ ASSERT(Thread->Tcb.Win32Thread == 0);
- if (PspWin32ThreadCallback != NULL)
- {
- PspWin32ThreadCallback (Thread, TRUE);
- }
+ /* Tell Win32k about our thread */
+ Status = PspWin32ThreadCallback(Thread, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Revert our table */
+ DPRINT1("Danger: Win32k wasn't happy about us!\n");
+ Thread->Tcb.ServiceTable = KeServiceDescriptorTable;
}
- return(STATUS_SUCCESS);
+ /* Return status */
+ return Status;
}
-
VOID
+NTAPI
PsTerminateWin32Process (PEPROCESS Process)
{
if (Process->Win32Process == NULL)
PspWin32ProcessCallback (Process, FALSE);
}
- ExFreePool (Process->Win32Process);
+ /* don't delete the W32PROCESS structure at this point, wait until the
+ EPROCESS structure is being freed */
}
VOID
+NTAPI
PsTerminateWin32Thread (PETHREAD Thread)
{
- if (Thread->Win32Thread == NULL)
- return;
-
- if (PspWin32ThreadCallback != NULL)
+ if (Thread->Tcb.Win32Thread != NULL)
+ {
+ if (PspWin32ThreadCallback != NULL)
{
PspWin32ThreadCallback (Thread, FALSE);
}
- ExFreePool (Thread->Win32Thread);
+ /* don't delete the W32THREAD structure at this point, wait until the
+ ETHREAD structure is being freed */
+ }
+}
+
+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) &&
+ &Thread->Tcb != 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 */