[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / ex / sysinfo.c
index ca00617..0fa37b6 100644 (file)
 #define NDEBUG
 #include <debug.h>
 
-VOID MmPrintMemoryStatistic(VOID);
+/* The maximum size of an environment value (in bytes) */
+#define MAX_ENVVAL_SIZE 1024
 
 FAST_MUTEX ExpEnvironmentLock;
 ERESOURCE ExpFirmwareTableResource;
 LIST_ENTRY ExpFirmwareTableProviderListHead;
 
+FORCEINLINE
+NTSTATUS
+ExpConvertLdrModuleToRtlModule(IN ULONG ModuleCount,
+                               IN PLDR_DATA_TABLE_ENTRY LdrEntry,
+                               OUT PRTL_PROCESS_MODULE_INFORMATION ModuleInfo)
+{
+    PCHAR p;
+    NTSTATUS Status;
+    ANSI_STRING ModuleName;
+
+    /* Fill it out */
+    ModuleInfo->MappedBase = NULL;
+    ModuleInfo->ImageBase = LdrEntry->DllBase;
+    ModuleInfo->ImageSize = LdrEntry->SizeOfImage;
+    ModuleInfo->Flags = LdrEntry->Flags;
+    ModuleInfo->LoadCount = LdrEntry->LoadCount;
+    ModuleInfo->LoadOrderIndex = (USHORT)ModuleCount;
+    ModuleInfo->InitOrderIndex = 0;
+
+    /* Setup name */
+    RtlInitEmptyAnsiString(&ModuleName,
+                           ModuleInfo->FullPathName,
+                           sizeof(ModuleInfo->FullPathName));
+
+    /* Convert it */
+    Status = RtlUnicodeStringToAnsiString(&ModuleName,
+                                          &LdrEntry->FullDllName,
+                                          FALSE);
+    if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
+    {
+        /* Calculate offset to name */
+        p = ModuleName.Buffer + ModuleName.Length;
+        while ((p > ModuleName.Buffer) && (*--p))
+        {
+            /* Check if we found the separator */
+            if (*p == OBJ_NAME_PATH_SEPARATOR)
+            {
+                /* We did, break out */
+                p++;
+                break;
+            }
+        }
+
+        /* Set the offset */
+        ModuleInfo->OffsetToFileName = (USHORT)(p - ModuleName.Buffer);
+    }
+    else
+    {
+        /* Return empty name */
+        ModuleInfo->FullPathName[0] = ANSI_NULL;
+        ModuleInfo->OffsetToFileName = 0;
+    }
+
+    return Status;
+}
+
 NTSTATUS
 NTAPI
 ExpQueryModuleInformation(IN PLIST_ENTRY KernelModeList,
@@ -32,10 +89,8 @@ ExpQueryModuleInformation(IN PLIST_ENTRY KernelModeList,
     ULONG RequiredLength;
     PRTL_PROCESS_MODULE_INFORMATION ModuleInfo;
     PLDR_DATA_TABLE_ENTRY LdrEntry;
-    ANSI_STRING ModuleName;
     ULONG ModuleCount = 0;
     PLIST_ENTRY NextEntry;
-    PCHAR p;
 
     /* Setup defaults */
     RequiredLength = FIELD_OFFSET(RTL_PROCESS_MODULES, Modules);
@@ -54,48 +109,9 @@ ExpQueryModuleInformation(IN PLIST_ENTRY KernelModeList,
         RequiredLength += sizeof(RTL_PROCESS_MODULE_INFORMATION);
         if (Length >= RequiredLength)
         {
-            /* Fill it out */
-            ModuleInfo->MappedBase = NULL;
-            ModuleInfo->ImageBase = LdrEntry->DllBase;
-            ModuleInfo->ImageSize = LdrEntry->SizeOfImage;
-            ModuleInfo->Flags = LdrEntry->Flags;
-            ModuleInfo->LoadCount = LdrEntry->LoadCount;
-            ModuleInfo->LoadOrderIndex = (USHORT)ModuleCount;
-            ModuleInfo->InitOrderIndex = 0;
-
-            /* Setup name */
-            RtlInitEmptyAnsiString(&ModuleName,
-                                   ModuleInfo->FullPathName,
-                                   sizeof(ModuleInfo->FullPathName));
-
-            /* Convert it */
-            Status = RtlUnicodeStringToAnsiString(&ModuleName,
-                                                  &LdrEntry->FullDllName,
-                                                  FALSE);
-            if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
-            {
-                /* Calculate offset to name */
-                p = ModuleName.Buffer + ModuleName.Length;
-                while ((p > ModuleName.Buffer) && (*--p))
-                {
-                    /* Check if we found the separator */
-                    if (*p == OBJ_NAME_PATH_SEPARATOR)
-                    {
-                        /* We did, break out */
-                        p++;
-                        break;
-                    }
-                }
-
-                /* Set the offset */
-                ModuleInfo->OffsetToFileName = p - ModuleName.Buffer;
-            }
-            else
-            {
-                /* Return empty name */
-                ModuleInfo->FullPathName[0] = ANSI_NULL;
-                ModuleInfo->OffsetToFileName = 0;
-            }
+            Status = ExpConvertLdrModuleToRtlModule(ModuleCount,
+                                                    LdrEntry,
+                                                    ModuleInfo);
 
             /* Go to the next module */
             ModuleInfo++;
@@ -114,8 +130,35 @@ ExpQueryModuleInformation(IN PLIST_ENTRY KernelModeList,
     /* Check if caller also wanted user modules */
     if (UserModeList)
     {
-        /* FIXME: TODO */
-        DPRINT1("User-mode list not yet supported in ReactOS!\n");
+        NextEntry = UserModeList->Flink;
+        while (NextEntry != UserModeList)
+        {
+            /* Get the entry */
+            LdrEntry = CONTAINING_RECORD(NextEntry,
+                                         LDR_DATA_TABLE_ENTRY,
+                                         InLoadOrderLinks);
+
+            /* Update size and check if we can manage one more entry */
+            RequiredLength += sizeof(RTL_PROCESS_MODULE_INFORMATION);
+            if (Length >= RequiredLength)
+            {
+                Status = ExpConvertLdrModuleToRtlModule(ModuleCount,
+                                                        LdrEntry,
+                                                        ModuleInfo);
+
+                /* Go to the next module */
+                ModuleInfo++;
+            }
+            else
+            {
+                /* Set error code */
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+            }
+
+            /* Update count and move to next entry */
+            ModuleCount++;
+            NextEntry = NextEntry->Flink;
+        }
     }
 
     /* Update return length */
@@ -137,6 +180,62 @@ ExpQueryModuleInformation(IN PLIST_ENTRY KernelModeList,
     return Status;
 }
 
+VOID
+NTAPI
+ExUnlockUserBuffer(PMDL Mdl)
+{
+    MmUnlockPages(Mdl);
+    ExFreePoolWithTag(Mdl, TAG_MDL);
+}
+
+NTSTATUS
+NTAPI
+ExLockUserBuffer(
+    PVOID BaseAddress,
+    ULONG Length,
+    KPROCESSOR_MODE AccessMode,
+    LOCK_OPERATION Operation,
+    PVOID *MappedSystemVa,
+    PMDL *OutMdl)
+{
+    PMDL Mdl;
+    PAGED_CODE();
+
+    *MappedSystemVa = NULL;
+    *OutMdl = NULL;
+
+    /* Allocate an MDL for the buffer */
+    Mdl = IoAllocateMdl(BaseAddress, Length, FALSE, TRUE, NULL);
+    if (Mdl == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Enter SEH for probing */
+    _SEH2_TRY
+    {
+        MmProbeAndLockPages(Mdl, AccessMode, Operation);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        ExFreePoolWithTag(Mdl, TAG_MDL);
+        return _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
+
+    /* Return the safe kernel mode buffer */
+    *MappedSystemVa = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
+    if (*MappedSystemVa == NULL)
+    {
+        ExUnlockUserBuffer(Mdl);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Return the MDL */
+    *OutMdl = Mdl;
+    return STATUS_SUCCESS;
+}
+
 /* FUNCTIONS *****************************************************************/
 
 /*
@@ -152,7 +251,7 @@ ExGetCurrentProcessorCpuUsage(PULONG CpuUsage)
 
     Prcb = KeGetCurrentPrcb();
 
-    ScaledIdle = Prcb->IdleThread->KernelTime * 100;
+    ScaledIdle = (ULONGLONG)Prcb->IdleThread->KernelTime * 100;
     TotalTime = Prcb->KernelTime + Prcb->UserTime;
     if (TotalTime != 0)
         *CpuUsage = (ULONG)(100 - (ScaledIdle / TotalTime));
@@ -213,27 +312,22 @@ NtQuerySystemEnvironmentValue(IN PUNICODE_STRING VariableName,
     ANSI_STRING AName;
     UNICODE_STRING WName;
     ARC_STATUS Result;
-    PCH Value;
+    PCH AnsiValueBuffer;
     ANSI_STRING AValue;
     UNICODE_STRING WValue;
     KPROCESSOR_MODE PreviousMode;
     NTSTATUS Status;
     PAGED_CODE();
 
+    /* Check if the call came from user mode */
     PreviousMode = ExGetPreviousMode();
-
     if (PreviousMode != KernelMode)
     {
         _SEH2_TRY
         {
-            ProbeForRead(VariableName,
-                         sizeof(UNICODE_STRING),
-                         sizeof(ULONG));
-
-            ProbeForWrite(ValueBuffer,
-                          ValueBufferLength,
-                          sizeof(WCHAR));
-
+            /* Probe the input and output buffers */
+            ProbeForRead(VariableName, sizeof(UNICODE_STRING), sizeof(ULONG));
+            ProbeForWrite(ValueBuffer, ValueBufferLength, sizeof(WCHAR));
             if (ReturnLength != NULL) ProbeForWriteUlong(ReturnLength);
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
@@ -244,101 +338,68 @@ NtQuerySystemEnvironmentValue(IN PUNICODE_STRING VariableName,
         _SEH2_END;
     }
 
-    /*
-     * Copy the name to kernel space if necessary and convert it to ANSI.
-     */
-    Status = ProbeAndCaptureUnicodeString(&WName,
-                                          PreviousMode,
-                                          VariableName);
-    if (NT_SUCCESS(Status))
+    /* According to NTInternals the SeSystemEnvironmentName privilege is required! */
+    if (!SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege, PreviousMode))
     {
-        /*
-         * according to ntinternals the SeSystemEnvironmentName privilege is required!
-         */
-        if (!SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege,
-                                    PreviousMode))
-        {
-            ReleaseCapturedUnicodeString(&WName, PreviousMode);
-            DPRINT1("NtQuerySystemEnvironmentValue: Caller requires the SeSystemEnvironmentPrivilege privilege!\n");
-            return STATUS_PRIVILEGE_NOT_HELD;
-        }
+        DPRINT1("NtQuerySystemEnvironmentValue: Caller requires the SeSystemEnvironmentPrivilege privilege!\n");
+        return STATUS_PRIVILEGE_NOT_HELD;
+    }
 
-        /*
-         * convert the value name to ansi
-         */
-        Status = RtlUnicodeStringToAnsiString(&AName, &WName, TRUE);
-        ReleaseCapturedUnicodeString(&WName, PreviousMode);
+    /* Copy the name to kernel space if necessary */
+    Status = ProbeAndCaptureUnicodeString(&WName, PreviousMode, VariableName);
+    if (!NT_SUCCESS(Status)) return Status;
 
-        if (!NT_SUCCESS(Status)) return Status;
+    /* Convert the name to ANSI and release the captured UNICODE string */
+    Status = RtlUnicodeStringToAnsiString(&AName, &WName, TRUE);
+    ReleaseCapturedUnicodeString(&WName, PreviousMode);
+    if (!NT_SUCCESS(Status)) return Status;
 
-        /*
-         * Create a temporary buffer for the value
-         */
-        Value = ExAllocatePool(NonPagedPool, ValueBufferLength);
-        if (Value == NULL)
-        {
-            RtlFreeAnsiString(&AName);
-            return STATUS_INSUFFICIENT_RESOURCES;
-        }
+    /* Allocate a buffer for the ANSI environment variable */
+    AnsiValueBuffer = ExAllocatePoolWithTag(NonPagedPool, MAX_ENVVAL_SIZE, 'rvnE');
+    if (AnsiValueBuffer == NULL)
+    {
+        RtlFreeAnsiString(&AName);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
 
-        /*
-         * Get the environment variable
-         */
-        Result = HalGetEnvironmentVariable(AName.Buffer,
-                                           (USHORT)ValueBufferLength,
-                                           Value);
-        if (!Result)
-        {
-            RtlFreeAnsiString(&AName);
-            ExFreePool(Value);
-            return STATUS_UNSUCCESSFUL;
-        }
+    /* Get the environment variable and free the ANSI name */
+    Result = HalGetEnvironmentVariable(AName.Buffer,
+                                       MAX_ENVVAL_SIZE,
+                                       AnsiValueBuffer);
+    RtlFreeAnsiString(&AName);
 
-        /*
-         * Convert the result to UNICODE, protect with SEH in case the value buffer
-         * isn't NULL-terminated!
-         */
+    /* Check if we had success */
+    if (Result == ESUCCESS)
+    {
+        /* Copy the result back to the caller. */
         _SEH2_TRY
         {
-            RtlInitAnsiString(&AValue, Value);
-            Status = RtlAnsiStringToUnicodeString(&WValue, &AValue, TRUE);
+            /* Initialize ANSI string from the result */
+            RtlInitAnsiString(&AValue, AnsiValueBuffer);
+
+            /* Initialize a UNICODE string from the callers buffer */
+            RtlInitEmptyUnicodeString(&WValue, ValueBuffer, (USHORT)ValueBufferLength);
+
+            /* Convert the result to UNICODE */
+            Status = RtlAnsiStringToUnicodeString(&WValue, &AValue, FALSE);
+
+            if (ReturnLength != NULL)
+                *ReturnLength = WValue.Length;
         }
         _SEH2_EXCEPT(ExSystemExceptionFilter())
         {
             Status = _SEH2_GetExceptionCode();
         }
         _SEH2_END;
-
-        if (NT_SUCCESS(Status))
-        {
-            /*
-             * Copy the result back to the caller.
-             */
-            _SEH2_TRY
-            {
-                RtlCopyMemory(ValueBuffer, WValue.Buffer, WValue.Length);
-                ValueBuffer[WValue.Length / sizeof(WCHAR)] = L'\0';
-                if (ReturnLength != NULL)
-                {
-                    *ReturnLength = WValue.Length + sizeof(WCHAR);
-                }
-
-                Status = STATUS_SUCCESS;
-            }
-            _SEH2_EXCEPT(ExSystemExceptionFilter())
-            {
-                Status = _SEH2_GetExceptionCode();
-            }
-            _SEH2_END;
-        }
-
-        /*
-         * Cleanup allocated resources.
-         */
-        RtlFreeAnsiString(&AName);
-        ExFreePool(Value);
+    }
+    else
+    {
+        Status = STATUS_UNSUCCESSFUL;
     }
 
+    /* Free the allocated ANSI value buffer */
+    ExFreePoolWithTag(AnsiValueBuffer, 'rvnE');
+
     return Status;
 }
 
@@ -458,6 +519,16 @@ static NTSTATUS QSI_USE(n) (PVOID Buffer, ULONG Size, PULONG ReqSize)
 #define SSI_DEF(n) \
 static NTSTATUS SSI_USE(n) (PVOID Buffer, ULONG Size)
 
+VOID
+NTAPI
+ExQueryPoolUsage(OUT PULONG PagedPoolPages,
+                 OUT PULONG NonPagedPoolPages,
+                 OUT PULONG PagedPoolAllocs,
+                 OUT PULONG PagedPoolFrees,
+                 OUT PULONG PagedPoolLookasideHits,
+                 OUT PULONG NonPagedPoolAllocs,
+                 OUT PULONG NonPagedPoolFrees,
+                 OUT PULONG NonPagedPoolLookasideHits);
 
 /* Class 0 - Basic Information */
 QSI_DEF(SystemBasicInformation)
@@ -478,8 +549,8 @@ QSI_DEF(SystemBasicInformation)
     Sbi->TimerResolution = KeMaximumIncrement;
     Sbi->PageSize = PAGE_SIZE;
     Sbi->NumberOfPhysicalPages = MmNumberOfPhysicalPages;
-    Sbi->LowestPhysicalPageNumber = MmLowestPhysicalPage;
-    Sbi->HighestPhysicalPageNumber = MmHighestPhysicalPage;
+    Sbi->LowestPhysicalPageNumber = (ULONG)MmLowestPhysicalPage;
+    Sbi->HighestPhysicalPageNumber = (ULONG)MmHighestPhysicalPage;
     Sbi->AllocationGranularity = MM_VIRTMEM_GRANULARITY; /* hard coded on Intel? */
     Sbi->MinimumUserModeAddress = 0x10000; /* Top of 64k */
     Sbi->MaximumUserModeAddress = (ULONG_PTR)MmHighestUserAddress;
@@ -508,7 +579,7 @@ QSI_DEF(SystemProcessorInformation)
     Spi->Reserved = 0;
     Spi->ProcessorFeatureBits = KeFeatureBits;
 
-    DPRINT("Arch %d Level %d Rev 0x%x\n", Spi->ProcessorArchitecture,
+    DPRINT("Arch %u Level %u Rev 0x%x\n", Spi->ProcessorArchitecture,
         Spi->ProcessorLevel, Spi->ProcessorRevision);
 
     return STATUS_SUCCESS;
@@ -542,7 +613,7 @@ QSI_DEF(SystemPerformanceInformation)
     Spi->IoWriteOperationCount = IoWriteOperationCount;
     Spi->IoOtherOperationCount = IoOtherOperationCount;
 
-    Spi->AvailablePages = MmAvailablePages;
+    Spi->AvailablePages = (ULONG)MmAvailablePages;
     /*
      *   Add up all the used "Committed" memory + pagefile.
      *   Not sure this is right. 8^\
@@ -573,21 +644,27 @@ QSI_DEF(SystemPerformanceInformation)
     Spi->MappedPagesWriteCount = 0; /* FIXME */
     Spi->MappedWriteIoCount = 0; /* FIXME */
 
-    Spi->PagedPoolPages = 0; /* FIXME */
-    Spi->PagedPoolAllocs = 0; /* FIXME */
-    Spi->PagedPoolFrees = 0; /* FIXME */
-    Spi->NonPagedPoolPages = 0; /* FIXME */
-    Spi->NonPagedPoolAllocs = 0; /* FIXME */
-    Spi->NonPagedPoolFrees = 0; /* FIXME */
-
+    Spi->PagedPoolPages = 0;
+    Spi->NonPagedPoolPages = 0;
+    Spi->PagedPoolAllocs = 0;
+    Spi->PagedPoolFrees = 0;
+    Spi->PagedPoolLookasideHits = 0;
+    Spi->NonPagedPoolAllocs = 0;
+    Spi->NonPagedPoolFrees = 0;
+    Spi->NonPagedPoolLookasideHits = 0;
+    ExQueryPoolUsage(&Spi->PagedPoolPages,
+                     &Spi->NonPagedPoolPages,
+                     &Spi->PagedPoolAllocs,
+                     &Spi->PagedPoolFrees,
+                     &Spi->PagedPoolLookasideHits,
+                     &Spi->NonPagedPoolAllocs,
+                     &Spi->NonPagedPoolFrees,
+                     &Spi->NonPagedPoolLookasideHits);
     Spi->FreeSystemPtes = 0; /* FIXME */
 
     Spi->ResidentSystemCodePage = 0; /* FIXME */
 
     Spi->TotalSystemDriverPages = 0; /* FIXME */
-    Spi->TotalSystemCodePages = 0; /* FIXME */
-    Spi->NonPagedPoolLookasideHits = 0; /* FIXME */
-    Spi->PagedPoolLookasideHits = 0; /* FIXME */
     Spi->Spare3Count = 0; /* FIXME */
 
     Spi->ResidentSystemCachePage = MiMemoryConsumers[MC_CACHE].PagesUsed;
@@ -713,7 +790,9 @@ QSI_DEF(SystemProcessInformation)
 
         /* Check for overflow */
         if (Size < sizeof(SYSTEM_PROCESS_INFORMATION))
+        {
             Overflow = TRUE;
+        }
 
         /* Zero user's buffer */
         if (!Overflow) RtlZeroMemory(Spi, Size);
@@ -726,9 +805,21 @@ QSI_DEF(SystemProcessInformation)
         {
             SpiCurrent = (PSYSTEM_PROCESS_INFORMATION) Current;
 
+            if ((Process->ProcessExiting) &&
+                (Process->Pcb.Header.SignalState) &&
+                !(Process->ActiveThreads) &&
+                (IsListEmpty(&Process->Pcb.ThreadListHead)))
+            {
+                DPRINT1("Process %p (%s:%p) is a zombie\n",
+                        Process, Process->ImageFileName, Process->UniqueProcessId);
+                CurrentSize = 0;
+                ImageNameMaximumLength = 0;
+                goto Skip;
+            }
+
             ThreadsCount = 0;
-            CurrentEntry = Process->ThreadListHead.Flink;
-            while (CurrentEntry != &Process->ThreadListHead)
+            CurrentEntry = Process->Pcb.ThreadListHead.Flink;
+            while (CurrentEntry != &Process->Pcb.ThreadListHead)
             {
                 ThreadsCount++;
                 CurrentEntry = CurrentEntry->Flink;
@@ -757,9 +848,9 @@ QSI_DEF(SystemProcessInformation)
                 }
               }
             }
-            if (!ImageNameLength && Process != PsIdleProcess && Process->ImageFileName)
+            if (!ImageNameLength && Process != PsIdleProcess)
             {
-              ImageNameLength = strlen(Process->ImageFileName) * sizeof(WCHAR);
+              ImageNameLength = (USHORT)strlen(Process->ImageFileName) * sizeof(WCHAR);
             }
 
             /* Round up the image name length as NT does */
@@ -772,7 +863,9 @@ QSI_DEF(SystemProcessInformation)
 
             /* Check for overflow */
             if (TotalSize > Size)
+            {
                 Overflow = TRUE;
+            }
 
             /* Fill system information */
             if (!Overflow)
@@ -792,9 +885,9 @@ QSI_DEF(SystemProcessInformation)
                         RtlCopyMemory(SpiCurrent->ImageName.Buffer, szSrc, SpiCurrent->ImageName.Length);
 
                         /* Release the memory allocated by SeLocateProcessImageName */
-                        ExFreePool(ProcessImageName);
+                        ExFreePoolWithTag(ProcessImageName, TAG_SEPA);
                     }
-                    else if (Process->ImageFileName)
+                    else
                     {
                         RtlInitAnsiString(&ImageName, Process->ImageFileName);
                         RtlAnsiStringToUnicodeString(&SpiCurrent->ImageName, &ImageName, FALSE);
@@ -823,10 +916,10 @@ QSI_DEF(SystemProcessInformation)
                 SpiCurrent->PrivatePageCount = Process->CommitCharge;
                 ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(SpiCurrent + 1);
 
-                CurrentEntry = Process->ThreadListHead.Flink;
-                while (CurrentEntry != &Process->ThreadListHead)
+                CurrentEntry = Process->Pcb.ThreadListHead.Flink;
+                while (CurrentEntry != &Process->Pcb.ThreadListHead)
                 {
-                    CurrentThread = CONTAINING_RECORD(CurrentEntry, ETHREAD,
+                    CurrentThread = (PETHREAD)CONTAINING_RECORD(CurrentEntry, KTHREAD,
                         ThreadListEntry);
 
                     ThreadInfo->KernelTime.QuadPart = UInt32x32To64(CurrentThread->Tcb.KernelTime, KeMaximumIncrement);
@@ -852,6 +945,7 @@ QSI_DEF(SystemProcessInformation)
             }
 
             /* Handle idle process entry */
+Skip:
             if (Process == PsIdleProcess) Process = NULL;
 
             Process = PsGetNextProcess(Process);
@@ -1224,9 +1318,8 @@ SSI_DEF(SystemFileCacheInformation)
 /* Class 22 - Pool Tag Information */
 QSI_DEF(SystemPoolTagInformation)
 {
-    /* FIXME */
-    DPRINT1("NtQuerySystemInformation - SystemPoolTagInformation not implemented\n");
-    return STATUS_NOT_IMPLEMENTED;
+    if (Size < sizeof(SYSTEM_POOLTAG_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
+    return ExGetPoolTagInfo(Buffer, Size, ReqSize);
 }
 
 /* Class 23 - Interrupt Information for all processors */
@@ -1292,16 +1385,12 @@ QSI_DEF(SystemFullMemoryInformation)
 
     TheIdleProcess = PsIdleProcess;
 
-    DPRINT("PID: %d, KernelTime: %u PFFree: %d PFUsed: %d\n",
+    DPRINT("PID: %p, KernelTime: %u PFFree: %lu PFUsed: %lu\n",
            TheIdleProcess->UniqueProcessId,
            TheIdleProcess->Pcb.KernelTime,
            MiFreeSwapPages,
            MiUsedSwapPages);
 
-#ifndef NDEBUG
-    MmPrintMemoryStatistic();
-#endif
-
     *Spi = MiMemoryConsumers[MC_USER].PagesUsed;
 
     return STATUS_SUCCESS;
@@ -1364,7 +1453,7 @@ SSI_DEF(SystemLoadGdiDriverInformation)
 /* Class 27 - Unload Image */
 SSI_DEF(SystemUnloadGdiDriverInformation)
 {
-    PVOID SectionPointer = Buffer;
+    PVOID *SectionPointer = Buffer;
 
     /* Validate size */
     if (Size != sizeof(PVOID))
@@ -1377,7 +1466,7 @@ SSI_DEF(SystemUnloadGdiDriverInformation)
     if (ExGetPreviousMode() != KernelMode) return STATUS_PRIVILEGE_NOT_HELD;
 
     /* Unload the image */
-    MmUnloadSystemImage(SectionPointer);
+    MmUnloadSystemImage(*SectionPointer);
     return STATUS_SUCCESS;
 }
 
@@ -1397,7 +1486,7 @@ QSI_DEF(SystemTimeAdjustmentInformation)
     /* Give time values to our caller */
     TimeInfo->TimeIncrement = KeMaximumIncrement;
     TimeInfo->TimeAdjustment = KeTimeAdjustment;
-    TimeInfo->Enable = TRUE;
+    TimeInfo->Enable = !KiTimeAdjustmentEnabled;
 
     return STATUS_SUCCESS;
 }
@@ -1405,8 +1494,8 @@ QSI_DEF(SystemTimeAdjustmentInformation)
 SSI_DEF(SystemTimeAdjustmentInformation)
 {
     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
-    /*PSYSTEM_SET_TIME_ADJUST_INFORMATION TimeInfo =
-        (PSYSTEM_SET_TIME_ADJUST_INFORMATION)Buffer;*/
+    PSYSTEM_SET_TIME_ADJUST_INFORMATION TimeInfo =
+        (PSYSTEM_SET_TIME_ADJUST_INFORMATION)Buffer;
 
     /* Check size of a buffer, it must match our expectations */
     if (sizeof(SYSTEM_SET_TIME_ADJUST_INFORMATION) != Size)
@@ -1422,9 +1511,24 @@ SSI_DEF(SystemTimeAdjustmentInformation)
         }
     }
 
-    /* TODO: Set time adjustment information */
-    DPRINT1("Setting of SystemTimeAdjustmentInformation is not implemented yet!\n");
-    return STATUS_NOT_IMPLEMENTED;
+    /* FIXME: behaviour suggests the member be named 'Disable' */
+    if (TimeInfo->Enable)
+    {
+        /* Disable time adjustment and set default value */
+        KiTimeAdjustmentEnabled = FALSE;
+        KeTimeAdjustment = KeMaximumIncrement;
+    }
+    else
+    {
+        /* Check if a valid time adjustment value is given */
+        if (TimeInfo->TimeAdjustment == 0) return STATUS_INVALID_PARAMETER_2;
+
+        /* Enable time adjustment and set the adjustment value */
+        KiTimeAdjustmentEnabled = TRUE;
+        KeTimeAdjustment = TimeInfo->TimeAdjustment;
+    }
+
+    return STATUS_SUCCESS;
 }
 
 /* Class 29 - Summary Memory Information */
@@ -1606,28 +1710,51 @@ SSI_DEF(SystemExtendServiceTableInformation)
     /* Check who is calling */
     if (PreviousMode != KernelMode)
     {
+        static const UNICODE_STRING Win32kName =
+            RTL_CONSTANT_STRING(L"\\SystemRoot\\System32\\win32k.sys");
+
         /* Make sure we can load drivers */
         if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, UserMode))
         {
             /* FIXME: We can't, fail */
-            //return STATUS_PRIVILEGE_NOT_HELD;
+            return STATUS_PRIVILEGE_NOT_HELD;
         }
-    }
 
-    /* Probe and capture the driver name */
-    ProbeAndCaptureUnicodeString(&ImageName, PreviousMode, Buffer);
+        _SEH2_TRY
+        {
+            /* Probe and copy the unicode string */
+            ProbeForRead(Buffer, sizeof(ImageName), 1);
+            ImageName = *(PUNICODE_STRING)Buffer;
+
+            /* Probe the string buffer */
+            ProbeForRead(ImageName.Buffer, ImageName.Length, sizeof(WCHAR));
+
+            /* Check if we have the correct name (nothing else is allowed!) */
+            if (!RtlEqualUnicodeString(&ImageName, &Win32kName, FALSE))
+            {
+                _SEH2_YIELD(return STATUS_PRIVILEGE_NOT_HELD);
+            }
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+
+        /* Recursively call the function, so that we are from kernel mode */
+        return ZwSetSystemInformation(SystemExtendServiceTableInformation,
+                                      (PVOID)&Win32kName,
+                                      sizeof(Win32kName));
+    }
 
     /* Load the image */
-    Status = MmLoadSystemImage(&ImageName,
+    Status = MmLoadSystemImage((PUNICODE_STRING)Buffer,
                                NULL,
                                NULL,
                                0,
                                (PVOID)&ModuleObject,
                                &ImageBase);
 
-    /* Release String */
-    ReleaseCapturedUnicodeString(&ImageName, PreviousMode);
-
     if (!NT_SUCCESS(Status)) return Status;
 
     /* Get the headers */
@@ -1728,13 +1855,151 @@ SSI_DEF(SystemCurrentTimeZoneInformation)
     return ExpSetTimeZoneInformation((PTIME_ZONE_INFORMATION)Buffer);
 }
 
+static
+VOID
+ExpCopyLookasideInformation(
+    PSYSTEM_LOOKASIDE_INFORMATION *InfoPointer,
+    PULONG RemainingPointer,
+    PLIST_ENTRY ListHead,
+    BOOLEAN ListUsesMisses)
+
+{
+    PSYSTEM_LOOKASIDE_INFORMATION Info;
+    PGENERAL_LOOKASIDE LookasideList;
+    PLIST_ENTRY ListEntry;
+    ULONG Remaining;
+
+    /* Get info pointer and remaining count of free array element */
+    Info = *InfoPointer;
+    Remaining = *RemainingPointer;
+
+    /* Loop as long as we have lookaside lists and free array elements */
+    for (ListEntry = ListHead->Flink;
+         (ListEntry != ListHead) && (Remaining > 0);
+         ListEntry = ListEntry->Flink, Remaining--)
+    {
+        LookasideList = CONTAINING_RECORD(ListEntry, GENERAL_LOOKASIDE, ListEntry);
+
+        /* Fill the next array element */
+        Info->CurrentDepth = LookasideList->Depth;
+        Info->MaximumDepth = LookasideList->MaximumDepth;
+        Info->TotalAllocates = LookasideList->TotalAllocates;
+        Info->TotalFrees = LookasideList->TotalFrees;
+        Info->Type = LookasideList->Type;
+        Info->Tag = LookasideList->Tag;
+        Info->Size = LookasideList->Size;
+
+        /* Check how the lists track misses/hits */
+        if (ListUsesMisses)
+        {
+            /* Copy misses */
+            Info->AllocateMisses = LookasideList->AllocateMisses;
+            Info->FreeMisses = LookasideList->FreeMisses;
+        }
+        else
+        {
+            /* Calculate misses */
+            Info->AllocateMisses = LookasideList->TotalAllocates
+                                   - LookasideList->AllocateHits;
+            Info->FreeMisses = LookasideList->TotalFrees
+                               - LookasideList->FreeHits;
+        }
+    }
+
+    /* Return the updated pointer and remaining count */
+    *InfoPointer = Info;
+    *RemainingPointer = Remaining;
+}
 
 /* Class 45 - Lookaside Information */
 QSI_DEF(SystemLookasideInformation)
 {
-    /* FIXME */
-    DPRINT1("NtQuerySystemInformation - SystemLookasideInformation not implemented\n");
-    return STATUS_NOT_IMPLEMENTED;
+    KPROCESSOR_MODE PreviousMode;
+    PSYSTEM_LOOKASIDE_INFORMATION Info;
+    PMDL Mdl;
+    ULONG MaxCount, Remaining;
+    KIRQL OldIrql;
+    NTSTATUS Status;
+
+    /* First we need to lock down the memory, since we are going to access it
+       at high IRQL */
+    PreviousMode = ExGetPreviousMode();
+    Status = ExLockUserBuffer(Buffer,
+                              Size,
+                              PreviousMode,
+                              IoWriteAccess,
+                              (PVOID*)&Info,
+                              &Mdl);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to lock the user buffer: 0x%lx\n", Status);
+        return Status;
+    }
+
+    /* Calculate how many items we can store */
+    Remaining = MaxCount = Size / sizeof(SYSTEM_LOOKASIDE_INFORMATION);
+    if (Remaining == 0)
+    {
+        goto Leave;
+    }
+
+    /* Copy info from pool lookaside lists */
+    ExpCopyLookasideInformation(&Info,
+                                &Remaining,
+                                &ExPoolLookasideListHead,
+                                FALSE);
+    if (Remaining == 0)
+    {
+        goto Leave;
+    }
+
+    /* Copy info from system lookaside lists */
+    ExpCopyLookasideInformation(&Info,
+                                &Remaining,
+                                &ExSystemLookasideListHead,
+                                TRUE);
+    if (Remaining == 0)
+    {
+        goto Leave;
+    }
+
+    /* Acquire spinlock for ExpNonPagedLookasideListHead */
+    OldIrql = KfAcquireSpinLock(&ExpNonPagedLookasideListLock);
+
+    /* Copy info from non-paged lookaside lists */
+    ExpCopyLookasideInformation(&Info,
+                                &Remaining,
+                                &ExpNonPagedLookasideListHead,
+                                TRUE);
+
+    /* Release spinlock for ExpNonPagedLookasideListHead */
+    KfReleaseSpinLock(&ExpNonPagedLookasideListLock, OldIrql);
+
+    if (Remaining == 0)
+    {
+        goto Leave;
+    }
+
+    /* Acquire spinlock for ExpPagedLookasideListHead */
+    OldIrql = KfAcquireSpinLock(&ExpPagedLookasideListLock);
+
+    /* Copy info from paged lookaside lists */
+    ExpCopyLookasideInformation(&Info,
+                                &Remaining,
+                                &ExpPagedLookasideListHead,
+                                TRUE);
+
+    /* Release spinlock for ExpPagedLookasideListHead */
+    KfReleaseSpinLock(&ExpPagedLookasideListLock, OldIrql);
+
+Leave:
+
+    /* Release the locked user buffer */
+    ExUnlockUserBuffer(Mdl);
+
+    /* Return the size of the actually written data */
+    *ReqSize = (MaxCount - Remaining) * sizeof(SYSTEM_LOOKASIDE_INFORMATION);
+    return STATUS_SUCCESS;
 }
 
 
@@ -1746,22 +2011,57 @@ SSI_DEF(SystemSetTimeSlipEvent)
     return STATUS_NOT_IMPLEMENTED;
 }
 
+NTSTATUS
+NTAPI
+MmSessionCreate(OUT PULONG SessionId);
+
+NTSTATUS
+NTAPI
+MmSessionDelete(IN ULONG SessionId);
 
 /* Class 47 - Create a new session (TSE) */
 SSI_DEF(SystemCreateSession)
 {
-    /* FIXME */
-    DPRINT1("NtSetSystemInformation - SystemCreateSession not implemented\n");
-    return STATUS_NOT_IMPLEMENTED;
+    ULONG SessionId;
+    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+    NTSTATUS Status;
+
+    if (Size != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
+
+    if (PreviousMode != KernelMode)
+    {
+        if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
+        {
+            return STATUS_PRIVILEGE_NOT_HELD;
+        }
+    }
+
+    Status = MmSessionCreate(&SessionId);
+    if (NT_SUCCESS(Status)) *(PULONG)Buffer = SessionId;
+
+    return Status;
 }
 
 
 /* Class 48 - Delete an existing session (TSE) */
 SSI_DEF(SystemDeleteSession)
 {
-    /* FIXME */
-    DPRINT1("NtSetSystemInformation - SystemDeleteSession not implemented\n");
-    return STATUS_NOT_IMPLEMENTED;
+    ULONG SessionId;
+    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+
+    if (Size != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
+
+    if (PreviousMode != KernelMode)
+    {
+        if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
+        {
+            return STATUS_PRIVILEGE_NOT_HELD;
+        }
+    }
+
+    SessionId = *(PULONG)Buffer;
+
+    return MmSessionDelete(SessionId);
 }
 
 
@@ -1777,11 +2077,15 @@ QSI_DEF(SystemInvalidInfoClass4)
 /* Class 50 - System range start address */
 QSI_DEF(SystemRangeStartInformation)
 {
-    /* FIXME */
-    DPRINT1("NtQuerySystemInformation - SystemRangeStartInformation not implemented\n");
-    return STATUS_NOT_IMPLEMENTED;
-}
+    /* Check user buffer's size */
+    if (Size != sizeof(ULONG_PTR)) return STATUS_INFO_LENGTH_MISMATCH;
+
+    *(PULONG_PTR)Buffer = (ULONG_PTR)MmSystemRangeStart;
+
+    if (ReqSize) *ReqSize = sizeof(ULONG_PTR);
 
+    return STATUS_SUCCESS;
+}
 
 /* Class 51 - Driver verifier information */
 QSI_DEF(SystemVerifierInformation)
@@ -1846,51 +2150,51 @@ CallQS [] =
     SI_QX(SystemPerformanceInformation),
     SI_QX(SystemTimeOfDayInformation),
     SI_QX(SystemPathInformation), /* should be SI_XX */
-    SI_QX(SystemProcessInformation),
-    SI_QX(SystemCallCountInformation),
-    SI_QX(SystemDeviceInformation),
-    SI_QX(SystemProcessorPerformanceInformation),
-    SI_QS(SystemFlagsInformation),
+    SI_QX(SystemProcessInformation),  // aka SystemProcessesAndThreadsInformation
+    SI_QX(SystemCallCountInformation), // aka SystemCallCounts
+    SI_QX(SystemDeviceInformation), // aka SystemConfigurationInformation
+    SI_QX(SystemProcessorPerformanceInformation), // aka SystemProcessorTimes
+    SI_QS(SystemFlagsInformation), // aka SystemGlobalFlag
     SI_QX(SystemCallTimeInformation), /* should be SI_XX */
     SI_QX(SystemModuleInformation),
-    SI_QX(SystemLocksInformation),
+    SI_QX(SystemLocksInformation), // aka SystemLockInformation
     SI_QX(SystemStackTraceInformation), /* should be SI_XX */
     SI_QX(SystemPagedPoolInformation), /* should be SI_XX */
     SI_QX(SystemNonPagedPoolInformation), /* should be SI_XX */
     SI_QX(SystemHandleInformation),
     SI_QX(SystemObjectInformation),
-    SI_QX(SystemPageFileInformation),
-    SI_QX(SystemVdmInstemulInformation),
+    SI_QX(SystemPageFileInformation), // aka SystemPagefileInformation
+    SI_QX(SystemVdmInstemulInformation), // aka SystemInstructionEmulationCounts
     SI_QX(SystemVdmBopInformation), /* it should be SI_XX */
-    SI_QS(SystemFileCacheInformation),
+    SI_QS(SystemFileCacheInformation), // aka SystemCacheInformation
     SI_QX(SystemPoolTagInformation),
-    SI_QX(SystemInterruptInformation),
-    SI_QS(SystemDpcBehaviourInformation),
+    SI_QX(SystemInterruptInformation), // aka SystemProcessorStatistics
+    SI_QS(SystemDpcBehaviourInformation), // aka SystemDpcInformation
     SI_QX(SystemFullMemoryInformation), /* it should be SI_XX */
-    SI_XS(SystemLoadGdiDriverInformation),
-    SI_XS(SystemUnloadGdiDriverInformation),
-    SI_QS(SystemTimeAdjustmentInformation),
+    SI_XS(SystemLoadGdiDriverInformation), // correct: SystemLoadImage
+    SI_XS(SystemUnloadGdiDriverInformation), // correct: SystemUnloadImage
+    SI_QS(SystemTimeAdjustmentInformation), // aka SystemTimeAdjustment
     SI_QX(SystemSummaryMemoryInformation), /* it should be SI_XX */
     SI_QX(SystemNextEventIdInformation), /* it should be SI_XX */
-    SI_QX(SystemEventIdsInformation), /* it should be SI_XX */
+    SI_QX(SystemEventIdsInformation), /* it should be SI_XX */ // SystemPerformanceTraceInformation
     SI_QX(SystemCrashDumpInformation),
     SI_QX(SystemExceptionInformation),
     SI_QX(SystemCrashDumpStateInformation),
     SI_QX(SystemKernelDebuggerInformation),
     SI_QX(SystemContextSwitchInformation),
     SI_QS(SystemRegistryQuotaInformation),
-    SI_XS(SystemExtendServiceTableInformation),
+    SI_XS(SystemExtendServiceTableInformation), // correct: SystemLoadAndCallImage
     SI_XS(SystemPrioritySeperation),
     SI_QX(SystemPlugPlayBusInformation), /* it should be SI_XX */
     SI_QX(SystemDockInformation), /* it should be SI_XX */
-    SI_QX(SystemPowerInformation), /* it should be SI_XX */
+    SI_QX(SystemPowerInformation), /* it should be SI_XX */ // SystemPowerInformationNative? SystemInvalidInfoClass2
     SI_QX(SystemProcessorSpeedInformation), /* it should be SI_XX */
-    SI_QS(SystemCurrentTimeZoneInformation), /* it should be SI_QX */
+    SI_QS(SystemCurrentTimeZoneInformation), /* it should be SI_QX */ // aka SystemTimeZoneInformation
     SI_QX(SystemLookasideInformation),
     SI_XS(SystemSetTimeSlipEvent),
     SI_XS(SystemCreateSession),
     SI_XS(SystemDeleteSession),
-    SI_QX(SystemInvalidInfoClass4), /* it should be SI_XX */
+    SI_QX(SystemInvalidInfoClass4), /* it should be SI_XX */ // SystemSessionInformation?
     SI_QX(SystemRangeStartInformation),
     SI_QS(SystemVerifierInformation),
     SI_XS(SystemAddVerifier),
@@ -1911,7 +2215,7 @@ NtQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
                          OUT PULONG UnsafeResultLength)
 {
     KPROCESSOR_MODE PreviousMode;
-    ULONG ResultLength;
+    ULONG ResultLength = 0;
     NTSTATUS FStatus = STATUS_NOT_IMPLEMENTED;
 
     PAGED_CODE();
@@ -1928,8 +2232,11 @@ NtQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
                 ProbeForWriteUlong(UnsafeResultLength);
         }
 
+        if (UnsafeResultLength)
+            *UnsafeResultLength = 0;
+
         /*
-         * Check the request is valid.
+         * Check if the request is valid.
          */
         if (SystemInformationClass >= MAX_SYSTEM_INFO_CLASS)
         {
@@ -1944,17 +2251,10 @@ NtQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
             FStatus = CallQS [SystemInformationClass].Query(SystemInformation,
                                                             Length,
                                                             &ResultLength);
-            if (UnsafeResultLength != NULL)
-            {
-                if (PreviousMode != KernelMode)
-                {
-                    *UnsafeResultLength = ResultLength;
-                }
-                else
-                {
-                    *UnsafeResultLength = ResultLength;
-                }
-            }
+
+            /* Save the result length to the caller */
+            if (UnsafeResultLength)
+                *UnsafeResultLength = ResultLength;
         }
     }
     _SEH2_EXCEPT(ExSystemExceptionFilter())