fixed uninitialized variable warning
[reactos.git] / reactos / ntoskrnl / ke / usercall.c
index 9659295..9ca8b1f 100644 (file)
@@ -3,7 +3,6 @@
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/ke/usercall.c
  * PURPOSE:         User-Mode callbacks. Portable part.
- *
  * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
  */
 
 #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);
-}
+KiCallUserMode(
+    IN PVOID *OutputBuffer,
+    IN PULONG OutputLength
+);
 
-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);
-    }
-}
+PULONG
+STDCALL
+KiGetUserModeStackAddress(
+    VOID
+);
 
-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
+/* FUNCTIONS *****************************************************************/
 
 /*
  * @implemented
@@ -162,92 +38,63 @@ KeUserModeCallback(IN ULONG RoutineIndex,
                    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))
+    ULONG_PTR NewStack, OldStack;
+    PULONG UserEsp;
+    NTSTATUS CallbackStatus = STATUS_SUCCESS;
+    PEXCEPTION_REGISTRATION_RECORD ExceptionList;
+    DPRINT("KeUserModeCallback(RoutineIndex %d, Argument %X, ArgumentLength %d)\n",
+            RoutineIndex, Argument, ArgumentLength);
+    ASSERT(KeGetCurrentThread()->ApcState.KernelApcInProgress == FALSE);
+    ASSERT(KeGetPreviousMode() == UserMode);
+
+    /* Get the current user-mode stack */
+    UserEsp = KiGetUserModeStackAddress();
+    OldStack = *UserEsp;
+
+    /* Enter a SEH Block */
+    _SEH_TRY
     {
-      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);
+        /* Calculate and align the stack size */
+        NewStack = (OldStack - ArgumentLength) & ~3;
+
+        /* Make sure it's writable */
+        ProbeForWrite((PVOID)(NewStack - 6 * sizeof(ULONG_PTR)),
+                      ArgumentLength + 6 * sizeof(ULONG_PTR),
+                      sizeof(CHAR));
+
+        /* Copy the buffer into the stack */
+        RtlCopyMemory((PVOID)NewStack, Argument, ArgumentLength);
+
+        /* Write the arguments */
+        NewStack -= 24;
+        *(PULONG)NewStack = 0;
+        *(PULONG)(NewStack + 4) = RoutineIndex;
+        *(PULONG)(NewStack + 8) = (NewStack + 24);
+        *(PULONG)(NewStack + 12) = ArgumentLength;
+
+        /* Save the exception list */
+        ExceptionList = KeGetCurrentThread()->Teb->Tib.ExceptionList;
+
+        /* Jump to user mode */
+        *UserEsp = NewStack;
+        CallbackStatus = KiCallUserMode(Result, ResultLength);
+
+        /* FIXME: Handle user-mode exception status */
+
+        /* Restore exception list */
+        KeGetCurrentThread()->Teb->Tib.ExceptionList = ExceptionList;
     }
-  /* 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)
+    _SEH_HANDLE
     {
-      RtlCopyMemory((char*)NewStack + StackSize - sizeof(FX_SAVE_AREA),
-                    (char*)SavedState.SavedInitialStack - sizeof(FX_SAVE_AREA),
-                    sizeof(FX_SAVE_AREA));
+        CallbackStatus = _SEH_GetExceptionCode();
     }
-  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);
+    _SEH_END;
+
+    /* FIXME: Flush GDI Batch */
+
+    /* Restore stack and return */
+    *UserEsp = OldStack;
+    return CallbackStatus;
 }
 
 /* EOF */