update for HEAD-2003091401
[reactos.git] / ntoskrnl / ps / process.c
index 127f79f..506f8f3 100644 (file)
@@ -12,7 +12,8 @@
 /* INCLUDES ******************************************************************/
 
 #include <limits.h>
-#include <ddk/ntddk.h>
+#define NTOS_MODE_KERNEL
+#include <ntos.h>
 #include <internal/ob.h>
 #include <internal/mm.h>
 #include <internal/ke.h>
 #include <roscfg.h>
 #include <internal/se.h>
 #include <internal/kd.h>
+#include <internal/nls.h>
 
 #define NDEBUG
 #include <internal/debug.h>
 
+
 /* GLOBALS ******************************************************************/
 
 PEPROCESS EXPORTED PsInitialSystemProcess = NULL;
@@ -50,14 +53,20 @@ static GENERIC_MAPPING PiProcessMapping = {PROCESS_READ,
 
 #define MAX_PROCESS_NOTIFY_ROUTINE_COUNT    8
 
-static ULONG PiProcessNotifyRoutineCount = 0;
 static PCREATE_PROCESS_NOTIFY_ROUTINE
 PiProcessNotifyRoutine[MAX_PROCESS_NOTIFY_ROUTINE_COUNT];
 
-/* FUNCTIONS *****************************************************************/
+typedef struct
+{
+    WORK_QUEUE_ITEM WorkQueueItem;
+    KEVENT Event;
+    PEPROCESS Process;
+    BOOLEAN IsWorkerQueue;
+} DEL_CONTEXT, *PDEL_CONTEXT;
 
+/* FUNCTIONS *****************************************************************/
 
-PEPROCESS 
+PEPROCESS
 PsGetNextProcess(PEPROCESS OldProcess)
 {
    KIRQL oldIrql;
@@ -82,15 +91,15 @@ PsGetNextProcess(PEPROCESS OldProcess)
                                        EPROCESS,
                                        ProcessListEntry);
      }
-   KeReleaseSpinLock(&PsProcessListLock, oldIrql);
    Status = ObReferenceObjectByPointer(NextProcess,
                                       PROCESS_ALL_ACCESS,
                                       PsProcessType,
                                       KernelMode);   
+   KeReleaseSpinLock(&PsProcessListLock, oldIrql);
    if (!NT_SUCCESS(Status))
      {
        CPRINT("PsGetNextProcess(): ObReferenceObjectByPointer failed\n");
-       KeBugCheck(0);
+       KEBUGCHECK(0);
      }
    ObDereferenceObject(OldProcess);
    
@@ -122,6 +131,9 @@ _NtOpenProcessToken(IN      HANDLE          ProcessHandle,
 }
 
 
+/*
+ * @implemented
+ */
 NTSTATUS STDCALL 
 NtOpenProcessToken(IN  HANDLE          ProcessHandle,
                   IN   ACCESS_MASK     DesiredAccess,
@@ -131,6 +143,9 @@ NtOpenProcessToken(IN       HANDLE          ProcessHandle,
 }
 
 
+/*
+ * @implemented
+ */
 PACCESS_TOKEN STDCALL
 PsReferencePrimaryToken(PEPROCESS Process)
 {
@@ -232,7 +247,7 @@ PsInitProcessManagment(VOID)
    /*
     * Initialize the system process
     */
-   Status = ObCreateObject(NULL,
+   Status = ObRosCreateObject(NULL,
                           PROCESS_ALL_ACCESS,
                           NULL,
                           PsProcessType,
@@ -244,6 +259,9 @@ PsInitProcessManagment(VOID)
    
    /* System threads may run on any processor. */
    PsInitialSystemProcess->Pcb.Affinity = 0xFFFFFFFF;
+   PsInitialSystemProcess->Pcb.IopmOffset = 0xffff;
+   PsInitialSystemProcess->Pcb.LdtDescriptor[0] = 0;
+   PsInitialSystemProcess->Pcb.LdtDescriptor[1] = 0;
    PsInitialSystemProcess->Pcb.BasePriority = PROCESS_PRIO_NORMAL;
    KeInitializeDispatcherHeader(&PsInitialSystemProcess->Pcb.DispatcherHeader,
                                InternalProcessType,
@@ -279,73 +297,162 @@ PsInitProcessManagment(VOID)
 }
 
 VOID STDCALL
-PiDeleteProcess(PVOID ObjectBody)
+PiDeleteProcessWorker(PVOID pContext)
 {
   KIRQL oldIrql;
-  PEPROCESS Process;
   ULONG i;
+  PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine[MAX_PROCESS_NOTIFY_ROUTINE_COUNT];
+  ULONG NotifyRoutineCount;
+  PDEL_CONTEXT Context;
+  PEPROCESS CurrentProcess;
+  PEPROCESS Process;
+
+  Context = (PDEL_CONTEXT)pContext;
+  Process = Context->Process;
+  CurrentProcess = PsGetCurrentProcess();
 
-  DPRINT("PiDeleteProcess(ObjectBody %x)\n",ObjectBody);
+  DPRINT("PiDeleteProcess(ObjectBody %x)\n",Process);
+
+  if (CurrentProcess != Process)
+    {
+      KeAttachProcess(Process);
+    }
+
+  /* Terminate Win32 Process */
+  PsTerminateWin32Process (Process);
 
-  Process = (PEPROCESS)ObjectBody;
   KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
-  for (i = 0; i < PiProcessNotifyRoutineCount; i++)
+  NotifyRoutineCount = 0;
+  for (i = 0; i < MAX_PROCESS_NOTIFY_ROUTINE_COUNT; i++)
     {
-      PiProcessNotifyRoutine[i](Process->InheritedFromUniqueProcessId,
-                               (HANDLE)Process->UniqueProcessId,
-                               FALSE);
+      if (PiProcessNotifyRoutine[i])
+       {
+         NotifyRoutine[NotifyRoutineCount++] = PiProcessNotifyRoutine[i];
+       }
+    }
+  RemoveEntryList(&Process->ProcessListEntry);
+  KeReleaseSpinLock(&PsProcessListLock, oldIrql);
+
+  for (i = 0;i < NotifyRoutineCount; i++)
+    {
+      /* must be called below DISPATCH_LVL */
+      NotifyRoutine[i](Process->InheritedFromUniqueProcessId,
+                      (HANDLE)Process->UniqueProcessId,
+                      FALSE);
     }
-   RemoveEntryList(&Process->ProcessListEntry);
-   KeReleaseSpinLock(&PsProcessListLock, oldIrql);
 
-   /* KDB hook */
-   KDB_DELETEPROCESS_HOOK(Process);
+  /* KDB hook */
+  KDB_DELETEPROCESS_HOOK(Process);
 
-   ObDereferenceObject(Process->Token);
-   ObDeleteHandleTable(Process);
+  ObDereferenceObject(Process->Token);
+  ObDeleteHandleTable(Process);
 
-   (VOID)MmReleaseMmInfo(Process);
+  if (CurrentProcess != Process)
+    {
+      KeDetachProcess();
+    }
+
+  MmReleaseMmInfo(Process);
+  if (Context->IsWorkerQueue)
+    {
+      KeSetEvent(&Context->Event, IO_NO_INCREMENT, FALSE);
+    }
 }
 
+VOID STDCALL 
+PiDeleteProcess(PVOID ObjectBody)
+{
+  DEL_CONTEXT Context;
+
+  Context.Process = (PEPROCESS)ObjectBody;
+
+  if (PsGetCurrentProcess() == Context.Process || PsGetCurrentThread()->OldProcess == NULL)
+    {
+      Context.IsWorkerQueue = FALSE;
+      PiDeleteProcessWorker(&Context);
+    }
+  else
+    {
+      Context.IsWorkerQueue = TRUE;
+      KeInitializeEvent(&Context.Event, NotificationEvent, FALSE);
+      ExInitializeWorkItem (&Context.WorkQueueItem, PiDeleteProcessWorker, &Context);
+      ExQueueWorkItem(&Context.WorkQueueItem, HyperCriticalWorkQueue);
+      if (KeReadStateEvent(&Context.Event) == 0)
+        {
+          KeWaitForSingleObject(&Context.Event, Executive, KernelMode, FALSE, NULL);
+       }
+    }
+}
 
 static NTSTATUS
 PsCreatePeb(HANDLE ProcessHandle,
-           PVOID ImageBase,
-           PVOID* RPeb)
+           PEPROCESS Process,
+           PVOID ImageBase)
 {
-   NTSTATUS Status;
-   PVOID PebBase;
-   ULONG PebSize;
-   PEB Peb;
-   ULONG BytesWritten;
-   
-   memset(&Peb, 0, sizeof(Peb));
-   Peb.ImageBaseAddress = ImageBase;
-   
-   PebBase = (PVOID)PEB_BASE;
-   PebSize = 0x1000;
-   Status = NtAllocateVirtualMemory(ProcessHandle,
-                                   &PebBase,
-                                   0,
-                                   &PebSize,
-                                   MEM_RESERVE | MEM_COMMIT,
-                                   PAGE_READWRITE);
-   if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-   
-   NtWriteVirtualMemory(ProcessHandle,
-                       (PVOID)PEB_BASE,
-                       &Peb,
-                       sizeof(Peb),
-                       &BytesWritten);
+  ULONG PebSize;
+  PPEB Peb;
+  LARGE_INTEGER SectionOffset;
+  ULONG ViewSize;
+  PVOID TableBase;
+  NTSTATUS Status;
+
+  /* Allocate the Process Environment Block (PEB) */
+  Peb = (PPEB)PEB_BASE;
+  PebSize = PAGE_SIZE;
+  Status = NtAllocateVirtualMemory(ProcessHandle,
+                                  (PVOID*)&Peb,
+                                  0,
+                                  &PebSize,
+                                  MEM_RESERVE | MEM_COMMIT,
+                                  PAGE_READWRITE);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("NtAllocateVirtualMemory() failed (Status %lx)\n", Status);
+      return(Status);
+    }
+  DPRINT("Peb %p  PebSize %lu\n", Peb, PebSize);
+
+  ViewSize = 0;
+  SectionOffset.QuadPart = 0LL;
+  TableBase = NULL;
+  Status = MmMapViewOfSection(NlsSectionObject,
+                             Process,
+                             &TableBase,
+                             0,
+                             0,
+                             &SectionOffset,
+                             &ViewSize,
+                             ViewShare,
+                             MEM_TOP_DOWN,
+                             PAGE_READONLY);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status);
+      return(Status);
+    }
+  DPRINT("TableBase %p  ViewSize %lx\n", TableBase, ViewSize);
 
-   DPRINT("PsCreatePeb: Peb created at %x\n", PebBase);
-   
-   *RPeb = PebBase;
-   
-   return(STATUS_SUCCESS);
+  KeAttachProcess(Process);
+
+  /* Initialize the PEB */
+  RtlZeroMemory(Peb, sizeof(PEB));
+  Peb->ImageBaseAddress = ImageBase;
+
+  Peb->OSMajorVersion = 4;
+  Peb->OSMinorVersion = 0;
+  Peb->OSBuildNumber = 0;
+  Peb->OSPlatformId = 2; //VER_PLATFORM_WIN32_NT;
+
+  Peb->AnsiCodePageData = TableBase + NlsAnsiTableOffset;
+  Peb->OemCodePageData = TableBase + NlsOemTableOffset;
+  Peb->UnicodeCaseTableData = TableBase + NlsUnicodeTableOffset;
+
+  Process->Peb = Peb;
+  KeDetachProcess();
+
+  DPRINT("PsCreatePeb: Peb created at %p\n", Peb);
+
+  return(STATUS_SUCCESS);
 }
 
 
@@ -355,17 +462,22 @@ KeGetCurrentProcess(VOID)
  * FUNCTION: Returns a pointer to the current process
  */
 {
-   return(&(PsGetCurrentProcess()->Pcb));
+  return(&(PsGetCurrentProcess()->Pcb));
 }
 
+/*
+ * @implemented
+ */
 HANDLE STDCALL
 PsGetCurrentProcessId(VOID)
 {
-   return((HANDLE)PsGetCurrentProcess()->UniqueProcessId);
+  return((HANDLE)PsGetCurrentProcess()->UniqueProcessId);
 }
 
 /*
  * FUNCTION: Returns a pointer to the current process
+ *
+ * @implemented
  */
 PEPROCESS STDCALL
 IoGetCurrentProcess(VOID)
@@ -381,6 +493,9 @@ IoGetCurrentProcess(VOID)
      }
 }
 
+/*
+ * @implemented
+ */
 NTSTATUS STDCALL
 PsCreateSystemProcess(PHANDLE ProcessHandle,
                      ACCESS_MASK DesiredAccess,
@@ -434,13 +549,14 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
    KIRQL oldIrql;
    PVOID LdrStartupAddr;
    PVOID ImageBase;
-   PVOID Peb;
    PEPORT DebugPort;
    PEPORT ExceptionPort;
    PVOID BaseAddress;
    PMEMORY_AREA MemoryArea;
    ULONG i;
-   
+   PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine[MAX_PROCESS_NOTIFY_ROUTINE_COUNT];
+   ULONG NotifyRoutineCount;
+
    DPRINT("NtCreateProcess(ObjectAttributes %x)\n",ObjectAttributes);
 
    Status = ObReferenceObjectByHandle(ParentProcessHandle,
@@ -455,7 +571,7 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
        return(Status);
      }
 
-   Status = ObCreateObject(ProcessHandle,
+   Status = ObRosCreateObject(ProcessHandle,
                           DesiredAccess,
                           ObjectAttributes,
                           PsProcessType,
@@ -463,7 +579,7 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
    if (!NT_SUCCESS(Status))
      {
        ObDereferenceObject(ParentProcess);
-       DPRINT("ObCreateObject() = %x\n",Status);
+       DPRINT("ObRosCreateObject() = %x\n",Status);
        return(Status);
      }
 
@@ -475,6 +591,9 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
    /* Inherit parent process's affinity. */
    KProcess->Affinity = ParentProcess->Pcb.Affinity;
    KProcess->BasePriority = PROCESS_PRIO_NORMAL;
+   KProcess->IopmOffset = 0xffff;
+   KProcess->LdtDescriptor[0] = 0;
+   KProcess->LdtDescriptor[1] = 0;
    MmInitializeAddressSpace(Process,
                            &Process->AddressSpace);
    Process->UniqueProcessId = InterlockedIncrement((LONG *)&PiNextProcessUniqueId);
@@ -497,7 +616,7 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
                                  DUPLICATE_SAME_ACCESS);
        if (!NT_SUCCESS(Status))
         {
-          KeBugCheck(0);
+          KEBUGCHECK(0);
         }
      }
    else
@@ -517,7 +636,7 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
                                  DUPLICATE_SAME_ACCESS);
        if (!NT_SUCCESS(Status))
         {
-          KeBugCheck(0);
+          KEBUGCHECK(0);
         }
      }
    else
@@ -526,16 +645,26 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
      }
 
    KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
-   for (i = 0; i < PiProcessNotifyRoutineCount; i++)
-    {
-      PiProcessNotifyRoutine[i](Process->InheritedFromUniqueProcessId,
-                               (HANDLE)Process->UniqueProcessId,
-                               TRUE);
-    }
+   NotifyRoutineCount = 0;
+   for (i = 0; i < MAX_PROCESS_NOTIFY_ROUTINE_COUNT; i++)
+   {
+      if (PiProcessNotifyRoutine[i])
+      {
+         NotifyRoutine[NotifyRoutineCount++] = PiProcessNotifyRoutine[i];   
+      }
+   }
    InsertHeadList(&PsProcessListHead, &Process->ProcessListEntry);
    InitializeListHead(&Process->ThreadListHead);
    KeReleaseSpinLock(&PsProcessListLock, oldIrql);
-   
+
+   for (i = 0;i < NotifyRoutineCount; i++)
+   {
+      //must be called below DISPATCH_LVL
+      NotifyRoutine[i](Process->InheritedFromUniqueProcessId,
+                       (HANDLE)Process->UniqueProcessId,
+                       TRUE);
+   }
+
    Process->Pcb.State = PROCESS_STATE_ACTIVE;
    
    /*
@@ -585,11 +714,66 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
    /*
     * Now we have created the process proper
     */
-   
-   /*
-    * Create the shared data page
-    */
+
    MmLockAddressSpace(&Process->AddressSpace);
+
+   /* Protect the highest 64KB of the process address space */
+   BaseAddress = MmUserProbeAddress;
+   Status = MmCreateMemoryArea(Process,
+                              &Process->AddressSpace,
+                              MEMORY_AREA_NO_ACCESS,
+                              &BaseAddress,
+                              0x10000,
+                              PAGE_NOACCESS,
+                              &MemoryArea,
+                              FALSE,
+                              FALSE);
+   if (!NT_SUCCESS(Status))
+     {
+       MmUnlockAddressSpace(&Process->AddressSpace);
+       DPRINT1("Failed to protect the highest 64KB of the process address space\n");
+       KEBUGCHECK(0);
+     }
+
+   /* Protect the lowest 64KB of the process address space */
+#if 0
+   BaseAddress = (PVOID)0x00000000;
+   Status = MmCreateMemoryArea(Process,
+                              &Process->AddressSpace,
+                              MEMORY_AREA_NO_ACCESS,
+                              &BaseAddress,
+                              0x10000,
+                              PAGE_NOACCESS,
+                              &MemoryArea,
+                              FALSE,
+                              FALSE);
+   if (!NT_SUCCESS(Status))
+     {
+       MmUnlockAddressSpace(&Process->AddressSpace);
+       DPRINT1("Failed to protect the lowest 64KB of the process address space\n");
+       KEBUGCHECK(0);
+     }
+#endif
+
+   /* Protect the 60KB above the shared user page */
+   BaseAddress = (PVOID)USER_SHARED_DATA + PAGE_SIZE;
+   Status = MmCreateMemoryArea(Process,
+                              &Process->AddressSpace,
+                              MEMORY_AREA_NO_ACCESS,
+                              &BaseAddress,
+                              0x10000 - PAGE_SIZE,
+                              PAGE_NOACCESS,
+                              &MemoryArea,
+                              FALSE,
+                              FALSE);
+   if (!NT_SUCCESS(Status))
+     {
+       MmUnlockAddressSpace(&Process->AddressSpace);
+       DPRINT1("Failed to protect the memory above the shared user page\n");
+       KEBUGCHECK(0);
+     }
+
+   /* Create the shared data page */
    BaseAddress = (PVOID)USER_SHARED_DATA;
    Status = MmCreateMemoryArea(Process,
                               &Process->AddressSpace,
@@ -598,14 +782,15 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
                               PAGE_SIZE,
                               PAGE_READONLY,
                               &MemoryArea,
+                              FALSE,
                               FALSE);
    MmUnlockAddressSpace(&Process->AddressSpace);
    if (!NT_SUCCESS(Status))
      {
        DPRINT1("Failed to create shared data page\n");
-       KeBugCheck(0);
+       KEBUGCHECK(0);
      }
-   
+
    /*
     * Map ntdll
     */
@@ -658,8 +843,8 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
     */
    DPRINT("Creating PEB\n");
    Status = PsCreatePeb(*ProcessHandle,
-                       ImageBase,
-                       &Peb);
+                       Process,
+                       ImageBase);
    if (!NT_SUCCESS(Status))
      {
         DbgPrint("NtCreateProcess() Peb creation failed: Status %x\n",Status);
@@ -669,7 +854,6 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
        *ProcessHandle = NULL;
        return(Status);
      }
-   Process->Peb = Peb;
    
    /*
     * Maybe send a message to the creator process's debugger
@@ -705,6 +889,9 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
 }
 
 
+/*
+ * @unimplemented
+ */
 NTSTATUS STDCALL
 NtOpenProcess(OUT PHANDLE          ProcessHandle,
              IN  ACCESS_MASK       DesiredAccess,
@@ -788,17 +975,24 @@ NtOpenProcess(OUT PHANDLE     ProcessHandle,
 }
 
 
+/*
+ * @unimplemented
+ */
 NTSTATUS STDCALL
 NtQueryInformationProcess(IN  HANDLE ProcessHandle,
                          IN  CINT ProcessInformationClass,
                          OUT PVOID ProcessInformation,
                          IN  ULONG ProcessInformationLength,
-                         OUT PULONG ReturnLength)
+                         OUT PULONG ReturnLength OPTIONAL)
 {
    PEPROCESS Process;
    NTSTATUS Status;
-   PPROCESS_BASIC_INFORMATION ProcessBasicInformationP;
-   
+
+   /*
+    * TODO: Here we should probably check that ProcessInformationLength
+    * bytes indeed are writable at address ProcessInformation.
+    */
+
    Status = ObReferenceObjectByHandle(ProcessHandle,
                                      PROCESS_SET_INFORMATION,
                                      PsProcessType,
@@ -809,48 +1003,137 @@ NtQueryInformationProcess(IN  HANDLE ProcessHandle,
      {
        return(Status);
      }
-   
+
    switch (ProcessInformationClass)
      {
       case ProcessBasicInformation:
-       ProcessBasicInformationP = (PPROCESS_BASIC_INFORMATION)
-         ProcessInformation;
-       ProcessBasicInformationP->ExitStatus = Process->ExitStatus;
-       ProcessBasicInformationP->PebBaseAddress = Process->Peb;
-       ProcessBasicInformationP->AffinityMask = Process->Pcb.Affinity;
-       ProcessBasicInformationP->UniqueProcessId =
-         Process->UniqueProcessId;
-       ProcessBasicInformationP->InheritedFromUniqueProcessId =
-         (ULONG)Process->InheritedFromUniqueProcessId;
-       Status = STATUS_SUCCESS;
+       if (ProcessInformationLength != sizeof(PROCESS_BASIC_INFORMATION))
+       {
+         Status = STATUS_INFO_LENGTH_MISMATCH;
+       }
+       else
+       {
+         PPROCESS_BASIC_INFORMATION ProcessBasicInformationP =
+           (PPROCESS_BASIC_INFORMATION)ProcessInformation;
+         ProcessBasicInformationP->ExitStatus = Process->ExitStatus;
+         ProcessBasicInformationP->PebBaseAddress = Process->Peb;
+         ProcessBasicInformationP->AffinityMask = Process->Pcb.Affinity;
+         ProcessBasicInformationP->UniqueProcessId =
+           Process->UniqueProcessId;
+         ProcessBasicInformationP->InheritedFromUniqueProcessId =
+           (ULONG)Process->InheritedFromUniqueProcessId;
+
+         if (ReturnLength)
+         {
+           *ReturnLength = sizeof(PROCESS_BASIC_INFORMATION);
+         }
+       }
        break;
-       
+
       case ProcessQuotaLimits:
       case ProcessIoCounters:
-      case ProcessVmCounters:
       case ProcessTimes:
       case ProcessDebugPort:
       case ProcessLdtInformation:
+      case ProcessWorkingSetWatch:
+      case ProcessWx86Information:
+      case ProcessHandleCount:
+      case ProcessSessionInformation:
+      case ProcessWow64Information:
        Status = STATUS_NOT_IMPLEMENTED;
        break;
-       
-      case ProcessDefaultHardErrorMode:
-       *((PULONG)ProcessInformation) = Process->DefaultHardErrorProcessing;
+
+      case ProcessVmCounters:
+       if (ProcessInformationLength != sizeof(VM_COUNTERS))
+       {
+         Status = STATUS_INFO_LENGTH_MISMATCH;
+       }
+       else
+       {
+         PVM_COUNTERS pOut = (PVM_COUNTERS)ProcessInformation;
+         pOut->PeakVirtualSize            = Process->PeakVirtualSize;
+         /*
+          * Here we should probably use VirtualSize.LowPart, but due to
+          * incompatibilities in current headers (no unnamed union),
+          * I opted for cast.
+          */
+         pOut->VirtualSize                = (ULONG)Process->VirtualSize.QuadPart;
+         pOut->PageFaultCount             = Process->Vm.PageFaultCount;
+         pOut->PeakWorkingSetSize         = Process->Vm.PeakWorkingSetSize;
+         pOut->WorkingSetSize             = Process->Vm.WorkingSetSize;
+         pOut->QuotaPeakPagedPoolUsage    = Process->QuotaPeakPoolUsage[0]; // TODO: Verify!
+         pOut->QuotaPagedPoolUsage        = Process->QuotaPoolUsage[0];     // TODO: Verify!
+         pOut->QuotaPeakNonPagedPoolUsage = Process->QuotaPeakPoolUsage[1]; // TODO: Verify!
+         pOut->QuotaNonPagedPoolUsage     = Process->QuotaPoolUsage[1];     // TODO: Verify!
+         pOut->PagefileUsage              = Process->PagefileUsage;
+         pOut->PeakPagefileUsage          = Process->PeakPagefileUsage;
+
+         if (ReturnLength)
+         {
+           *ReturnLength = sizeof(VM_COUNTERS);
+         }
+       }
        break;
-       
-      case ProcessWorkingSetWatch:
-       Status = STATUS_NOT_IMPLEMENTED;
+
+      case ProcessDefaultHardErrorMode:
+       if (ProcessInformationLength != sizeof(ULONG))
+       {
+         Status = STATUS_INFO_LENGTH_MISMATCH;
+       }
+       else
+       {
+         PULONG HardErrMode = (PULONG)ProcessInformation;
+         *HardErrMode = Process->DefaultHardErrorProcessing;
+
+         if (ReturnLength)
+         {
+           *ReturnLength = sizeof(ULONG);
+         }
+       }
        break;
 
-      case ProcessWx86Information:
-      case ProcessHandleCount:
       case ProcessPriorityBoost:
+       if (ProcessInformationLength != sizeof(ULONG))
+       {
+         Status = STATUS_INFO_LENGTH_MISMATCH;
+       }
+       else
+       {
+         PULONG BoostEnabled = (PULONG)ProcessInformation;
+         *BoostEnabled = Process->Pcb.DisableBoost ? FALSE : TRUE;
+
+         if (ReturnLength)
+         {
+           *ReturnLength = sizeof(ULONG);
+         }
+       }
+       break;
+
       case ProcessDeviceMap:
-      case ProcessSessionInformation:
-      case ProcessWow64Information:
        Status = STATUS_NOT_IMPLEMENTED;
        break;
-       
+
+      case ProcessPriorityClass:
+       if (ProcessInformationLength != sizeof(USHORT))
+       {
+         Status = STATUS_INFO_LENGTH_MISMATCH;
+       }
+       else
+       {
+         PUSHORT Priority = (PUSHORT)ProcessInformation;
+         *Priority = Process->PriorityClass;
+
+         if (ReturnLength)
+         {
+           *ReturnLength = sizeof(USHORT);
+         }
+       }
+       break;
+
+      /*
+       * Note: The following 10 information classes are verified to not be
+       * implemented on NT, and do indeed return STATUS_INVALID_INFO_CLASS;
+       */
       case ProcessBasePriority:
       case ProcessRaisePriority:
       case ProcessExceptionPort:
@@ -859,7 +1142,6 @@ NtQueryInformationProcess(IN  HANDLE ProcessHandle,
       case ProcessIoPortHandlers:
       case ProcessUserModeIOPL:
       case ProcessEnableAlignmentFaultFixup:
-      case ProcessPriorityClass:
       case ProcessAffinityMask:
       case ProcessForegroundInformation:
       default:
@@ -869,6 +1151,7 @@ NtQueryInformationProcess(IN  HANDLE ProcessHandle,
    return(Status);
 }
 
+
 NTSTATUS
 PspAssignPrimaryToken(PEPROCESS Process,
                      HANDLE TokenHandle)
@@ -896,6 +1179,9 @@ PspAssignPrimaryToken(PEPROCESS Process,
    return(Status);
 }
 
+/*
+ * @unimplemented
+ */
 NTSTATUS STDCALL
 NtSetInformationProcess(IN HANDLE ProcessHandle,
                        IN CINT ProcessInformationClass,
@@ -951,7 +1237,6 @@ NtSetInformationProcess(IN HANDLE ProcessHandle,
 
       case ProcessBasicInformation:
       case ProcessIoCounters:
-      case ProcessVmCounters:
       case ProcessTimes:
       case ProcessPooledUsageAndLimits:
       case ProcessWx86Information:
@@ -1180,6 +1465,9 @@ PiQuerySystemProcessInformation(PVOID Buffer,
 #endif
 }
 
+/*
+ * @implemented
+ */
 LARGE_INTEGER STDCALL
 PsGetProcessExitTime(VOID)
 {
@@ -1188,6 +1476,9 @@ PsGetProcessExitTime(VOID)
   return Li;
 }
 
+/*
+ * @implemented
+ */
 BOOLEAN STDCALL
 PsIsThreadTerminating(IN PETHREAD Thread)
 {
@@ -1195,6 +1486,9 @@ PsIsThreadTerminating(IN PETHREAD Thread)
 }
 
 
+/*
+ * @implemented
+ */
 NTSTATUS STDCALL
 PsLookupProcessByProcessId(IN PVOID ProcessId,
                           OUT PEPROCESS *Process)
@@ -1227,17 +1521,51 @@ PsLookupProcessByProcessId(IN PVOID ProcessId,
 }
 
 
+/*
+ * @implemented
+ */
 NTSTATUS STDCALL
 PsSetCreateProcessNotifyRoutine(IN PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,
                                IN BOOLEAN Remove)
 {
-  if (PiProcessNotifyRoutineCount >= MAX_PROCESS_NOTIFY_ROUTINE_COUNT)
-    return(STATUS_INSUFFICIENT_RESOURCES);
+  KIRQL oldIrql;
+  ULONG i;
 
-  PiProcessNotifyRoutine[PiProcessNotifyRoutineCount] = NotifyRoutine;
-  PiProcessNotifyRoutineCount++;
+  KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
 
-  return(STATUS_SUCCESS);
+  if (Remove)
+  {
+     for(i=0;i<MAX_PROCESS_NOTIFY_ROUTINE_COUNT;i++)
+     {
+        if ((PVOID)PiProcessNotifyRoutine[i] == (PVOID)NotifyRoutine)
+        {
+           PiProcessNotifyRoutine[i] = NULL;
+           break;
+        }
+     }
+
+     KeReleaseSpinLock(&PsProcessListLock, oldIrql);
+     return(STATUS_SUCCESS);
+  }
+
+  /*insert*/
+  for(i=0;i<MAX_PROCESS_NOTIFY_ROUTINE_COUNT;i++)
+  {
+     if (PiProcessNotifyRoutine[i] == NULL)
+     {
+        PiProcessNotifyRoutine[i] = NotifyRoutine;
+        break;
+     }
+  }
+
+  KeReleaseSpinLock(&PsProcessListLock, oldIrql);
+
+  if (i == MAX_PROCESS_NOTIFY_ROUTINE_COUNT)
+  {
+     return STATUS_INSUFFICIENT_RESOURCES;
+  }
+
+  return STATUS_SUCCESS;
 }
 
 /* EOF */