Sync to trunk head(r38096)
[reactos.git] / reactos / ntoskrnl / ex / sysinfo.c
index a9e1778..748d303 100644 (file)
@@ -1,23 +1,18 @@
-/* $Id$
- *
+/*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/ex/sysinfo.c
  * PURPOSE:         System information functions
  *
  * PROGRAMMERS:     David Welch (welch@mcmail.com)
- *                  Aleksey Bragin (aleksey@studiocerebral.com)
+ *                  Aleksey Bragin (aleksey@reactos.org)
  */
 
 /* INCLUDES *****************************************************************/
 
 #include <ntoskrnl.h>
 #define NDEBUG
-#include <internal/debug.h>
-
-extern PEPROCESS PsIdleProcess;
-extern ULONG NtGlobalFlag; /* FIXME: it should go in a ddk/?.h */
-ULONGLONG STDCALL KeQueryInterruptTime(VOID);
+#include <debug.h>
 
 VOID MmPrintMemoryStatistic(VOID);
 
@@ -25,41 +20,142 @@ FAST_MUTEX ExpEnvironmentLock;
 ERESOURCE ExpFirmwareTableResource;
 LIST_ENTRY ExpFirmwareTableProviderListHead;
 
+NTSTATUS
+NTAPI
+ExpQueryModuleInformation(IN PLIST_ENTRY KernelModeList,
+                          IN PLIST_ENTRY UserModeList,
+                          OUT PRTL_PROCESS_MODULES Modules,
+                          IN ULONG Length,
+                          OUT PULONG ReturnLength)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    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);
+    ModuleInfo = &Modules->Modules[0];
+
+    /* Loop the kernel list */
+    NextEntry = KernelModeList->Flink;
+    while (NextEntry != KernelModeList)
+    {
+        /* 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)
+        {
+            /* 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;
+            }
+
+            /* 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;
+    }
+
+    /* Check if caller also wanted user modules */
+    if (UserModeList)
+    {
+        /* FIXME: TODO */
+        DPRINT1("User-mode list not yet supported in ReactOS!\n");
+    }
+
+    /* Update return length */
+    if (ReturnLength) *ReturnLength = RequiredLength;
+
+    /* Validate the length again */
+    if (Length >= FIELD_OFFSET(RTL_PROCESS_MODULES, Modules))
+    {
+        /* Set the final count */
+        Modules->NumberOfModules = ModuleCount;
+    }
+    else
+    {
+        /* Otherwise, we failed */
+        Status = STATUS_INFO_LENGTH_MISMATCH;
+    }
+
+    /* Done */
+    return Status;
+}
+
 /* FUNCTIONS *****************************************************************/
 
 /*
  * @implemented
  */
+#undef ExGetPreviousMode
 KPROCESSOR_MODE
 NTAPI
 ExGetPreviousMode (VOID)
 {
-    return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode;
-}
-
-/*
- * @unimplemented
- */
-VOID
-STDCALL
-ExEnumHandleTable (
-       PULONG  HandleTable,
-       PVOID   Callback,
-       PVOID   Param,
-       PHANDLE Handle OPTIONAL
-       )
-{
-       UNIMPLEMENTED;
+    return KeGetPreviousMode();
 }
 
 /*
  * @implemented
  */
 VOID
-STDCALL
-ExGetCurrentProcessorCpuUsage (
-       PULONG  CpuUsage
-       )
+NTAPI
+ExGetCurrentProcessorCpuUsage(PULONG CpuUsage)
 {
        PKPRCB Prcb;
        ULONG TotalTime;
@@ -70,7 +166,7 @@ ExGetCurrentProcessorCpuUsage (
        ScaledIdle = Prcb->IdleThread->KernelTime * 100;
        TotalTime = Prcb->KernelTime + Prcb->UserTime;
        if (TotalTime != 0)
-               *CpuUsage = 100 - (ScaledIdle / TotalTime);
+               *CpuUsage = (ULONG)(100 - (ScaledIdle / TotalTime));
        else
                *CpuUsage = 0;
 }
@@ -79,12 +175,10 @@ ExGetCurrentProcessorCpuUsage (
  * @implemented
  */
 VOID
-STDCALL
-ExGetCurrentProcessorCounts (
-       PULONG  ThreadKernelTime,
-       PULONG  TotalCpuTime,
-       PULONG  ProcessorNumber
-       )
+NTAPI
+ExGetCurrentProcessorCounts(PULONG ThreadKernelTime,
+                            PULONG TotalCpuTime,
+                            PULONG ProcessorNumber)
 {
        PKPRCB Prcb;
 
@@ -99,7 +193,7 @@ ExGetCurrentProcessorCounts (
  * @implemented
  */
 BOOLEAN
-STDCALL
+NTAPI
 ExIsProcessorFeaturePresent(IN ULONG ProcessorFeature)
 {
     /* Quick check to see if it exists at all */
@@ -113,14 +207,15 @@ ExIsProcessorFeaturePresent(IN ULONG ProcessorFeature)
  * @implemented
  */
 BOOLEAN
-STDCALL
+NTAPI
 ExVerifySuite(SUITE_TYPE SuiteType)
 {
     if (SuiteType == Personal) return TRUE;
     return FALSE;
 }
 
-NTSTATUS STDCALL
+NTSTATUS
+NTAPI
 NtQuerySystemEnvironmentValue (IN      PUNICODE_STRING VariableName,
                               OUT      PWSTR           ValueBuffer,
                               IN       ULONG           ValueBufferLength,
@@ -128,7 +223,7 @@ NtQuerySystemEnvironmentValue (IN   PUNICODE_STRING VariableName,
 {
   ANSI_STRING AName;
   UNICODE_STRING WName;
-  BOOLEAN Result;
+  ARC_STATUS Result;
   PCH Value;
   ANSI_STRING AValue;
   UNICODE_STRING WValue;
@@ -141,7 +236,7 @@ NtQuerySystemEnvironmentValue (IN   PUNICODE_STRING VariableName,
 
   if(PreviousMode != KernelMode)
   {
-    _SEH_TRY
+    _SEH2_TRY
     {
       ProbeForRead(VariableName,
                    sizeof(UNICODE_STRING),
@@ -154,11 +249,11 @@ NtQuerySystemEnvironmentValue (IN PUNICODE_STRING VariableName,
         ProbeForWriteUlong(ReturnLength);
       }
     }
-    _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+    _SEH2_EXCEPT(ExSystemExceptionFilter())
     {
-      Status = _SEH_GetExceptionCode();
+      Status = _SEH2_GetExceptionCode();
     }
-    _SEH_END;
+    _SEH2_END;
 
     if(!NT_SUCCESS(Status))
     {
@@ -210,7 +305,9 @@ NtQuerySystemEnvironmentValue (IN   PUNICODE_STRING VariableName,
     /*
      * Get the environment variable
      */
-    Result = HalGetEnvironmentVariable(AName.Buffer, ValueBufferLength, Value);
+    Result = HalGetEnvironmentVariable(AName.Buffer,
+                                       (USHORT)ValueBufferLength,
+                                       Value);
     if(!Result)
     {
       RtlFreeAnsiString(&AName);
@@ -222,23 +319,23 @@ NtQuerySystemEnvironmentValue (IN PUNICODE_STRING VariableName,
      * Convert the result to UNICODE, protect with SEH in case the value buffer
      * isn't NULL-terminated!
      */
-    _SEH_TRY
+    _SEH2_TRY
     {
       RtlInitAnsiString(&AValue, Value);
       Status = RtlAnsiStringToUnicodeString(&WValue, &AValue, TRUE);
     }
-    _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+    _SEH2_EXCEPT(ExSystemExceptionFilter())
     {
-      Status = _SEH_GetExceptionCode();
+      Status = _SEH2_GetExceptionCode();
     }
-    _SEH_END;
+    _SEH2_END;
 
     if(NT_SUCCESS(Status))
     {
       /*
        * Copy the result back to the caller.
        */
-      _SEH_TRY
+      _SEH2_TRY
       {
         RtlCopyMemory(ValueBuffer, WValue.Buffer, WValue.Length);
         ValueBuffer[WValue.Length / sizeof(WCHAR)] = L'\0';
@@ -249,11 +346,11 @@ NtQuerySystemEnvironmentValue (IN PUNICODE_STRING VariableName,
 
         Status = STATUS_SUCCESS;
       }
-      _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+      _SEH2_EXCEPT(ExSystemExceptionFilter())
       {
-        Status = _SEH_GetExceptionCode();
+        Status = _SEH2_GetExceptionCode();
       }
-      _SEH_END;
+      _SEH2_END;
     }
 
     /*
@@ -267,7 +364,7 @@ NtQuerySystemEnvironmentValue (IN   PUNICODE_STRING VariableName,
 }
 
 
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 NtSetSystemEnvironmentValue (IN        PUNICODE_STRING VariableName,
                             IN PUNICODE_STRING Value)
 {
@@ -312,7 +409,7 @@ NtSetSystemEnvironmentValue (IN     PUNICODE_STRING VariableName,
                                                 TRUE);
           if(NT_SUCCESS(Status))
           {
-            BOOLEAN Result = HalSetEnvironmentVariable(AName.Buffer,
+            ARC_STATUS Result = HalSetEnvironmentVariable(AName.Buffer,
                                                        AValue.Buffer);
 
             Status = (Result ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
@@ -336,6 +433,36 @@ NtSetSystemEnvironmentValue (IN    PUNICODE_STRING VariableName,
   return Status;
 }
 
+NTSTATUS
+NTAPI
+NtEnumerateSystemEnvironmentValuesEx(IN ULONG InformationClass,
+                                     IN PVOID Buffer,
+                                     IN ULONG BufferLength)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+NtQuerySystemEnvironmentValueEx(IN PUNICODE_STRING VariableName,
+                                IN LPGUID VendorGuid,
+                                IN PVOID Value,
+                                IN OUT PULONG ReturnLength,
+                                IN OUT PULONG Attributes)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+NtSetSystemEnvironmentValueEx(IN PUNICODE_STRING VariableName,
+                              IN LPGUID VendorGuid)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
 
 /* --- Query/Set System Information --- */
 
@@ -366,6 +493,7 @@ QSI_DEF(SystemBasicInformation)
        {
                return (STATUS_INFO_LENGTH_MISMATCH);
        }
+       RtlZeroMemory(Sbi, Size);
        Sbi->Reserved = 0;
        Sbi->TimerResolution = KeMaximumIncrement;
        Sbi->PageSize = PAGE_SIZE;
@@ -395,11 +523,11 @@ QSI_DEF(SystemProcessorInformation)
                return (STATUS_INFO_LENGTH_MISMATCH);
        }
        Prcb = KeGetCurrentPrcb();
-       Spi->ProcessorArchitecture = 0; /* Intel Processor */
-       Spi->ProcessorLevel        = Prcb->CpuType;
-       Spi->ProcessorRevision     = Prcb->CpuStep;
+       Spi->ProcessorArchitecture = KeProcessorArchitecture;
+       Spi->ProcessorLevel        = KeProcessorLevel;
+       Spi->ProcessorRevision     = KeProcessorRevision;
        Spi->Reserved              = 0;
-       Spi->ProcessorFeatureBits          = Prcb->FeatureBits;
+       Spi->ProcessorFeatureBits          = KeFeatureBits;
 
        DPRINT("Arch %d Level %d Rev 0x%x\n", Spi->ProcessorArchitecture,
                Spi->ProcessorLevel, Spi->ProcessorRevision);
@@ -410,6 +538,7 @@ QSI_DEF(SystemProcessorInformation)
 /* Class 2 - Performance Information */
 QSI_DEF(SystemPerformanceInformation)
 {
+       ULONG IdleUser, IdleKernel;
        PSYSTEM_PERFORMANCE_INFORMATION Spi
                = (PSYSTEM_PERFORMANCE_INFORMATION) Buffer;
 
@@ -426,8 +555,8 @@ QSI_DEF(SystemPerformanceInformation)
 
        TheIdleProcess = PsIdleProcess;
 
-       Spi->IdleProcessTime.QuadPart = TheIdleProcess->Pcb.KernelTime * 100000LL;
-
+       IdleKernel = KeQueryRuntimeProcess(&TheIdleProcess->Pcb, &IdleUser);
+       Spi->IdleProcessTime.QuadPart = UInt32x32To64(IdleKernel, KeMaximumIncrement);
        Spi->IoReadTransferCount = IoReadTransferCount;
        Spi->IoWriteTransferCount = IoWriteTransferCount;
        Spi->IoOtherTransferCount = IoOtherTransferCount;
@@ -437,7 +566,7 @@ QSI_DEF(SystemPerformanceInformation)
 
        Spi->AvailablePages = MmStats.NrFreePages;
 /*
-        Add up all the used "Commitied" memory + pagefile.
+        Add up all the used "Committed" memory + pagefile.
         Not sure this is right. 8^\
  */
        Spi->CommittedPages = MiMemoryConsumers[MC_PPOOL].PagesUsed +
@@ -548,7 +677,7 @@ QSI_DEF(SystemTimeOfDayInformation)
 
   KeQuerySystemTime(&CurrentTime);
 
-  Sti->BootTime= SystemBootTime;
+  Sti->BootTime= KeBootTime;
   Sti->CurrentTime = CurrentTime;
   Sti->TimeZoneBias.QuadPart = ExpTimeZoneBias.QuadPart;
   Sti->TimeZoneId = ExpTimeZoneId;
@@ -571,10 +700,11 @@ QSI_DEF(SystemProcessInformation)
 {
        ULONG ovlSize = 0, nThreads;
        PEPROCESS pr = NULL, syspr;
-       unsigned char *pCur;
+       PUCHAR pCur;
+       ULONG TotalUser, TotalKernel;
        NTSTATUS Status = STATUS_SUCCESS;
 
-       _SEH_TRY
+       _SEH2_TRY
        {
                /* scan the process list */
 
@@ -585,10 +715,11 @@ QSI_DEF(SystemProcessInformation)
 
                if (Size < sizeof(SYSTEM_PROCESS_INFORMATION))
                {
-                       return (STATUS_INFO_LENGTH_MISMATCH); // in case buffer size is too small
+                       _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH); // in case buffer size is too small
                }
+               RtlZeroMemory(Spi, Size);
 
-               syspr = PsGetNextProcess(NULL);
+               syspr = PsIdleProcess;
                pr = syspr;
                pCur = (unsigned char *)Spi;
 
@@ -600,7 +731,7 @@ QSI_DEF(SystemProcessInformation)
                        int inLen=32; // image name len in bytes
                        PLIST_ENTRY current_entry;
                        PETHREAD current;
-            PSYSTEM_THREAD_INFORMATION ThreadInfo;
+                       PSYSTEM_THREAD_INFORMATION ThreadInfo;
 
                        SpiCur = (PSYSTEM_PROCESS_INFORMATION)pCur;
 
@@ -621,17 +752,15 @@ QSI_DEF(SystemProcessInformation)
                                *ReqSize = ovlSize;
                                ObDereferenceObject(pr);
 
-                               return (STATUS_INFO_LENGTH_MISMATCH); // in case buffer size is too small
+                               _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH); // in case buffer size is too small
                        }
 
                        // fill system information
                        SpiCur->NextEntryOffset = curSize+inLen; // relative offset to the beginnnig of the next structure
                        SpiCur->NumberOfThreads = nThreads;
                        SpiCur->CreateTime = pr->CreateTime;
-                       SpiCur->UserTime.QuadPart = pr->Pcb.UserTime * 100000LL;
-                       SpiCur->KernelTime.QuadPart = pr->Pcb.KernelTime * 100000LL;
                        SpiCur->ImageName.Length = strlen(pr->ImageFileName) * sizeof(WCHAR);
-                       SpiCur->ImageName.MaximumLength = inLen;
+                       SpiCur->ImageName.MaximumLength = (USHORT)inLen;
                        SpiCur->ImageName.Buffer = (void*)(pCur+curSize);
 
                        // copy name to the end of the struct
@@ -642,7 +771,7 @@ QSI_DEF(SystemProcessInformation)
                        }
                        else
                        {
-                               RtlInitUnicodeString(&SpiCur->ImageName, NULL);
+                               RtlInitUnicodeString(&SpiCur->ImageName, NULL);
                        }
 
                        SpiCur->BasePriority = pr->Pcb.BasePriority;
@@ -658,21 +787,20 @@ QSI_DEF(SystemProcessInformation)
                        SpiCur->QuotaPagedPoolUsage = pr->QuotaUsage[0];
                        SpiCur->QuotaPeakNonPagedPoolUsage = pr->QuotaPeak[1];
                        SpiCur->QuotaNonPagedPoolUsage = pr->QuotaUsage[1];
-                       SpiCur->PagefileUsage = pr->QuotaUsage[3];
-                       SpiCur->PeakPagefileUsage = pr->QuotaPeak[3];
+                       SpiCur->PagefileUsage = pr->QuotaUsage[2];
+                       SpiCur->PeakPagefileUsage = pr->QuotaPeak[2];
                        SpiCur->PrivatePageCount = pr->CommitCharge;
-            ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(SpiCur + 1);
+                       ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(SpiCur + 1);
 
-                       current_entry = pr->ThreadListHead.Flink;
-                       while (current_entry != &pr->ThreadListHead)
+                       current_entry = pr->ThreadListHead.Flink;
+                       while (current_entry != &pr->ThreadListHead)
                        {
                                current = CONTAINING_RECORD(current_entry, ETHREAD,
                                                            ThreadListEntry);
 
-                
-                               ThreadInfo->KernelTime.QuadPart = current->Tcb.KernelTime * 100000LL;
-                               ThreadInfo->UserTime.QuadPart = current->Tcb.UserTime * 100000LL;
-//                             SpiCur->TH[i].CreateTime = current->CreateTime;
+                               ThreadInfo->KernelTime.QuadPart = UInt32x32To64(current->Tcb.KernelTime, KeMaximumIncrement);
+                               ThreadInfo->UserTime.QuadPart = UInt32x32To64(current->Tcb.UserTime, KeMaximumIncrement);
+                               ThreadInfo->CreateTime.QuadPart = current->CreateTime.QuadPart;
                                ThreadInfo->WaitTime = current->Tcb.WaitTime;
                                ThreadInfo->StartAddress = (PVOID) current->StartAddress;
                                ThreadInfo->ClientId = current->Cid;
@@ -681,10 +809,19 @@ QSI_DEF(SystemProcessInformation)
                                ThreadInfo->ContextSwitches = current->Tcb.ContextSwitches;
                                ThreadInfo->ThreadState = current->Tcb.State;
                                ThreadInfo->WaitReason = current->Tcb.WaitReason;
+
                                ThreadInfo++;
                                current_entry = current_entry->Flink;
                        }
 
+                       /* Query total user/kernel times of a process */
+                       TotalKernel = KeQueryRuntimeProcess(&pr->Pcb, &TotalUser);
+                       SpiCur->UserTime.QuadPart = UInt32x32To64(TotalUser, KeMaximumIncrement);
+                       SpiCur->KernelTime.QuadPart = UInt32x32To64(TotalKernel, KeMaximumIncrement);
+
+                       /* Handle idle process entry */
+                       if (pr == PsIdleProcess) pr = NULL;
+
                        pr = PsGetNextProcess(pr);
                        nThreads = 0;
                        if ((pr == syspr) || (pr == NULL))
@@ -700,13 +837,13 @@ QSI_DEF(SystemProcessInformation)
                        ObDereferenceObject(pr);
                Status = STATUS_SUCCESS;
        }
-       _SEH_HANDLE
+       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
        {
                if(pr != NULL)
                        ObDereferenceObject(pr);
-               Status = _SEH_GetExceptionCode();
+               Status = _SEH2_GetExceptionCode();
        }
-       _SEH_END
+       _SEH2_END
 
        *ReqSize = ovlSize;
        return Status;
@@ -751,37 +888,39 @@ QSI_DEF(SystemDeviceInformation)
 /* Class 8 - Processor Performance Information */
 QSI_DEF(SystemProcessorPerformanceInformation)
 {
-       PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION Spi
-               = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) Buffer;
+    PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION Spi
+        = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) Buffer;
 
-        LONG i;
-       LARGE_INTEGER CurrentTime;
-       PKPRCB Prcb;
+    LONG i;
+    ULONG TotalTime;
+    LARGE_INTEGER CurrentTime;
+    PKPRCB Prcb;
 
-       *ReqSize = KeNumberProcessors * sizeof (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
-       /*
-        * Check user buffer's size
-        */
-       if (Size < KeNumberProcessors * sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION))
-       {
-               return (STATUS_INFO_LENGTH_MISMATCH);
-       }
+    *ReqSize = KeNumberProcessors * sizeof (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
 
-       CurrentTime.QuadPart = KeQueryInterruptTime();
-       Prcb = ((PKPCR)KPCR_BASE)->Prcb;
-       for (i = 0; i < KeNumberProcessors; i++)
-       {
-          Spi->IdleTime.QuadPart = (Prcb->IdleThread->KernelTime + Prcb->IdleThread->UserTime) * 100000LL; // IdleTime
-           Spi->KernelTime.QuadPart =  Prcb->KernelTime * 100000LL; // KernelTime
-           Spi->UserTime.QuadPart = Prcb->UserTime * 100000LL;
-           Spi->DpcTime.QuadPart = Prcb->DpcTime * 100000LL;
-           Spi->InterruptTime.QuadPart = Prcb->InterruptTime * 100000LL;
-           Spi->InterruptCount = Prcb->InterruptCount; // Interrupt Count
-          Spi++;
-          Prcb = (PKPRCB)((ULONG_PTR)Prcb + PAGE_SIZE);
-       }
+    /* Check user buffer's size */
+    if (Size < *ReqSize)
+    {
+        return STATUS_INFO_LENGTH_MISMATCH;
+    }
 
-       return (STATUS_SUCCESS);
+    CurrentTime.QuadPart = KeQueryInterruptTime();
+    Prcb = KeGetPcr()->Prcb;
+    for (i = 0; i < KeNumberProcessors; i++)
+    {
+        /* Calculate total user and kernel times */
+        TotalTime = Prcb->IdleThread->KernelTime + Prcb->IdleThread->UserTime;
+        Spi->IdleTime.QuadPart = UInt32x32To64(TotalTime, KeMaximumIncrement);
+        Spi->KernelTime.QuadPart =  UInt32x32To64(Prcb->KernelTime, KeMaximumIncrement);
+        Spi->UserTime.QuadPart = UInt32x32To64(Prcb->UserTime, KeMaximumIncrement);
+        Spi->DpcTime.QuadPart = UInt32x32To64(Prcb->DpcTime, KeMaximumIncrement);
+        Spi->InterruptTime.QuadPart = UInt32x32To64(Prcb->InterruptTime, KeMaximumIncrement);
+        Spi->InterruptCount = Prcb->InterruptCount;
+        Spi++;
+        Prcb = (PKPRCB)((ULONG_PTR)Prcb + PAGE_SIZE);
+    }
+
+    return STATUS_SUCCESS;
 }
 
 /* Class 9 - Flags Information */
@@ -817,7 +956,12 @@ QSI_DEF(SystemCallTimeInformation)
 /* Class 11 - Module Information */
 QSI_DEF(SystemModuleInformation)
 {
-       return LdrpQueryModuleInformation(Buffer, Size, ReqSize);
+    extern LIST_ENTRY PsLoadedModuleList;
+    return ExpQueryModuleInformation(&PsLoadedModuleList,
+                                     NULL,
+                                     (PRTL_PROCESS_MODULES)Buffer,
+                                     Size,
+                                     ReqSize);
 }
 
 /* Class 12 - Locks Information */
@@ -919,7 +1063,7 @@ QSI_DEF(SystemHandleInformation)
 
             for (Count = 0; HandleCount > 0 ; HandleCount--)
                {
-                 Shi->Handles[i].UniqueProcessId = (ULONG)pr->UniqueProcessId;
+                 Shi->Handles[i].UniqueProcessId = (USHORT)(ULONG_PTR)pr->UniqueProcessId;
                  Count++;
                  i++;
                }
@@ -1044,6 +1188,7 @@ QSI_DEF(SystemPoolTagInformation)
 QSI_DEF(SystemInterruptInformation)
 {
   PKPRCB Prcb;
+  PKPCR Pcr;
   LONG i;
   ULONG ti;
   PSYSTEM_INTERRUPT_INFORMATION sii = (PSYSTEM_INTERRUPT_INFORMATION)Buffer;
@@ -1055,17 +1200,25 @@ QSI_DEF(SystemInterruptInformation)
 
   ti = KeQueryTimeIncrement();
 
-  Prcb = ((PKPCR)KPCR_BASE)->Prcb;
   for (i = 0; i < KeNumberProcessors; i++)
   {
-    //sii->ContextSwitches = Prcb->KeContextSwitches;
-    sii->DpcCount = 0; /* FIXME */
-    sii->DpcRate = 0; /* FIXME */
+    Prcb = KiProcessorBlock[i];
+#ifdef _M_AMD64
+    Pcr = CONTAINING_RECORD(Prcb, KPCR, CurrentPrcb);
+#else
+    Pcr = CONTAINING_RECORD(Prcb, KPCR, Prcb);
+#endif
+#ifdef _M_ARM // This code should probably be done differently
+    sii->ContextSwitches = Pcr->ContextSwitches;
+#else
+    sii->ContextSwitches = ((PKIPCR)Pcr)->ContextSwitches;
+#endif
+    sii->DpcCount = Prcb->DpcData[0].DpcCount;
+    sii->DpcRate = Prcb->DpcRequestRate;
     sii->TimeIncrement = ti;
-    sii->DpcBypassCount = 0; /* FIXME */
-    sii->ApcBypassCount = 0; /* FIXME */
+    sii->DpcBypassCount = 0;
+    sii->ApcBypassCount = 0;
     sii++;
-    Prcb = (PKPRCB)((ULONG_PTR)Prcb + PAGE_SIZE);
   }
 
   return STATUS_SUCCESS;
@@ -1119,33 +1272,101 @@ QSI_DEF(SystemFullMemoryInformation)
 }
 
 /* Class 26 - Load Image */
-SSI_DEF(SystemLoadImage)
-{
-  PSYSTEM_GDI_DRIVER_INFORMATION Sli = (PSYSTEM_GDI_DRIVER_INFORMATION)Buffer;
-
-  if (sizeof(SYSTEM_GDI_DRIVER_INFORMATION) != Size)
+SSI_DEF(SystemLoadGdiDriverInformation)
+{
+    PSYSTEM_GDI_DRIVER_INFORMATION DriverInfo = (PVOID)Buffer;
+    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+    UNICODE_STRING ImageName;
+    PVOID ImageBase;
+    PLDR_DATA_TABLE_ENTRY ModuleObject;
+    ULONG_PTR EntryPoint;
+    NTSTATUS Status;
+    ULONG DirSize;
+    PIMAGE_NT_HEADERS NtHeader;
+
+    /* Validate size */
+    if (Size != sizeof(SYSTEM_GDI_DRIVER_INFORMATION))
     {
-      return(STATUS_INFO_LENGTH_MISMATCH);
+        /* Incorrect buffer length, fail */
+        return STATUS_INFO_LENGTH_MISMATCH;
     }
 
-  return(LdrpLoadImage(&Sli->DriverName,
-                      &Sli->ImageAddress,
-                      &Sli->SectionPointer,
-                      &Sli->EntryPoint,
-                      (PVOID)&Sli->ExportSectionPointer));
+    /* Only kernel-mode can call this function */
+    if (PreviousMode != KernelMode) return STATUS_PRIVILEGE_NOT_HELD;
+
+    /* Load the driver */
+    ImageName = DriverInfo->DriverName;
+    Status = MmLoadSystemImage(&ImageName,
+                               NULL,
+                               NULL,
+                               0,
+                               (PVOID)&ModuleObject,
+                               &ImageBase);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Return the export pointer */
+    DriverInfo->ExportSectionPointer =
+        RtlImageDirectoryEntryToData(ImageBase,
+                                     TRUE,
+                                     IMAGE_DIRECTORY_ENTRY_EXPORT,
+                                     &DirSize);
+
+    /* Get the entrypoint */
+    NtHeader = RtlImageNtHeader(ImageBase);
+    EntryPoint = NtHeader->OptionalHeader.AddressOfEntryPoint;
+    EntryPoint += (ULONG_PTR)ImageBase;
+
+    /* Save other data */
+    DriverInfo->ImageAddress = ImageBase;
+    DriverInfo->SectionPointer = NULL;
+    DriverInfo->EntryPoint = (PVOID)EntryPoint;
+    DriverInfo->ImageLength = NtHeader->OptionalHeader.SizeOfImage;
+
+    /* All is good */
+    return STATUS_SUCCESS;
 }
 
 /* Class 27 - Unload Image */
-SSI_DEF(SystemUnloadImage)
+SSI_DEF(SystemUnloadGdiDriverInformation)
 {
-  PVOID Sui = (PVOID)Buffer;
+    PLDR_DATA_TABLE_ENTRY LdrEntry;
+    PLIST_ENTRY NextEntry;
+    PVOID BaseAddr = *((PVOID*)Buffer);
 
-  if (sizeof(PVOID) != Size)
+    if(Size != sizeof(PVOID))
+        return STATUS_INFO_LENGTH_MISMATCH;
+
+    if(KeGetPreviousMode() != KernelMode)
+        return STATUS_PRIVILEGE_NOT_HELD;
+
+    // Scan the module list
+    NextEntry = PsLoadedModuleList.Flink;
+    while(NextEntry != &PsLoadedModuleList)
     {
-      return(STATUS_INFO_LENGTH_MISMATCH);
+        LdrEntry = CONTAINING_RECORD(NextEntry,
+                                     LDR_DATA_TABLE_ENTRY,
+                                     InLoadOrderLinks);
+
+        if (LdrEntry->DllBase == BaseAddr)
+        {
+            // Found it.
+            break;
+        }
+
+        NextEntry = NextEntry->Flink;
+    }
+
+    // Check if we found the image
+    if(NextEntry != &PsLoadedModuleList)
+    {
+        return MmUnloadSystemImage(LdrEntry);
+    }
+    else
+    {
+        DPRINT1("Image 0x%x not found.\n", BaseAddr);
+        return STATUS_DLL_NOT_FOUND;
     }
 
-  return(LdrpUnloadImage(Sui));
 }
 
 /* Class 28 - Time Adjustment Information */
@@ -1272,16 +1493,78 @@ SSI_DEF(SystemRegistryQuotaInformation)
 }
 
 /* Class 38 - Load And Call Image */
-SSI_DEF(SystemLoadAndCallImage)
-{
-  PUNICODE_STRING Slci = (PUNICODE_STRING)Buffer;
+SSI_DEF(SystemExtendServiceTableInformation)
+{
+    UNICODE_STRING ImageName;
+    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+    PLDR_DATA_TABLE_ENTRY ModuleObject;
+    NTSTATUS Status;
+    PIMAGE_NT_HEADERS NtHeader;
+    DRIVER_OBJECT Win32k;
+    PDRIVER_INITIALIZE DriverInit;
+    PVOID ImageBase;
+    ULONG_PTR EntryPoint;
+
+    /* Validate the size */
+    if (Size != sizeof(UNICODE_STRING)) return STATUS_INFO_LENGTH_MISMATCH;
+
+    /* Check who is calling */
+    if (PreviousMode != KernelMode)
+    {
+        /* Make sure we can load drivers */
+        if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, UserMode))
+        {
+            /* FIXME: We can't, fail */
+            //return STATUS_PRIVILEGE_NOT_HELD;
+        }
 
-  if (sizeof(UNICODE_STRING) != Size)
+        /* Probe and capture the driver name */
+        ProbeAndCaptureUnicodeString(&ImageName, UserMode, Buffer);
+
+        /* Force kernel as previous mode */
+        return ZwSetSystemInformation(SystemExtendServiceTableInformation,
+                                      &ImageName,
+                                      sizeof(ImageName));
+    }
+
+    /* Just copy the string */
+    ImageName = *(PUNICODE_STRING)Buffer;
+
+    /* Load the image */
+    Status = MmLoadSystemImage(&ImageName,
+                               NULL,
+                               NULL,
+                               0,
+                               (PVOID)&ModuleObject,
+                               &ImageBase);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Get the headers */
+    NtHeader = RtlImageNtHeader(ImageBase);
+    if (!NtHeader)
     {
-      return(STATUS_INFO_LENGTH_MISMATCH);
+        /* Fail */
+        MmUnloadSystemImage(ModuleObject);
+        return STATUS_INVALID_IMAGE_FORMAT;
     }
 
-  return(LdrpLoadAndCallImage(Slci));
+    /* Get the entrypoint */
+    EntryPoint = NtHeader->OptionalHeader.AddressOfEntryPoint;
+    EntryPoint += (ULONG_PTR)ImageBase;
+    DriverInit = (PDRIVER_INITIALIZE)EntryPoint;
+
+    /* Create a dummy device */
+    RtlZeroMemory(&Win32k, sizeof(Win32k));
+    ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
+    Win32k.DriverStart = ImageBase;
+
+    /* Call it */
+    Status = (DriverInit)(&Win32k, NULL);
+    ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+    /* Unload if we failed */
+    if (!NT_SUCCESS(Status)) MmUnloadSystemImage(ModuleObject);
+    return Status;
 }
 
 /* Class 39 - Priority Separation */
@@ -1493,8 +1776,8 @@ CallQS [] =
        SI_QX(SystemInterruptInformation),
        SI_QS(SystemDpcBehaviourInformation),
        SI_QX(SystemFullMemoryInformation), /* it should be SI_XX */
-       SI_XS(SystemLoadImage),
-       SI_XS(SystemUnloadImage),
+       SI_XS(SystemLoadGdiDriverInformation),
+       SI_XS(SystemUnloadGdiDriverInformation),
        SI_QS(SystemTimeAdjustmentInformation),
        SI_QX(SystemSummaryMemoryInformation), /* it should be SI_XX */
        SI_QX(SystemNextEventIdInformation), /* it should be SI_XX */
@@ -1505,7 +1788,7 @@ CallQS [] =
        SI_QX(SystemKernelDebuggerInformation),
        SI_QX(SystemContextSwitchInformation),
        SI_QS(SystemRegistryQuotaInformation),
-       SI_XS(SystemLoadAndCallImage),
+       SI_XS(SystemExtendServiceTableInformation),
        SI_XS(SystemPrioritySeperation),
        SI_QX(SystemPlugPlayBusInformation), /* it should be SI_XX */
        SI_QX(SystemDockInformation), /* it should be SI_XX */
@@ -1523,11 +1806,14 @@ CallQS [] =
        SI_QX(SystemSessionProcessesInformation)
 };
 
+C_ASSERT(SystemBasicInformation == 0);
+#define MIN_SYSTEM_INFO_CLASS (SystemBasicInformation)
+#define MAX_SYSTEM_INFO_CLASS (sizeof(CallQS) / sizeof(CallQS[0]))
 
 /*
  * @implemented
  */
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 NtQuerySystemInformation (IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
                          OUT PVOID SystemInformation,
                          IN ULONG Length,
@@ -1538,28 +1824,25 @@ NtQuerySystemInformation (IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
   NTSTATUS FStatus = STATUS_NOT_IMPLEMENTED;
 
   PAGED_CODE();
-  
+
   PreviousMode = ExGetPreviousMode();
-  
-  _SEH_TRY
+
+  _SEH2_TRY
     {
       if (PreviousMode != KernelMode)
         {
           /* SystemKernelDebuggerInformation needs only BOOLEAN alignment */
-          ProbeForWrite(SystemInformation, Length, 1); 
+          ProbeForWrite(SystemInformation, Length, 1);
           if (UnsafeResultLength != NULL)
             ProbeForWriteUlong(UnsafeResultLength);
         }
 
-      /* Clear user buffer. */
-      RtlZeroMemory(SystemInformation, Length);
-
       /*
        * Check the request is valid.
        */
-      if (SystemInformationClass >= MaxSystemInfoClass)
+      if (SystemInformationClass >= MAX_SYSTEM_INFO_CLASS)
         {
-          return (STATUS_INVALID_INFO_CLASS);
+          _SEH2_YIELD(return STATUS_INVALID_INFO_CLASS);
         }
 
       if (NULL != CallQS [SystemInformationClass].Query)
@@ -1574,15 +1857,7 @@ NtQuerySystemInformation (IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
            {
               if (PreviousMode != KernelMode)
                 {
-                  _SEH_TRY
-                    {
                       *UnsafeResultLength = ResultLength;
-                    }
-                  _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
-                    {
-                      FStatus = _SEH_GetExceptionCode();
-                    }
-                  _SEH_END;
                 }
               else
                 {
@@ -1591,18 +1866,18 @@ NtQuerySystemInformation (IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
            }
        }
     }
-  _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+  _SEH2_EXCEPT(ExSystemExceptionFilter())
     {
-      FStatus = _SEH_GetExceptionCode();
+      FStatus = _SEH2_GetExceptionCode();
     }
-  _SEH_END;
+  _SEH2_END;
 
   return (FStatus);
 }
 
 
 NTSTATUS
-STDCALL
+NTAPI
 NtSetSystemInformation (
        IN      SYSTEM_INFORMATION_CLASS        SystemInformationClass,
        IN      PVOID                           SystemInformation,
@@ -1632,8 +1907,8 @@ NtSetSystemInformation (
        /*
         * Check the request is valid.
         */
-       if (    (SystemInformationClass >= SystemBasicInformation)
-               && (SystemInformationClass < MaxSystemInfoClass)
+       if (    (SystemInformationClass >= MIN_SYSTEM_INFO_CLASS)
+               && (SystemInformationClass < MAX_SYSTEM_INFO_CLASS)
                )
        {
                if (NULL != CallQS [SystemInformationClass].Set)
@@ -1652,18 +1927,39 @@ NtSetSystemInformation (
 
 
 NTSTATUS
-STDCALL
+NTAPI
 NtFlushInstructionCache (
        IN      HANDLE  ProcessHandle,
        IN      PVOID   BaseAddress,
        IN      ULONG   NumberOfBytesToFlush
        )
 {
-        PAGED_CODE();
-
-       __asm__("wbinvd\n");
-       return STATUS_SUCCESS;
+    PAGED_CODE();
+
+#if defined(_M_IX86)
+    __wbinvd();
+#elif defined(_M_PPC)
+    __asm__ __volatile__("tlbsync");
+#elif defined(_M_MIPS)
+    DPRINT1("NtFlushInstructionCache() is not implemented\n");
+    for (;;);
+#elif defined(_M_ARM)
+    __asm__ __volatile__("mov r1, #0; mcr p15, 0, r1, c7, c5, 0");
+#elif defined(_M_AMD64)
+    DPRINT1("NtFlushInstructionCache() is not implemented\n");
+    for (;;);
+#else
+#error Unknown architecture
+#endif
+    return STATUS_SUCCESS;
 }
 
+ULONG
+NTAPI
+NtGetCurrentProcessorNumber(VOID)
+{
+    /* Just return the CPU */
+    return KeGetCurrentProcessorNumber();
+}
 
-/* EOF */
+/* EOF */
\ No newline at end of file