- Fix MmCreateKernelStack to actually take into account the GuiStack parameter.
[reactos.git] / reactos / ntoskrnl / ps / win32.c
index c6c662a..36e394c 100644 (file)
-/*
- *  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.8 2004/08/15 16:39:10 chorns 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 <ntoskrnl.h>
-
-/* TYPES *******************************************************************/
+#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 ***************************************************************/
 
 /*
  * @implemented
  */
-VOID STDCALL
-PsEstablishWin32Callouts (PW32_PROCESS_CALLBACK W32ProcessCallback,
-                         PW32_THREAD_CALLBACK W32ThreadCallback,
-                         PVOID Param3,
-                         PVOID Param4,
-                         ULONG W32ThreadSize,
-                         ULONG W32ProcessSize)
+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)
@@ -145,22 +165,136 @@ PsTerminateWin32Process (PEPROCESS Process)
       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 */