- NDK 0.98, now with versionned headers. Too many changes to list, see the TinyKRNL...
[reactos.git] / reactos / ntoskrnl / ps / win32.c
index de106b2..a80b378 100644 (file)
 #include <ntoskrnl.h>
 #define NDEBUG
 #include <internal/debug.h>
+#include <win32k/callout.h>
 
 /* GLOBALS ******************************************************************/
 
-static PW32_PROCESS_CALLBACK PspWin32ProcessCallback = NULL;
-static PW32_THREAD_CALLBACK PspWin32ThreadCallback = NULL;
-static ULONG PspWin32ProcessSize = 0;
-static ULONG PspWin32ThreadSize = 0;
+static PKWIN32_PROCESS_CALLOUT PspWin32ProcessCallback = NULL;
+static PKWIN32_THREAD_CALLOUT PspWin32ThreadCallback = NULL;
 
 extern OB_OPEN_METHOD ExpWindowStationObjectOpen;
-extern OB_PARSE_METHOD ExpWindowStationObjectParse;
+extern OB_ROS_PARSE_METHOD ExpWindowStationObjectParse;
 extern OB_DELETE_METHOD ExpWindowStationObjectDelete;
-extern OB_FIND_METHOD ExpWindowStationObjectFind;
-extern OB_CREATE_METHOD ExpDesktopObjectCreate;
+extern OB_ROS_FIND_METHOD ExpWindowStationObjectFind;
+extern OB_ROS_CREATE_METHOD ExpDesktopObjectCreate;
 extern OB_DELETE_METHOD ExpDesktopObjectDelete;
 
 #ifndef ALEX_CB_REWRITE
@@ -43,110 +42,122 @@ typedef struct _NTW32CALL_SAVED_STATE
 } NTW32CALL_SAVED_STATE, *PNTW32CALL_SAVED_STATE;
 #endif
 
-/* FUNCTIONS ***************************************************************/
-
-PW32THREAD STDCALL
-PsGetWin32Thread(VOID)
-{
-  return(PsGetCurrentThread()->Tcb.Win32Thread);
-}
-
-PW32PROCESS STDCALL
-PsGetWin32Process(VOID)
-{
-  return (PW32PROCESS)PsGetCurrentProcess()->Win32Process;
-}
-
-NTSTATUS STDCALL
-PsCreateWin32Process(PEPROCESS Process)
-{
-  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);
-}
+PVOID
+STDCALL
+KeSwitchKernelStack(
+    IN PVOID StackBase,
+    IN PVOID StackLimit
+);
 
+/* FUNCTIONS ***************************************************************/
 
 /*
  * @implemented
  */
-VOID STDCALL
-PsEstablishWin32Callouts (PW32_PROCESS_CALLBACK W32ProcessCallback,
-                         PW32_THREAD_CALLBACK W32ThreadCallback,
-                         PW32_OBJECT_CALLBACK W32ObjectCallback,
-                         PVOID Param4,
-                         ULONG W32ThreadSize,
-                         ULONG W32ProcessSize)
+VOID 
+STDCALL
+PsEstablishWin32Callouts(PWIN32_CALLOUTS_FPNS calloutData)
 {
-  PspWin32ProcessCallback = W32ProcessCallback;
-  PspWin32ThreadCallback = W32ThreadCallback;
-
-  PspWin32ProcessSize = W32ProcessSize;
-  PspWin32ThreadSize = W32ThreadSize;
-
-  ExpWindowStationObjectOpen = W32ObjectCallback->WinStaCreate;
-  ExpWindowStationObjectParse = W32ObjectCallback->WinStaParse;
-  ExpWindowStationObjectDelete = W32ObjectCallback->WinStaDelete;
-  ExpWindowStationObjectFind = W32ObjectCallback->WinStaFind;
-  ExpDesktopObjectCreate = W32ObjectCallback->DesktopCreate;
-  ExpDesktopObjectDelete = W32ObjectCallback->DesktopDelete;
+    PW32_CALLOUT_DATA CalloutData = (PW32_CALLOUT_DATA)calloutData;
+    PspWin32ProcessCallback = CalloutData->W32ProcessCallout;
+    PspWin32ThreadCallback = CalloutData->W32ThreadCallout;
+    ExpWindowStationObjectOpen = CalloutData->WinStaOpen;
+    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;
+    ULONG_PTR NewStack;
+    PVOID 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)
     {
-      /* FIXME - lock the process */
-      Process->Win32Process = ExAllocatePool (NonPagedPool,
-                                             PspWin32ProcessSize);
+        DPRINT1("Danger: Win32K call attempted but Win32k not ready!\n");
+        return STATUS_ACCESS_DENIED;
+    }
 
-      if (Process->Win32Process == NULL)
-       return STATUS_NO_MEMORY;
+    /* 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;
+    }
 
-      RtlZeroMemory (Process->Win32Process,
-                    PspWin32ProcessSize);
-      /* FIXME - unlock the process */
+    /* Check if we don't already have a kernel-mode stack */
+    if (!Thread->Tcb.LargeStack)
+    {
+        /* We don't create one */
+        NewStack = (ULONG_PTR)MmCreateKernelStack(TRUE) + KERNEL_LARGE_STACK_SIZE;
+        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)NewStack,
+                                       (PVOID)(NewStack - KERNEL_STACK_SIZE));
+
+        /* Leave the critical region */
+        KeLeaveCriticalRegion();
+
+        /* Delete the old stack */
+        MmDeleteKernelStack(OldStack, FALSE);
+    }
 
-      if (PspWin32ProcessCallback != NULL)
-       {
-          PspWin32ProcessCallback (Process, TRUE);
-       }
+    /* This check is bizare. Check out win32k later */
+    if (!Process->Win32Process)
+    {
+        /* Now tell win32k about us */
+        Status = PspWin32ProcessCallback(Process, TRUE);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Danger: Win32k wasn't happy about us!\n");
+            return Status;
+        }
     }
 
-  if (Thread->Tcb.Win32Thread == NULL)
+    /* Set the new service table */
+    Thread->Tcb.ServiceTable = KeServiceDescriptorTableShadow;
+    ASSERT(Thread->Tcb.Win32Thread == 0);
+
+    /* Tell Win32k about our thread */
+    Status = PspWin32ThreadCallback(Thread, PsW32ThreadCalloutInitialize);
+    if (!NT_SUCCESS(Status))
     {
-      Thread->Tcb.Win32Thread = ExAllocatePool (NonPagedPool,
-                                               PspWin32ThreadSize);
-      if (Thread->Tcb.Win32Thread == NULL)
-       return STATUS_NO_MEMORY;
-
-      RtlZeroMemory (Thread->Tcb.Win32Thread,
-                    PspWin32ThreadSize);
-
-      if (PspWin32ThreadCallback != NULL)
-       {
-         PspWin32ThreadCallback (Thread, TRUE);
-       }
+        /* 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)
@@ -163,13 +174,14 @@ PsTerminateWin32Process (PEPROCESS Process)
 
 
 VOID
+NTAPI
 PsTerminateWin32Thread (PETHREAD Thread)
 {
   if (Thread->Tcb.Win32Thread != NULL)
   {
     if (PspWin32ThreadCallback != NULL)
     {
-      PspWin32ThreadCallback (Thread, FALSE);
+      PspWin32ThreadCallback (Thread, PsW32ThreadCalloutExit);
     }
 
     /* don't delete the W32THREAD structure at this point, wait until the
@@ -177,182 +189,61 @@ 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)
+          OUT PVOID* Result,
+          OUT PULONG ResultLength)
 {
-    NTSTATUS CallbackStatus;
+    PVOID RetResult;
+    ULONG RetResultLength;
+    NTSTATUS Status = STATUS_SUCCESS;
 
-    DPRINT("NtW32Call(RoutineIndex %d, Argument %X, ArgumentLength %d)\n",
+    DPRINT("NtW32Call(RoutineIndex %d, Argument %p, ArgumentLength %d)\n",
             RoutineIndex, Argument, ArgumentLength);
 
-    /* FIXME: SEH!!! */
+    /* must not be called as KernelMode! */
+    ASSERT(KeGetPreviousMode() != KernelMode);
 
-    /* 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)
+    _SEH_TRY
     {
-      return(STATUS_NO_CALLBACK_ACTIVE);
+        ProbeForWritePointer(Result);
+        ProbeForWriteUlong(ResultLength);
     }
-
-  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)
+    _SEH_HANDLE
     {
-      if (Result == NULL)
-       {
-         *CallerResultLength = 0;
-       }
-      else
-       {
-         *CallerResultLength = min(ResultLength, *CallerResultLength);
-         RtlCopyMemory(*CallerResult, Result, *CallerResultLength);
-       }
+        Status = _SEH_GetExceptionCode();
     }
+    _SEH_END;
 
-  /*
-   * Restore the old stack.
-   */
-  KeRaiseIrql(HIGH_LEVEL, &oldIrql);
-  if ((Thread->Tcb.NpxState & NPX_STATE_VALID) &&
-      ETHREAD_TO_KTHREAD(Thread) != KeGetCurrentPrcb()->NpxThread)
+    if (NT_SUCCESS(Status))
     {
-      RtlCopyMemory((char*)InitialStack - sizeof(FX_SAVE_AREA),
-                    (char*)Thread->Tcb.InitialStack - sizeof(FX_SAVE_AREA),
-                    sizeof(FX_SAVE_AREA));
+        /* Call kernel function */
+        Status = KeUserModeCallback(RoutineIndex,
+                                    Argument,
+                                    ArgumentLength,
+                                    &RetResult,
+                                    &RetResultLength);
+
+        if (NT_SUCCESS(Status))
+        {
+            _SEH_TRY
+            {
+                *Result = RetResult;
+                *ResultLength = RetResultLength;
+            }
+            _SEH_HANDLE
+            {
+                Status = _SEH_GetExceptionCode();
+            }
+            _SEH_END;
+        }
     }
-  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
+
+    /* Return the result */
+    return Status;
 }
+
 /* EOF */