xref: /reactos/ntoskrnl/ex/sysinfo.c (revision 71fefa32)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            ntoskrnl/ex/sysinfo.c
5  * PURPOSE:         System information functions
6  *
7  * PROGRAMMERS:     David Welch (welch@mcmail.com)
8  *                  Aleksey Bragin (aleksey@reactos.org)
9  */
10 
11 /* INCLUDES *****************************************************************/
12 
13 #include <ntoskrnl.h>
14 #include <wmidata.h>
15 #include <wmistr.h>
16 #define NDEBUG
17 #include <debug.h>
18 
19 /* The maximum size of an environment value (in bytes) */
20 #define MAX_ENVVAL_SIZE 1024
21 
22 #define SIG_ACPI 0x41435049
23 #define SIG_FIRM 0x4649524D
24 #define SIG_RSMB 0x52534D42
25 
26 extern LIST_ENTRY HandleTableListHead;
27 extern EX_PUSH_LOCK HandleTableListLock;
28 
29 FAST_MUTEX ExpEnvironmentLock;
30 ERESOURCE ExpFirmwareTableResource;
31 LIST_ENTRY ExpFirmwareTableProviderListHead;
32 
33 FORCEINLINE
34 NTSTATUS
35 ExpConvertLdrModuleToRtlModule(IN ULONG ModuleCount,
36                                IN PLDR_DATA_TABLE_ENTRY LdrEntry,
37                                OUT PRTL_PROCESS_MODULE_INFORMATION ModuleInfo)
38 {
39     PCHAR p;
40     NTSTATUS Status;
41     ANSI_STRING ModuleName;
42 
43     /* Fill it out */
44     ModuleInfo->MappedBase = NULL;
45     ModuleInfo->ImageBase = LdrEntry->DllBase;
46     ModuleInfo->ImageSize = LdrEntry->SizeOfImage;
47     ModuleInfo->Flags = LdrEntry->Flags;
48     ModuleInfo->LoadCount = LdrEntry->LoadCount;
49     ModuleInfo->LoadOrderIndex = (USHORT)ModuleCount;
50     ModuleInfo->InitOrderIndex = 0;
51 
52     /* Setup name */
53     RtlInitEmptyAnsiString(&ModuleName,
54                            ModuleInfo->FullPathName,
55                            sizeof(ModuleInfo->FullPathName));
56 
57     /* Convert it */
58     Status = RtlUnicodeStringToAnsiString(&ModuleName,
59                                           &LdrEntry->FullDllName,
60                                           FALSE);
61     if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
62     {
63         /* Calculate offset to name */
64         p = ModuleName.Buffer + ModuleName.Length;
65         while ((p > ModuleName.Buffer) && (*--p))
66         {
67             /* Check if we found the separator */
68             if (*p == OBJ_NAME_PATH_SEPARATOR)
69             {
70                 /* We did, break out */
71                 p++;
72                 break;
73             }
74         }
75 
76         /* Set the offset */
77         ModuleInfo->OffsetToFileName = (USHORT)(p - ModuleName.Buffer);
78     }
79     else
80     {
81         /* Return empty name */
82         ModuleInfo->FullPathName[0] = ANSI_NULL;
83         ModuleInfo->OffsetToFileName = 0;
84     }
85 
86     return Status;
87 }
88 
89 NTSTATUS
90 NTAPI
91 ExpQueryModuleInformation(IN PLIST_ENTRY KernelModeList,
92                           IN PLIST_ENTRY UserModeList,
93                           OUT PRTL_PROCESS_MODULES Modules,
94                           IN ULONG Length,
95                           OUT PULONG ReturnLength)
96 {
97     NTSTATUS Status = STATUS_SUCCESS;
98     ULONG RequiredLength;
99     PRTL_PROCESS_MODULE_INFORMATION ModuleInfo;
100     PLDR_DATA_TABLE_ENTRY LdrEntry;
101     ULONG ModuleCount = 0;
102     PLIST_ENTRY NextEntry;
103 
104     /* Setup defaults */
105     RequiredLength = FIELD_OFFSET(RTL_PROCESS_MODULES, Modules);
106     ModuleInfo = &Modules->Modules[0];
107 
108     /* Loop the kernel list */
109     NextEntry = KernelModeList->Flink;
110     while (NextEntry != KernelModeList)
111     {
112         /* Get the entry */
113         LdrEntry = CONTAINING_RECORD(NextEntry,
114                                      LDR_DATA_TABLE_ENTRY,
115                                      InLoadOrderLinks);
116 
117         /* Update size and check if we can manage one more entry */
118         RequiredLength += sizeof(RTL_PROCESS_MODULE_INFORMATION);
119         if (Length >= RequiredLength)
120         {
121             Status = ExpConvertLdrModuleToRtlModule(ModuleCount,
122                                                     LdrEntry,
123                                                     ModuleInfo);
124 
125             /* Go to the next module */
126             ModuleInfo++;
127         }
128         else
129         {
130             /* Set error code */
131             Status = STATUS_INFO_LENGTH_MISMATCH;
132         }
133 
134         /* Update count and move to next entry */
135         ModuleCount++;
136         NextEntry = NextEntry->Flink;
137     }
138 
139     /* Check if caller also wanted user modules */
140     if (UserModeList)
141     {
142         NextEntry = UserModeList->Flink;
143         while (NextEntry != UserModeList)
144         {
145             /* Get the entry */
146             LdrEntry = CONTAINING_RECORD(NextEntry,
147                                          LDR_DATA_TABLE_ENTRY,
148                                          InLoadOrderLinks);
149 
150             /* Update size and check if we can manage one more entry */
151             RequiredLength += sizeof(RTL_PROCESS_MODULE_INFORMATION);
152             if (Length >= RequiredLength)
153             {
154                 Status = ExpConvertLdrModuleToRtlModule(ModuleCount,
155                                                         LdrEntry,
156                                                         ModuleInfo);
157 
158                 /* Go to the next module */
159                 ModuleInfo++;
160             }
161             else
162             {
163                 /* Set error code */
164                 Status = STATUS_INFO_LENGTH_MISMATCH;
165             }
166 
167             /* Update count and move to next entry */
168             ModuleCount++;
169             NextEntry = NextEntry->Flink;
170         }
171     }
172 
173     /* Update return length */
174     if (ReturnLength) *ReturnLength = RequiredLength;
175 
176     /* Validate the length again */
177     if (Length >= FIELD_OFFSET(RTL_PROCESS_MODULES, Modules))
178     {
179         /* Set the final count */
180         Modules->NumberOfModules = ModuleCount;
181     }
182     else
183     {
184         /* Otherwise, we failed */
185         Status = STATUS_INFO_LENGTH_MISMATCH;
186     }
187 
188     /* Done */
189     return Status;
190 }
191 
192 VOID
193 NTAPI
194 ExUnlockUserBuffer(PMDL Mdl)
195 {
196     MmUnlockPages(Mdl);
197     ExFreePoolWithTag(Mdl, TAG_MDL);
198 }
199 
200 NTSTATUS
201 NTAPI
202 ExLockUserBuffer(
203     PVOID BaseAddress,
204     ULONG Length,
205     KPROCESSOR_MODE AccessMode,
206     LOCK_OPERATION Operation,
207     PVOID *MappedSystemVa,
208     PMDL *OutMdl)
209 {
210     PMDL Mdl;
211     PAGED_CODE();
212 
213     *MappedSystemVa = NULL;
214     *OutMdl = NULL;
215 
216     /* Allocate an MDL for the buffer */
217     Mdl = IoAllocateMdl(BaseAddress, Length, FALSE, TRUE, NULL);
218     if (Mdl == NULL)
219     {
220         return STATUS_INSUFFICIENT_RESOURCES;
221     }
222 
223     /* Enter SEH for probing */
224     _SEH2_TRY
225     {
226         MmProbeAndLockPages(Mdl, AccessMode, Operation);
227     }
228     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
229     {
230         ExFreePoolWithTag(Mdl, TAG_MDL);
231         _SEH2_YIELD(return _SEH2_GetExceptionCode());
232     }
233     _SEH2_END;
234 
235     /* Return the safe kernel mode buffer */
236     *MappedSystemVa = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
237     if (*MappedSystemVa == NULL)
238     {
239         ExUnlockUserBuffer(Mdl);
240         return STATUS_INSUFFICIENT_RESOURCES;
241     }
242 
243     /* Return the MDL */
244     *OutMdl = Mdl;
245     return STATUS_SUCCESS;
246 }
247 
248 NTSTATUS
249 NTAPI
250 ExpGetRawSMBiosTable(
251     _Out_opt_ PVOID Buffer,
252     _Out_ ULONG * OutSize,
253     _In_ ULONG BufferSize)
254 {
255     NTSTATUS Status;
256     PVOID DataBlockObject;
257     PWNODE_ALL_DATA AllData;
258     ULONG WMIBufSize;
259 
260     ASSERT(OutSize != NULL);
261     *OutSize = 0;
262 
263     /* Open the data block object for the SMBIOS table */
264     Status = IoWMIOpenBlock(&MSSmBios_RawSMBiosTables_GUID,
265                             WMIGUID_QUERY,
266                             &DataBlockObject);
267     if (!NT_SUCCESS(Status))
268     {
269         DPRINT1("IoWMIOpenBlock failed: 0x%08lx\n", Status);
270         return Status;
271     }
272 
273     /* Query the required buffer size */
274     WMIBufSize = 0;
275     Status = IoWMIQueryAllData(DataBlockObject, &WMIBufSize, NULL);
276     if (!NT_SUCCESS(Status))
277     {
278         DPRINT1("IoWMIOpenBlock failed: 0x%08lx\n", Status);
279         return Status;
280     }
281 
282     AllData = ExAllocatePoolWithTag(PagedPool, WMIBufSize, 'itfS');
283     if (AllData == NULL)
284     {
285         DPRINT1("Failed to allocate %lu bytes for SMBIOS tables\n", WMIBufSize);
286         return STATUS_INSUFFICIENT_RESOURCES;
287     }
288 
289     /* Query the buffer data */
290     Status = IoWMIQueryAllData(DataBlockObject, &WMIBufSize, AllData);
291     if (!NT_SUCCESS(Status))
292     {
293         DPRINT1("IoWMIOpenBlock failed: 0x%08lx\n", Status);
294         ExFreePoolWithTag(AllData, 'itfS');
295         return Status;
296     }
297 
298     Status = STATUS_SUCCESS;
299     *OutSize = AllData->FixedInstanceSize;
300     if (Buffer != NULL)
301     {
302         if (BufferSize >= *OutSize)
303         {
304             RtlMoveMemory(Buffer, AllData + 1, *OutSize);
305         }
306         else
307         {
308             Status = STATUS_BUFFER_TOO_SMALL;
309         }
310     }
311 
312     /* Free the buffer */
313     ExFreePoolWithTag(AllData, 'itfS');
314     return Status;
315 }
316 
317 /* FUNCTIONS *****************************************************************/
318 
319 /*
320  * @implemented
321  */
322 VOID
323 NTAPI
324 ExGetCurrentProcessorCpuUsage(PULONG CpuUsage)
325 {
326     PKPRCB Prcb;
327     ULONG TotalTime;
328     ULONGLONG ScaledIdle;
329 
330     Prcb = KeGetCurrentPrcb();
331 
332     ScaledIdle = (ULONGLONG)Prcb->IdleThread->KernelTime * 100;
333     TotalTime = Prcb->KernelTime + Prcb->UserTime;
334     if (TotalTime != 0)
335         *CpuUsage = (ULONG)(100 - (ScaledIdle / TotalTime));
336     else
337         *CpuUsage = 0;
338 }
339 
340 /*
341  * @implemented
342  */
343 VOID
344 NTAPI
345 ExGetCurrentProcessorCounts(PULONG ThreadKernelTime,
346                             PULONG TotalCpuTime,
347                             PULONG ProcessorNumber)
348 {
349     PKPRCB Prcb;
350 
351     Prcb = KeGetCurrentPrcb();
352 
353     *ThreadKernelTime = Prcb->KernelTime + Prcb->UserTime;
354     *TotalCpuTime = Prcb->CurrentThread->KernelTime;
355     *ProcessorNumber = KeGetCurrentProcessorNumber();
356 }
357 
358 /*
359  * @implemented
360  */
361 BOOLEAN
362 NTAPI
363 ExIsProcessorFeaturePresent(IN ULONG ProcessorFeature)
364 {
365     /* Quick check to see if it exists at all */
366     if (ProcessorFeature >= PROCESSOR_FEATURE_MAX) return(FALSE);
367 
368     /* Return our support for it */
369     return(SharedUserData->ProcessorFeatures[ProcessorFeature]);
370 }
371 
372 /*
373  * @implemented
374  */
375 BOOLEAN
376 NTAPI
377 ExVerifySuite(SUITE_TYPE SuiteType)
378 {
379     if (SuiteType == Personal) return TRUE;
380     return FALSE;
381 }
382 
383 NTSTATUS
384 NTAPI
385 NtQuerySystemEnvironmentValue(IN PUNICODE_STRING VariableName,
386                               OUT PWSTR ValueBuffer,
387                               IN ULONG ValueBufferLength,
388                               IN OUT PULONG ReturnLength OPTIONAL)
389 {
390     ANSI_STRING AName;
391     UNICODE_STRING WName;
392     ARC_STATUS Result;
393     PCH AnsiValueBuffer;
394     ANSI_STRING AValue;
395     UNICODE_STRING WValue;
396     KPROCESSOR_MODE PreviousMode;
397     NTSTATUS Status;
398     PAGED_CODE();
399 
400     /* Check if the call came from user mode */
401     PreviousMode = ExGetPreviousMode();
402     if (PreviousMode != KernelMode)
403     {
404         _SEH2_TRY
405         {
406             /* Probe the input and output buffers */
407             ProbeForRead(VariableName, sizeof(UNICODE_STRING), sizeof(ULONG));
408             ProbeForWrite(ValueBuffer, ValueBufferLength, sizeof(WCHAR));
409             if (ReturnLength != NULL) ProbeForWriteUlong(ReturnLength);
410         }
411         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
412         {
413             /* Return the exception code */
414             _SEH2_YIELD(return _SEH2_GetExceptionCode());
415         }
416         _SEH2_END;
417     }
418 
419     /* According to NTInternals the SeSystemEnvironmentName privilege is required! */
420     if (!SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege, PreviousMode))
421     {
422         DPRINT1("NtQuerySystemEnvironmentValue: Caller requires the SeSystemEnvironmentPrivilege privilege!\n");
423         return STATUS_PRIVILEGE_NOT_HELD;
424     }
425 
426     /* Copy the name to kernel space if necessary */
427     Status = ProbeAndCaptureUnicodeString(&WName, PreviousMode, VariableName);
428     if (!NT_SUCCESS(Status)) return Status;
429 
430     /* Convert the name to ANSI and release the captured UNICODE string */
431     Status = RtlUnicodeStringToAnsiString(&AName, &WName, TRUE);
432     ReleaseCapturedUnicodeString(&WName, PreviousMode);
433     if (!NT_SUCCESS(Status)) return Status;
434 
435     /* Allocate a buffer for the ANSI environment variable */
436     AnsiValueBuffer = ExAllocatePoolWithTag(NonPagedPool, MAX_ENVVAL_SIZE, 'rvnE');
437     if (AnsiValueBuffer == NULL)
438     {
439         RtlFreeAnsiString(&AName);
440         return STATUS_INSUFFICIENT_RESOURCES;
441     }
442 
443     /* Get the environment variable and free the ANSI name */
444     Result = HalGetEnvironmentVariable(AName.Buffer,
445                                        MAX_ENVVAL_SIZE,
446                                        AnsiValueBuffer);
447     RtlFreeAnsiString(&AName);
448 
449     /* Check if we had success */
450     if (Result == ESUCCESS)
451     {
452         /* Copy the result back to the caller. */
453         _SEH2_TRY
454         {
455             /* Initialize ANSI string from the result */
456             RtlInitAnsiString(&AValue, AnsiValueBuffer);
457 
458             /* Initialize a UNICODE string from the callers buffer */
459             RtlInitEmptyUnicodeString(&WValue, ValueBuffer, (USHORT)ValueBufferLength);
460 
461             /* Convert the result to UNICODE */
462             Status = RtlAnsiStringToUnicodeString(&WValue, &AValue, FALSE);
463 
464             if (ReturnLength != NULL)
465                 *ReturnLength = WValue.Length;
466         }
467         _SEH2_EXCEPT(ExSystemExceptionFilter())
468         {
469             Status = _SEH2_GetExceptionCode();
470         }
471         _SEH2_END;
472     }
473     else
474     {
475         Status = STATUS_UNSUCCESSFUL;
476     }
477 
478     /* Free the allocated ANSI value buffer */
479     ExFreePoolWithTag(AnsiValueBuffer, 'rvnE');
480 
481     return Status;
482 }
483 
484 
485 NTSTATUS
486 NTAPI
487 NtSetSystemEnvironmentValue(IN PUNICODE_STRING VariableName,
488                             IN PUNICODE_STRING Value)
489 {
490     UNICODE_STRING CapturedName, CapturedValue;
491     ANSI_STRING AName, AValue;
492     KPROCESSOR_MODE PreviousMode;
493     NTSTATUS Status;
494 
495     PAGED_CODE();
496 
497     PreviousMode = ExGetPreviousMode();
498 
499     /*
500      * Copy the strings to kernel space if necessary
501      */
502     Status = ProbeAndCaptureUnicodeString(&CapturedName,
503                                           PreviousMode,
504                                           VariableName);
505     if (NT_SUCCESS(Status))
506     {
507         Status = ProbeAndCaptureUnicodeString(&CapturedValue,
508                                               PreviousMode,
509                                               Value);
510         if (NT_SUCCESS(Status))
511         {
512             /*
513              * according to ntinternals the SeSystemEnvironmentName privilege is required!
514              */
515             if (SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege,
516                                        PreviousMode))
517             {
518                 /*
519                  * convert the strings to ANSI
520                  */
521                 Status = RtlUnicodeStringToAnsiString(&AName,
522                                                       &CapturedName,
523                                                       TRUE);
524                 if (NT_SUCCESS(Status))
525                 {
526                     Status = RtlUnicodeStringToAnsiString(&AValue,
527                                                           &CapturedValue,
528                                                           TRUE);
529                     if (NT_SUCCESS(Status))
530                     {
531                         ARC_STATUS Result = HalSetEnvironmentVariable(AName.Buffer,
532                                                                       AValue.Buffer);
533 
534                         Status = (Result ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
535                     }
536                 }
537             }
538             else
539             {
540                 DPRINT1("NtSetSystemEnvironmentValue: Caller requires the SeSystemEnvironmentPrivilege privilege!\n");
541                 Status = STATUS_PRIVILEGE_NOT_HELD;
542             }
543 
544             ReleaseCapturedUnicodeString(&CapturedValue,
545                                          PreviousMode);
546         }
547 
548         ReleaseCapturedUnicodeString(&CapturedName,
549                                      PreviousMode);
550     }
551 
552     return Status;
553 }
554 
555 NTSTATUS
556 NTAPI
557 NtEnumerateSystemEnvironmentValuesEx(IN ULONG InformationClass,
558                                      IN PVOID Buffer,
559                                      IN ULONG BufferLength)
560 {
561     UNIMPLEMENTED;
562     return STATUS_NOT_IMPLEMENTED;
563 }
564 
565 NTSTATUS
566 NTAPI
567 NtQuerySystemEnvironmentValueEx(IN PUNICODE_STRING VariableName,
568                                 IN LPGUID VendorGuid,
569                                 IN PVOID Value,
570                                 IN OUT PULONG ReturnLength,
571                                 IN OUT PULONG Attributes)
572 {
573     UNIMPLEMENTED;
574     return STATUS_NOT_IMPLEMENTED;
575 }
576 
577 NTSTATUS
578 NTAPI
579 NtSetSystemEnvironmentValueEx(IN PUNICODE_STRING VariableName,
580                               IN LPGUID VendorGuid,
581                               IN PVOID Value,
582                               IN OUT PULONG ReturnLength,
583                               IN OUT PULONG Attributes)
584 {
585     UNIMPLEMENTED;
586     return STATUS_NOT_IMPLEMENTED;
587 }
588 
589 /* --- Query/Set System Information --- */
590 
591 /*
592  * NOTE: QSI_DEF(n) and SSI_DEF(n) define _cdecl function symbols
593  * so the stack is popped only in one place on x86 platform.
594  */
595 #define QSI_USE(n) QSI##n
596 #define QSI_DEF(n) \
597 static NTSTATUS QSI_USE(n) (PVOID Buffer, ULONG Size, PULONG ReqSize)
598 
599 #define SSI_USE(n) SSI##n
600 #define SSI_DEF(n) \
601 static NTSTATUS SSI_USE(n) (PVOID Buffer, ULONG Size)
602 
603 VOID
604 NTAPI
605 ExQueryPoolUsage(OUT PULONG PagedPoolPages,
606                  OUT PULONG NonPagedPoolPages,
607                  OUT PULONG PagedPoolAllocs,
608                  OUT PULONG PagedPoolFrees,
609                  OUT PULONG PagedPoolLookasideHits,
610                  OUT PULONG NonPagedPoolAllocs,
611                  OUT PULONG NonPagedPoolFrees,
612                  OUT PULONG NonPagedPoolLookasideHits);
613 
614 /* Class 0 - Basic Information */
615 QSI_DEF(SystemBasicInformation)
616 {
617     PSYSTEM_BASIC_INFORMATION Sbi
618         = (PSYSTEM_BASIC_INFORMATION) Buffer;
619 
620     *ReqSize = sizeof(SYSTEM_BASIC_INFORMATION);
621 
622     /* Check user buffer's size */
623     if (Size != sizeof(SYSTEM_BASIC_INFORMATION))
624     {
625         return STATUS_INFO_LENGTH_MISMATCH;
626     }
627 
628     RtlZeroMemory(Sbi, Size);
629     Sbi->Reserved = 0;
630     Sbi->TimerResolution = KeMaximumIncrement;
631     Sbi->PageSize = PAGE_SIZE;
632     Sbi->NumberOfPhysicalPages = MmNumberOfPhysicalPages;
633     Sbi->LowestPhysicalPageNumber = (ULONG)MmLowestPhysicalPage;
634     Sbi->HighestPhysicalPageNumber = (ULONG)MmHighestPhysicalPage;
635     Sbi->AllocationGranularity = MM_VIRTMEM_GRANULARITY; /* hard coded on Intel? */
636     Sbi->MinimumUserModeAddress = 0x10000; /* Top of 64k */
637     Sbi->MaximumUserModeAddress = (ULONG_PTR)MmHighestUserAddress;
638     Sbi->ActiveProcessorsAffinityMask = KeActiveProcessors;
639     Sbi->NumberOfProcessors = KeNumberProcessors;
640 
641     return STATUS_SUCCESS;
642 }
643 
644 /* Class 1 - Processor Information */
645 QSI_DEF(SystemProcessorInformation)
646 {
647     PSYSTEM_PROCESSOR_INFORMATION Spi
648         = (PSYSTEM_PROCESSOR_INFORMATION) Buffer;
649 
650     *ReqSize = sizeof(SYSTEM_PROCESSOR_INFORMATION);
651 
652     /* Check user buffer's size */
653     if (Size < sizeof(SYSTEM_PROCESSOR_INFORMATION))
654     {
655         return STATUS_INFO_LENGTH_MISMATCH;
656     }
657     Spi->ProcessorArchitecture = KeProcessorArchitecture;
658     Spi->ProcessorLevel = KeProcessorLevel;
659     Spi->ProcessorRevision = KeProcessorRevision;
660     Spi->Reserved = 0;
661     Spi->ProcessorFeatureBits = KeFeatureBits;
662 
663     DPRINT("Arch %u Level %u Rev 0x%x\n", Spi->ProcessorArchitecture,
664         Spi->ProcessorLevel, Spi->ProcessorRevision);
665 
666     return STATUS_SUCCESS;
667 }
668 
669 /* Class 2 - Performance Information */
670 QSI_DEF(SystemPerformanceInformation)
671 {
672     LONG i;
673     ULONG IdleUser, IdleKernel;
674     PKPRCB Prcb;
675     PSYSTEM_PERFORMANCE_INFORMATION Spi
676         = (PSYSTEM_PERFORMANCE_INFORMATION) Buffer;
677 
678     PEPROCESS TheIdleProcess;
679 
680     *ReqSize = sizeof(SYSTEM_PERFORMANCE_INFORMATION);
681 
682     /* Check user buffer's size */
683     if (Size < sizeof(SYSTEM_PERFORMANCE_INFORMATION))
684     {
685         return STATUS_INFO_LENGTH_MISMATCH;
686     }
687 
688     TheIdleProcess = PsIdleProcess;
689 
690     IdleKernel = KeQueryRuntimeProcess(&TheIdleProcess->Pcb, &IdleUser);
691     Spi->IdleProcessTime.QuadPart = UInt32x32To64(IdleKernel, KeMaximumIncrement);
692     Spi->IoReadTransferCount = IoReadTransferCount;
693     Spi->IoWriteTransferCount = IoWriteTransferCount;
694     Spi->IoOtherTransferCount = IoOtherTransferCount;
695     Spi->IoReadOperationCount = IoReadOperationCount;
696     Spi->IoWriteOperationCount = IoWriteOperationCount;
697     Spi->IoOtherOperationCount = IoOtherOperationCount;
698     for (i = 0; i < KeNumberProcessors; i ++)
699     {
700         Prcb = KiProcessorBlock[i];
701         if (Prcb)
702         {
703             Spi->IoReadTransferCount.QuadPart += Prcb->IoReadTransferCount.QuadPart;
704             Spi->IoWriteTransferCount.QuadPart += Prcb->IoWriteTransferCount.QuadPart;
705             Spi->IoOtherTransferCount.QuadPart += Prcb->IoOtherTransferCount.QuadPart;
706             Spi->IoReadOperationCount += Prcb->IoReadOperationCount;
707             Spi->IoWriteOperationCount += Prcb->IoWriteOperationCount;
708             Spi->IoOtherOperationCount += Prcb->IoOtherOperationCount;
709         }
710     }
711 
712     Spi->AvailablePages = (ULONG)MmAvailablePages;
713     /*
714      *   Add up all the used "Committed" memory + pagefile.
715      *   Not sure this is right. 8^\
716      */
717     Spi->CommittedPages = MiMemoryConsumers[MC_SYSTEM].PagesUsed +
718                           MiMemoryConsumers[MC_CACHE].PagesUsed +
719                           MiMemoryConsumers[MC_USER].PagesUsed +
720                           MiUsedSwapPages;
721     /*
722      *  Add up the full system total + pagefile.
723      *  All this make Taskmgr happy but not sure it is the right numbers.
724      *  This too, fixes some of GlobalMemoryStatusEx numbers.
725      */
726     Spi->CommitLimit = MmNumberOfPhysicalPages + MiFreeSwapPages + MiUsedSwapPages;
727 
728     Spi->PeakCommitment = 0; /* FIXME */
729     Spi->PageFaultCount = 0; /* FIXME */
730     Spi->CopyOnWriteCount = 0; /* FIXME */
731     Spi->TransitionCount = 0; /* FIXME */
732     Spi->CacheTransitionCount = 0; /* FIXME */
733     Spi->DemandZeroCount = 0; /* FIXME */
734     Spi->PageReadCount = 0; /* FIXME */
735     Spi->PageReadIoCount = 0; /* FIXME */
736     Spi->CacheReadCount = 0; /* FIXME */
737     Spi->CacheIoCount = 0; /* FIXME */
738     Spi->DirtyPagesWriteCount = 0; /* FIXME */
739     Spi->DirtyWriteIoCount = 0; /* FIXME */
740     Spi->MappedPagesWriteCount = 0; /* FIXME */
741     Spi->MappedWriteIoCount = 0; /* FIXME */
742 
743     Spi->PagedPoolPages = 0;
744     Spi->NonPagedPoolPages = 0;
745     Spi->PagedPoolAllocs = 0;
746     Spi->PagedPoolFrees = 0;
747     Spi->PagedPoolLookasideHits = 0;
748     Spi->NonPagedPoolAllocs = 0;
749     Spi->NonPagedPoolFrees = 0;
750     Spi->NonPagedPoolLookasideHits = 0;
751     ExQueryPoolUsage(&Spi->PagedPoolPages,
752                      &Spi->NonPagedPoolPages,
753                      &Spi->PagedPoolAllocs,
754                      &Spi->PagedPoolFrees,
755                      &Spi->PagedPoolLookasideHits,
756                      &Spi->NonPagedPoolAllocs,
757                      &Spi->NonPagedPoolFrees,
758                      &Spi->NonPagedPoolLookasideHits);
759     Spi->FreeSystemPtes = 0; /* FIXME */
760 
761     Spi->ResidentSystemCodePage = 0; /* FIXME */
762 
763     Spi->TotalSystemDriverPages = 0; /* FIXME */
764     Spi->Spare3Count = 0; /* FIXME */
765 
766     Spi->ResidentSystemCachePage = MiMemoryConsumers[MC_CACHE].PagesUsed;
767     Spi->ResidentPagedPoolPage = 0; /* FIXME */
768 
769     Spi->ResidentSystemDriverPage = 0; /* FIXME */
770     Spi->CcFastReadNoWait = 0; /* FIXME */
771     Spi->CcFastReadWait = 0; /* FIXME */
772     Spi->CcFastReadResourceMiss = 0; /* FIXME */
773     Spi->CcFastReadNotPossible = 0; /* FIXME */
774 
775     Spi->CcFastMdlReadNoWait = 0; /* FIXME */
776     Spi->CcFastMdlReadWait = 0; /* FIXME */
777     Spi->CcFastMdlReadResourceMiss = 0; /* FIXME */
778     Spi->CcFastMdlReadNotPossible = 0; /* FIXME */
779 
780     Spi->CcMapDataNoWait = CcMapDataNoWait;
781     Spi->CcMapDataWait = CcMapDataWait;
782     Spi->CcMapDataNoWaitMiss = 0; /* FIXME */
783     Spi->CcMapDataWaitMiss = 0; /* FIXME */
784 
785     Spi->CcPinMappedDataCount = CcPinMappedDataCount;
786     Spi->CcPinReadNoWait = CcPinReadNoWait;
787     Spi->CcPinReadWait = CcPinReadWait;
788     Spi->CcPinReadNoWaitMiss = 0; /* FIXME */
789     Spi->CcPinReadWaitMiss = 0; /* FIXME */
790     Spi->CcCopyReadNoWait = 0; /* FIXME */
791     Spi->CcCopyReadWait = 0; /* FIXME */
792     Spi->CcCopyReadNoWaitMiss = 0; /* FIXME */
793     Spi->CcCopyReadWaitMiss = 0; /* FIXME */
794 
795     Spi->CcMdlReadNoWait = 0; /* FIXME */
796     Spi->CcMdlReadWait = 0; /* FIXME */
797     Spi->CcMdlReadNoWaitMiss = 0; /* FIXME */
798     Spi->CcMdlReadWaitMiss = 0; /* FIXME */
799     Spi->CcReadAheadIos = 0; /* FIXME */
800     Spi->CcLazyWriteIos = CcLazyWriteIos;
801     Spi->CcLazyWritePages = CcLazyWritePages;
802     Spi->CcDataFlushes = CcDataFlushes;
803     Spi->CcDataPages = CcDataPages;
804 
805     Spi->ContextSwitches = 0;
806     Spi->FirstLevelTbFills = 0;
807     Spi->SecondLevelTbFills = 0;
808     Spi->SystemCalls = 0;
809     for (i = 0; i < KeNumberProcessors; i ++)
810     {
811         Prcb = KiProcessorBlock[i];
812         if (Prcb)
813         {
814             Spi->ContextSwitches += KeGetContextSwitches(Prcb);
815             Spi->FirstLevelTbFills += Prcb->KeFirstLevelTbFills;
816             Spi->SecondLevelTbFills += Prcb->KeSecondLevelTbFills;
817             Spi->SystemCalls += Prcb->KeSystemCalls;
818         }
819     }
820 
821     return STATUS_SUCCESS;
822 }
823 
824 /* Class 3 - Time Of Day Information */
825 QSI_DEF(SystemTimeOfDayInformation)
826 {
827     SYSTEM_TIMEOFDAY_INFORMATION Sti;
828     LARGE_INTEGER CurrentTime;
829 
830     /* Set amount of written information to 0 */
831     *ReqSize = 0;
832 
833     /* Check user buffer's size */
834     if (Size > sizeof(SYSTEM_TIMEOFDAY_INFORMATION))
835     {
836         return STATUS_INFO_LENGTH_MISMATCH;
837     }
838 
839     /* Get current time */
840     KeQuerySystemTime(&CurrentTime);
841 
842     /* Zero local buffer */
843     RtlZeroMemory(&Sti, sizeof(SYSTEM_TIMEOFDAY_INFORMATION));
844 
845     /* Fill local time structure */
846     Sti.BootTime= KeBootTime;
847     Sti.CurrentTime = CurrentTime;
848     Sti.TimeZoneBias.QuadPart = ExpTimeZoneBias.QuadPart;
849     Sti.TimeZoneId = ExpTimeZoneId;
850     Sti.Reserved = 0;
851 
852     /* Copy as much as requested by caller */
853     RtlCopyMemory(Buffer, &Sti, Size);
854 
855     /* Set amount of information we copied */
856     *ReqSize = Size;
857 
858     return STATUS_SUCCESS;
859 }
860 
861 /* Class 4 - Path Information */
862 QSI_DEF(SystemPathInformation)
863 {
864     /* FIXME: QSI returns STATUS_BREAKPOINT. Why? */
865     DPRINT1("NtQuerySystemInformation - SystemPathInformation not implemented\n");
866 
867     return STATUS_BREAKPOINT;
868 }
869 
870 /* Class 5 - Process Information */
871 QSI_DEF(SystemProcessInformation)
872 {
873     PSYSTEM_PROCESS_INFORMATION SpiCurrent;
874     PSYSTEM_THREAD_INFORMATION ThreadInfo;
875     PEPROCESS Process = NULL, SystemProcess;
876     PETHREAD CurrentThread;
877     ANSI_STRING ImageName;
878     ULONG CurrentSize;
879     USHORT ImageNameMaximumLength; // image name length in bytes
880     USHORT ImageNameLength;
881     PLIST_ENTRY CurrentEntry;
882     ULONG TotalSize = 0, ThreadsCount;
883     ULONG TotalUser, TotalKernel;
884     PUCHAR Current;
885     NTSTATUS Status = STATUS_SUCCESS;
886     PUNICODE_STRING TempProcessImageName;
887     _SEH2_VOLATILE PUNICODE_STRING ProcessImageName = NULL;
888     PWCHAR szSrc;
889     BOOLEAN Overflow = FALSE;
890 
891     _SEH2_TRY
892     {
893         /* scan the process list */
894 
895         PSYSTEM_PROCESS_INFORMATION Spi
896             = (PSYSTEM_PROCESS_INFORMATION) Buffer;
897 
898         *ReqSize = sizeof(SYSTEM_PROCESS_INFORMATION);
899 
900         /* Check for overflow */
901         if (Size < sizeof(SYSTEM_PROCESS_INFORMATION))
902         {
903             Overflow = TRUE;
904         }
905 
906         /* Zero user's buffer */
907         if (!Overflow) RtlZeroMemory(Spi, Size);
908 
909         SystemProcess = PsIdleProcess;
910         Process = SystemProcess;
911         Current = (PUCHAR) Spi;
912 
913         do
914         {
915             SpiCurrent = (PSYSTEM_PROCESS_INFORMATION) Current;
916 
917             /* Lock the Process */
918             KeEnterCriticalRegion();
919             ExAcquirePushLockShared(&Process->ProcessLock);
920 
921             if ((Process->ProcessExiting) &&
922                 (Process->Pcb.Header.SignalState) &&
923                 !(Process->ActiveThreads) &&
924                 (IsListEmpty(&Process->Pcb.ThreadListHead)))
925             {
926                 DPRINT1("Process %p (%s:%p) is a zombie\n",
927                         Process, Process->ImageFileName, Process->UniqueProcessId);
928                 CurrentSize = 0;
929                 ImageNameMaximumLength = 0;
930 
931                 /* Unlock the Process */
932                 ExReleasePushLockShared(&Process->ProcessLock);
933                 KeLeaveCriticalRegion();
934                 goto Skip;
935             }
936 
937             ThreadsCount = 0;
938             CurrentEntry = Process->Pcb.ThreadListHead.Flink;
939             while (CurrentEntry != &Process->Pcb.ThreadListHead)
940             {
941                 ThreadsCount++;
942                 CurrentEntry = CurrentEntry->Flink;
943             }
944 
945             // size of the structure for every process
946             CurrentSize = sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_THREAD_INFORMATION) * ThreadsCount;
947             ImageNameLength = 0;
948             Status = SeLocateProcessImageName(Process, &TempProcessImageName);
949             ProcessImageName = TempProcessImageName;
950             szSrc = NULL;
951             if (NT_SUCCESS(Status) && (ProcessImageName->Length > 0))
952             {
953               szSrc = (PWCHAR)((PCHAR)ProcessImageName->Buffer + ProcessImageName->Length);
954               /* Loop the file name*/
955               while (szSrc > ProcessImageName->Buffer)
956               {
957                 /* Make sure this isn't a backslash */
958                 if (*--szSrc == OBJ_NAME_PATH_SEPARATOR)
959                 {
960                     szSrc++;
961                     break;
962                 }
963                 else
964                 {
965                     ImageNameLength += sizeof(WCHAR);
966                 }
967               }
968             }
969             if (!ImageNameLength && Process != PsIdleProcess)
970             {
971               ImageNameLength = (USHORT)strlen(Process->ImageFileName) * sizeof(WCHAR);
972             }
973 
974             /* Round up the image name length as NT does */
975             if (ImageNameLength > 0)
976                 ImageNameMaximumLength = ROUND_UP(ImageNameLength + sizeof(WCHAR), 8);
977             else
978                 ImageNameMaximumLength = 0;
979 
980             TotalSize += CurrentSize + ImageNameMaximumLength;
981 
982             /* Check for overflow */
983             if (TotalSize > Size)
984             {
985                 Overflow = TRUE;
986             }
987 
988             /* Fill system information */
989             if (!Overflow)
990             {
991                 SpiCurrent->NextEntryOffset = CurrentSize + ImageNameMaximumLength; // relative offset to the beginning of the next structure
992                 SpiCurrent->NumberOfThreads = ThreadsCount;
993                 SpiCurrent->CreateTime = Process->CreateTime;
994                 SpiCurrent->ImageName.Length = ImageNameLength;
995                 SpiCurrent->ImageName.MaximumLength = ImageNameMaximumLength;
996                 SpiCurrent->ImageName.Buffer = (void*)(Current + CurrentSize);
997 
998                 /* Copy name to the end of the struct */
999                 if(Process != PsIdleProcess)
1000                 {
1001                     if (szSrc)
1002                     {
1003                         RtlCopyMemory(SpiCurrent->ImageName.Buffer, szSrc, SpiCurrent->ImageName.Length);
1004                     }
1005                     else
1006                     {
1007                         RtlInitAnsiString(&ImageName, Process->ImageFileName);
1008                         RtlAnsiStringToUnicodeString(&SpiCurrent->ImageName, &ImageName, FALSE);
1009                     }
1010                 }
1011                 else
1012                 {
1013                     RtlInitUnicodeString(&SpiCurrent->ImageName, NULL);
1014                 }
1015 
1016                 SpiCurrent->BasePriority = Process->Pcb.BasePriority;
1017                 SpiCurrent->UniqueProcessId = Process->UniqueProcessId;
1018                 SpiCurrent->InheritedFromUniqueProcessId = Process->InheritedFromUniqueProcessId;
1019                 SpiCurrent->HandleCount = ObGetProcessHandleCount(Process);
1020                 SpiCurrent->PeakVirtualSize = Process->PeakVirtualSize;
1021                 SpiCurrent->VirtualSize = Process->VirtualSize;
1022                 SpiCurrent->PageFaultCount = Process->Vm.PageFaultCount;
1023                 SpiCurrent->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
1024                 SpiCurrent->WorkingSetSize = Process->Vm.WorkingSetSize;
1025                 SpiCurrent->QuotaPeakPagedPoolUsage = Process->QuotaPeak[0];
1026                 SpiCurrent->QuotaPagedPoolUsage = Process->QuotaUsage[0];
1027                 SpiCurrent->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[1];
1028                 SpiCurrent->QuotaNonPagedPoolUsage = Process->QuotaUsage[1];
1029                 SpiCurrent->PagefileUsage = Process->QuotaUsage[2];
1030                 SpiCurrent->PeakPagefileUsage = Process->QuotaPeak[2];
1031                 SpiCurrent->PrivatePageCount = Process->CommitCharge;
1032                 ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(SpiCurrent + 1);
1033 
1034                 CurrentEntry = Process->Pcb.ThreadListHead.Flink;
1035                 while (CurrentEntry != &Process->Pcb.ThreadListHead)
1036                 {
1037                     CurrentThread = CONTAINING_RECORD(CurrentEntry, ETHREAD, Tcb.ThreadListEntry);
1038 
1039                     ThreadInfo->KernelTime.QuadPart = UInt32x32To64(CurrentThread->Tcb.KernelTime, KeMaximumIncrement);
1040                     ThreadInfo->UserTime.QuadPart = UInt32x32To64(CurrentThread->Tcb.UserTime, KeMaximumIncrement);
1041                     ThreadInfo->CreateTime.QuadPart = CurrentThread->CreateTime.QuadPart;
1042                     ThreadInfo->WaitTime = CurrentThread->Tcb.WaitTime;
1043                     ThreadInfo->StartAddress = (PVOID) CurrentThread->StartAddress;
1044                     ThreadInfo->ClientId = CurrentThread->Cid;
1045                     ThreadInfo->Priority = CurrentThread->Tcb.Priority;
1046                     ThreadInfo->BasePriority = CurrentThread->Tcb.BasePriority;
1047                     ThreadInfo->ContextSwitches = CurrentThread->Tcb.ContextSwitches;
1048                     ThreadInfo->ThreadState = CurrentThread->Tcb.State;
1049                     ThreadInfo->WaitReason = CurrentThread->Tcb.WaitReason;
1050 
1051                     ThreadInfo++;
1052                     CurrentEntry = CurrentEntry->Flink;
1053                 }
1054 
1055                 /* Query total user/kernel times of a process */
1056                 TotalKernel = KeQueryRuntimeProcess(&Process->Pcb, &TotalUser);
1057                 SpiCurrent->UserTime.QuadPart = UInt32x32To64(TotalUser, KeMaximumIncrement);
1058                 SpiCurrent->KernelTime.QuadPart = UInt32x32To64(TotalKernel, KeMaximumIncrement);
1059             }
1060 
1061             if (ProcessImageName)
1062             {
1063                 /* Release the memory allocated by SeLocateProcessImageName */
1064                 ExFreePoolWithTag(ProcessImageName, TAG_SEPA);
1065                 ProcessImageName = NULL;
1066             }
1067 
1068             /* Unlock the Process */
1069             ExReleasePushLockShared(&Process->ProcessLock);
1070             KeLeaveCriticalRegion();
1071 
1072             /* Handle idle process entry */
1073 Skip:
1074             if (Process == PsIdleProcess) Process = NULL;
1075 
1076             Process = PsGetNextProcess(Process);
1077             ThreadsCount = 0;
1078             if ((Process == SystemProcess) || (Process == NULL))
1079             {
1080                 if (!Overflow)
1081                     SpiCurrent->NextEntryOffset = 0;
1082                 break;
1083             }
1084             else
1085                 Current += CurrentSize + ImageNameMaximumLength;
1086           }  while ((Process != SystemProcess) && (Process != NULL));
1087 
1088           if(Process != NULL)
1089             ObDereferenceObject(Process);
1090           Status = STATUS_SUCCESS;
1091     }
1092     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1093     {
1094         if(Process != NULL)
1095             ObDereferenceObject(Process);
1096         if (ProcessImageName)
1097         {
1098             /* Release the memory allocated by SeLocateProcessImageName */
1099             ExFreePoolWithTag(ProcessImageName, TAG_SEPA);
1100         }
1101 
1102         Status = _SEH2_GetExceptionCode();
1103     }
1104     _SEH2_END
1105 
1106     if (Overflow)
1107         Status = STATUS_INFO_LENGTH_MISMATCH;
1108 
1109     *ReqSize = TotalSize;
1110     return Status;
1111 }
1112 
1113 /* Class 6 - Call Count Information */
1114 QSI_DEF(SystemCallCountInformation)
1115 {
1116     /* FIXME */
1117     DPRINT1("NtQuerySystemInformation - SystemCallCountInformation not implemented\n");
1118     return STATUS_NOT_IMPLEMENTED;
1119 }
1120 
1121 /* Class 7 - Device Information */
1122 QSI_DEF(SystemDeviceInformation)
1123 {
1124     PSYSTEM_DEVICE_INFORMATION Sdi
1125         = (PSYSTEM_DEVICE_INFORMATION) Buffer;
1126     PCONFIGURATION_INFORMATION ConfigInfo;
1127 
1128     *ReqSize = sizeof(SYSTEM_DEVICE_INFORMATION);
1129 
1130     /* Check user buffer's size */
1131     if (Size < sizeof(SYSTEM_DEVICE_INFORMATION))
1132     {
1133         return STATUS_INFO_LENGTH_MISMATCH;
1134     }
1135 
1136     ConfigInfo = IoGetConfigurationInformation();
1137 
1138     Sdi->NumberOfDisks = ConfigInfo->DiskCount;
1139     Sdi->NumberOfFloppies = ConfigInfo->FloppyCount;
1140     Sdi->NumberOfCdRoms = ConfigInfo->CdRomCount;
1141     Sdi->NumberOfTapes = ConfigInfo->TapeCount;
1142     Sdi->NumberOfSerialPorts = ConfigInfo->SerialCount;
1143     Sdi->NumberOfParallelPorts = ConfigInfo->ParallelCount;
1144 
1145     return STATUS_SUCCESS;
1146 }
1147 
1148 /* Class 8 - Processor Performance Information */
1149 QSI_DEF(SystemProcessorPerformanceInformation)
1150 {
1151     PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION Spi
1152         = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) Buffer;
1153 
1154     LONG i;
1155     ULONG TotalTime;
1156     PKPRCB Prcb;
1157 
1158     *ReqSize = KeNumberProcessors * sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
1159 
1160     /* Check user buffer's size */
1161     if (Size < *ReqSize)
1162     {
1163         return STATUS_INFO_LENGTH_MISMATCH;
1164     }
1165 
1166     for (i = 0; i < KeNumberProcessors; i++)
1167     {
1168         /* Get the PRCB on this processor */
1169         Prcb = KiProcessorBlock[i];
1170 
1171         /* Calculate total user and kernel times */
1172         TotalTime = Prcb->IdleThread->KernelTime + Prcb->IdleThread->UserTime;
1173         Spi->IdleTime.QuadPart = UInt32x32To64(TotalTime, KeMaximumIncrement);
1174         Spi->KernelTime.QuadPart =  UInt32x32To64(Prcb->KernelTime, KeMaximumIncrement);
1175         Spi->UserTime.QuadPart = UInt32x32To64(Prcb->UserTime, KeMaximumIncrement);
1176         Spi->DpcTime.QuadPart = UInt32x32To64(Prcb->DpcTime, KeMaximumIncrement);
1177         Spi->InterruptTime.QuadPart = UInt32x32To64(Prcb->InterruptTime, KeMaximumIncrement);
1178         Spi->InterruptCount = Prcb->InterruptCount;
1179         Spi++;
1180     }
1181 
1182     return STATUS_SUCCESS;
1183 }
1184 
1185 /* Class 9 - Flags Information */
1186 QSI_DEF(SystemFlagsInformation)
1187 {
1188 #if (NTDDI_VERSION >= NTDDI_VISTA)
1189     *ReqSize = sizeof(SYSTEM_FLAGS_INFORMATION);
1190 #endif
1191 
1192     if (sizeof(SYSTEM_FLAGS_INFORMATION) != Size)
1193     {
1194         return STATUS_INFO_LENGTH_MISMATCH;
1195     }
1196 
1197     ((PSYSTEM_FLAGS_INFORMATION) Buffer)->Flags = NtGlobalFlag;
1198 #if (NTDDI_VERSION < NTDDI_VISTA)
1199     *ReqSize = sizeof(SYSTEM_FLAGS_INFORMATION);
1200 #endif
1201 
1202     return STATUS_SUCCESS;
1203 }
1204 
1205 SSI_DEF(SystemFlagsInformation)
1206 {
1207     if (sizeof(SYSTEM_FLAGS_INFORMATION) != Size)
1208     {
1209         return STATUS_INFO_LENGTH_MISMATCH;
1210     }
1211 
1212     if (!SeSinglePrivilegeCheck(SeDebugPrivilege, ExGetPreviousMode()))
1213     {
1214         return STATUS_ACCESS_DENIED;
1215     }
1216 
1217     NtGlobalFlag = ((PSYSTEM_FLAGS_INFORMATION) Buffer)->Flags;
1218     return STATUS_SUCCESS;
1219 }
1220 
1221 /* Class 10 - Call Time Information */
1222 QSI_DEF(SystemCallTimeInformation)
1223 {
1224     /* FIXME */
1225     DPRINT1("NtQuerySystemInformation - SystemCallTimeInformation not implemented\n");
1226     return STATUS_NOT_IMPLEMENTED;
1227 }
1228 
1229 /* Class 11 - Module Information */
1230 QSI_DEF(SystemModuleInformation)
1231 {
1232     NTSTATUS Status;
1233 
1234     /* Acquire system module list lock */
1235     KeEnterCriticalRegion();
1236     ExAcquireResourceExclusiveLite(&PsLoadedModuleResource, TRUE);
1237 
1238     /* Call the generic handler with the system module list */
1239     Status = ExpQueryModuleInformation(&PsLoadedModuleList,
1240                                        &MmLoadedUserImageList,
1241                                        (PRTL_PROCESS_MODULES)Buffer,
1242                                        Size,
1243                                        ReqSize);
1244 
1245     /* Release list lock and return status */
1246     ExReleaseResourceLite(&PsLoadedModuleResource);
1247     KeLeaveCriticalRegion();
1248     return Status;
1249 }
1250 
1251 /* Class 12 - Locks Information */
1252 QSI_DEF(SystemLocksInformation)
1253 {
1254     /* FIXME */
1255     DPRINT1("NtQuerySystemInformation - SystemLocksInformation not implemented\n");
1256     return STATUS_NOT_IMPLEMENTED;
1257 }
1258 
1259 /* Class 13 - Stack Trace Information */
1260 QSI_DEF(SystemStackTraceInformation)
1261 {
1262     /* FIXME */
1263     DPRINT1("NtQuerySystemInformation - SystemStackTraceInformation not implemented\n");
1264     return STATUS_NOT_IMPLEMENTED;
1265 }
1266 
1267 /* Class 14 - Paged Pool Information */
1268 QSI_DEF(SystemPagedPoolInformation)
1269 {
1270     /* FIXME */
1271     DPRINT1("NtQuerySystemInformation - SystemPagedPoolInformation not implemented\n");
1272     return STATUS_NOT_IMPLEMENTED;
1273 }
1274 
1275 /* Class 15 - Non Paged Pool Information */
1276 QSI_DEF(SystemNonPagedPoolInformation)
1277 {
1278     /* FIXME */
1279     DPRINT1("NtQuerySystemInformation - SystemNonPagedPoolInformation not implemented\n");
1280     return STATUS_NOT_IMPLEMENTED;
1281 }
1282 
1283 
1284 /* Class 16 - Handle Information */
1285 QSI_DEF(SystemHandleInformation)
1286 {
1287     PSYSTEM_HANDLE_INFORMATION HandleInformation;
1288     PLIST_ENTRY NextTableEntry;
1289     PHANDLE_TABLE HandleTable;
1290     PHANDLE_TABLE_ENTRY HandleTableEntry;
1291     EXHANDLE Handle;
1292     ULONG Index = 0;
1293     NTSTATUS Status;
1294     PMDL Mdl;
1295     PAGED_CODE();
1296 
1297     DPRINT("NtQuerySystemInformation - SystemHandleInformation\n");
1298 
1299     /* Set initial required buffer size */
1300     *ReqSize = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION, Handles);
1301 
1302     /* Check user's buffer size */
1303     if (Size < *ReqSize)
1304     {
1305         return STATUS_INFO_LENGTH_MISMATCH;
1306     }
1307 
1308     /* We need to lock down the memory */
1309     Status = ExLockUserBuffer(Buffer,
1310                               Size,
1311                               ExGetPreviousMode(),
1312                               IoWriteAccess,
1313                               (PVOID*)&HandleInformation,
1314                               &Mdl);
1315     if (!NT_SUCCESS(Status))
1316     {
1317         DPRINT1("Failed to lock the user buffer: 0x%lx\n", Status);
1318         return Status;
1319     }
1320 
1321     /* Reset of count of handles */
1322     HandleInformation->NumberOfHandles = 0;
1323 
1324     /* Enter a critical region */
1325     KeEnterCriticalRegion();
1326 
1327     /* Acquire the handle table lock */
1328     ExAcquirePushLockShared(&HandleTableListLock);
1329 
1330     /* Enumerate all system handles */
1331     for (NextTableEntry = HandleTableListHead.Flink;
1332          NextTableEntry != &HandleTableListHead;
1333          NextTableEntry = NextTableEntry->Flink)
1334     {
1335         /* Get current handle table */
1336         HandleTable = CONTAINING_RECORD(NextTableEntry, HANDLE_TABLE, HandleTableList);
1337 
1338         /* Set the initial value and loop the entries */
1339         Handle.Value = 0;
1340         while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle)))
1341         {
1342             /* Validate the entry */
1343             if ((HandleTableEntry->Object) &&
1344                 (HandleTableEntry->NextFreeTableEntry != -2))
1345             {
1346                 /* Increase of count of handles */
1347                 ++HandleInformation->NumberOfHandles;
1348 
1349                 /* Lock the entry */
1350                 if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
1351                 {
1352                     /* Increase required buffer size */
1353                     *ReqSize += sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO);
1354 
1355                     /* Check user's buffer size */
1356                     if (*ReqSize > Size)
1357                     {
1358                         Status = STATUS_INFO_LENGTH_MISMATCH;
1359                     }
1360                     else
1361                     {
1362                         POBJECT_HEADER ObjectHeader = ObpGetHandleObject(HandleTableEntry);
1363 
1364                         /* Filling handle information */
1365                         HandleInformation->Handles[Index].UniqueProcessId =
1366                             (USHORT)(ULONG_PTR) HandleTable->UniqueProcessId;
1367 
1368                         HandleInformation->Handles[Index].CreatorBackTraceIndex = 0;
1369 
1370 #if 0 /* FIXME!!! Type field currupted */
1371                         HandleInformation->Handles[Index].ObjectTypeIndex =
1372                             (UCHAR) ObjectHeader->Type->Index;
1373 #else
1374                         HandleInformation->Handles[Index].ObjectTypeIndex = 0;
1375 #endif
1376 
1377                         HandleInformation->Handles[Index].HandleAttributes =
1378                             HandleTableEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
1379 
1380                         HandleInformation->Handles[Index].HandleValue =
1381                             (USHORT)(ULONG_PTR) Handle.GenericHandleOverlay;
1382 
1383                         HandleInformation->Handles[Index].Object = &ObjectHeader->Body;
1384 
1385                         HandleInformation->Handles[Index].GrantedAccess =
1386                             HandleTableEntry->GrantedAccess;
1387 
1388                         ++Index;
1389                     }
1390 
1391                     /* Unlock it */
1392                     ExUnlockHandleTableEntry(HandleTable, HandleTableEntry);
1393                 }
1394             }
1395 
1396             /* Go to the next entry */
1397             Handle.Value += sizeof(HANDLE);
1398         }
1399     }
1400 
1401     /* Release the lock */
1402     ExReleasePushLockShared(&HandleTableListLock);
1403 
1404     /* Leave the critical region */
1405     KeLeaveCriticalRegion();
1406 
1407     /* Release the locked user buffer */
1408     ExUnlockUserBuffer(Mdl);
1409 
1410     return Status;
1411 }
1412 
1413 /* Class 17 -  Information */
1414 QSI_DEF(SystemObjectInformation)
1415 {
1416     /* FIXME */
1417     DPRINT1("NtQuerySystemInformation - SystemObjectInformation not implemented\n");
1418     return STATUS_NOT_IMPLEMENTED;
1419 }
1420 
1421 /* Class 18 -  Information */
1422 QSI_DEF(SystemPageFileInformation)
1423 {
1424     UNICODE_STRING FileName; /* FIXME */
1425     SYSTEM_PAGEFILE_INFORMATION *Spfi = (SYSTEM_PAGEFILE_INFORMATION *) Buffer;
1426 
1427     if (Size < sizeof(SYSTEM_PAGEFILE_INFORMATION))
1428     {
1429         * ReqSize = sizeof(SYSTEM_PAGEFILE_INFORMATION);
1430         return STATUS_INFO_LENGTH_MISMATCH;
1431     }
1432 
1433     RtlInitUnicodeString(&FileName, NULL); /* FIXME */
1434 
1435     /* FIXME */
1436     Spfi->NextEntryOffset = 0;
1437 
1438     Spfi->TotalSize = MiFreeSwapPages + MiUsedSwapPages;
1439     Spfi->TotalInUse = MiUsedSwapPages;
1440     Spfi->PeakUsage = MiUsedSwapPages; /* FIXME */
1441     Spfi->PageFileName = FileName;
1442     return STATUS_SUCCESS;
1443 }
1444 
1445 /* Class 19 - Vdm Instemul Information */
1446 QSI_DEF(SystemVdmInstemulInformation)
1447 {
1448     /* FIXME */
1449     DPRINT1("NtQuerySystemInformation - SystemVdmInstemulInformation not implemented\n");
1450     return STATUS_NOT_IMPLEMENTED;
1451 }
1452 
1453 /* Class 20 - Vdm Bop Information */
1454 QSI_DEF(SystemVdmBopInformation)
1455 {
1456     /* FIXME */
1457     DPRINT1("NtQuerySystemInformation - SystemVdmBopInformation not implemented\n");
1458     return STATUS_NOT_IMPLEMENTED;
1459 }
1460 
1461 /* Class 21 - File Cache Information */
1462 QSI_DEF(SystemFileCacheInformation)
1463 {
1464     SYSTEM_FILECACHE_INFORMATION *Sci = (SYSTEM_FILECACHE_INFORMATION *) Buffer;
1465 
1466     *ReqSize = sizeof(SYSTEM_FILECACHE_INFORMATION);
1467 
1468     if (Size < *ReqSize)
1469     {
1470         return STATUS_INFO_LENGTH_MISMATCH;
1471     }
1472 
1473     RtlZeroMemory(Sci, sizeof(SYSTEM_FILECACHE_INFORMATION));
1474 
1475     /* Return the Byte size not the page size. */
1476     Sci->CurrentSize =
1477         MiMemoryConsumers[MC_CACHE].PagesUsed * PAGE_SIZE;
1478     Sci->PeakSize =
1479             MiMemoryConsumers[MC_CACHE].PagesUsed * PAGE_SIZE; /* FIXME */
1480     /* Taskmgr multiplies this one by page size right away */
1481     Sci->CurrentSizeIncludingTransitionInPages =
1482         MiMemoryConsumers[MC_CACHE].PagesUsed; /* FIXME: Should be */
1483     /* system working set and standby pages. */
1484     Sci->PageFaultCount = 0; /* FIXME */
1485     Sci->MinimumWorkingSet = 0; /* FIXME */
1486     Sci->MaximumWorkingSet = 0; /* FIXME */
1487 
1488     return STATUS_SUCCESS;
1489 }
1490 
1491 SSI_DEF(SystemFileCacheInformation)
1492 {
1493     if (Size < sizeof(SYSTEM_FILECACHE_INFORMATION))
1494     {
1495         return STATUS_INFO_LENGTH_MISMATCH;
1496     }
1497     /* FIXME */
1498     DPRINT1("NtSetSystemInformation - SystemFileCacheInformation not implemented\n");
1499     return STATUS_NOT_IMPLEMENTED;
1500 }
1501 
1502 /* Class 22 - Pool Tag Information */
1503 QSI_DEF(SystemPoolTagInformation)
1504 {
1505     if (Size < sizeof(SYSTEM_POOLTAG_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
1506     return ExGetPoolTagInfo(Buffer, Size, ReqSize);
1507 }
1508 
1509 /* Class 23 - Interrupt Information for all processors */
1510 QSI_DEF(SystemInterruptInformation)
1511 {
1512     PKPRCB Prcb;
1513     LONG i;
1514     ULONG ti;
1515     PSYSTEM_INTERRUPT_INFORMATION sii = (PSYSTEM_INTERRUPT_INFORMATION)Buffer;
1516 
1517     if(Size < KeNumberProcessors * sizeof(SYSTEM_INTERRUPT_INFORMATION))
1518     {
1519         return STATUS_INFO_LENGTH_MISMATCH;
1520     }
1521 
1522     ti = KeQueryTimeIncrement();
1523 
1524     for (i = 0; i < KeNumberProcessors; i++)
1525     {
1526         Prcb = KiProcessorBlock[i];
1527         sii->ContextSwitches = KeGetContextSwitches(Prcb);
1528         sii->DpcCount = Prcb->DpcData[0].DpcCount;
1529         sii->DpcRate = Prcb->DpcRequestRate;
1530         sii->TimeIncrement = ti;
1531         sii->DpcBypassCount = 0;
1532         sii->ApcBypassCount = 0;
1533         sii++;
1534     }
1535 
1536     return STATUS_SUCCESS;
1537 }
1538 
1539 /* Class 24 - DPC Behaviour Information */
1540 QSI_DEF(SystemDpcBehaviourInformation)
1541 {
1542     PSYSTEM_DPC_BEHAVIOR_INFORMATION sdbi = (PSYSTEM_DPC_BEHAVIOR_INFORMATION)Buffer;
1543 
1544     if (Size < sizeof(SYSTEM_DPC_BEHAVIOR_INFORMATION))
1545     {
1546         return STATUS_INFO_LENGTH_MISMATCH;
1547     }
1548 
1549     sdbi->DpcQueueDepth = KiMaximumDpcQueueDepth;
1550     sdbi->MinimumDpcRate = KiMinimumDpcRate;
1551     sdbi->AdjustDpcThreshold = KiAdjustDpcThreshold;
1552     sdbi->IdealDpcRate = KiIdealDpcRate;
1553 
1554     return STATUS_SUCCESS;
1555 }
1556 
1557 SSI_DEF(SystemDpcBehaviourInformation)
1558 {
1559     /* FIXME */
1560     DPRINT1("NtSetSystemInformation - SystemDpcBehaviourInformation not implemented\n");
1561     return STATUS_NOT_IMPLEMENTED;
1562 }
1563 
1564 /* Class 25 - Full Memory Information */
1565 QSI_DEF(SystemFullMemoryInformation)
1566 {
1567     PULONG Spi = (PULONG) Buffer;
1568 
1569     PEPROCESS TheIdleProcess;
1570 
1571     *ReqSize = sizeof(ULONG);
1572 
1573     if (sizeof(ULONG) != Size)
1574     {
1575         return STATUS_INFO_LENGTH_MISMATCH;
1576     }
1577 
1578     DPRINT("SystemFullMemoryInformation\n");
1579 
1580     TheIdleProcess = PsIdleProcess;
1581 
1582     DPRINT("PID: %p, KernelTime: %u PFFree: %lu PFUsed: %lu\n",
1583            TheIdleProcess->UniqueProcessId,
1584            TheIdleProcess->Pcb.KernelTime,
1585            MiFreeSwapPages,
1586            MiUsedSwapPages);
1587 
1588     *Spi = MiMemoryConsumers[MC_USER].PagesUsed;
1589 
1590     return STATUS_SUCCESS;
1591 }
1592 
1593 /* Class 26 - Load Image */
1594 SSI_DEF(SystemLoadGdiDriverInformation)
1595 {
1596     PSYSTEM_GDI_DRIVER_INFORMATION DriverInfo = (PVOID)Buffer;
1597     UNICODE_STRING ImageName;
1598     PVOID ImageBase;
1599     PVOID SectionPointer;
1600     ULONG_PTR EntryPoint;
1601     NTSTATUS Status;
1602     ULONG DirSize;
1603     PIMAGE_NT_HEADERS NtHeader;
1604 
1605     /* Validate size */
1606     if (Size != sizeof(SYSTEM_GDI_DRIVER_INFORMATION))
1607     {
1608         /* Incorrect buffer length, fail */
1609         return STATUS_INFO_LENGTH_MISMATCH;
1610     }
1611 
1612     /* Only kernel mode can call this function */
1613     if (ExGetPreviousMode() != KernelMode) return STATUS_PRIVILEGE_NOT_HELD;
1614 
1615     /* Load the driver */
1616     ImageName = DriverInfo->DriverName;
1617     Status = MmLoadSystemImage(&ImageName,
1618                                NULL,
1619                                NULL,
1620                                0,
1621                                &SectionPointer,
1622                                &ImageBase);
1623     if (!NT_SUCCESS(Status)) return Status;
1624 
1625     /* Return the export pointer */
1626     DriverInfo->ExportSectionPointer =
1627         RtlImageDirectoryEntryToData(ImageBase,
1628                                      TRUE,
1629                                      IMAGE_DIRECTORY_ENTRY_EXPORT,
1630                                      &DirSize);
1631 
1632     /* Get the entrypoint */
1633     NtHeader = RtlImageNtHeader(ImageBase);
1634     EntryPoint = NtHeader->OptionalHeader.AddressOfEntryPoint;
1635     EntryPoint += (ULONG_PTR)ImageBase;
1636 
1637     /* Save other data */
1638     DriverInfo->ImageAddress = ImageBase;
1639     DriverInfo->SectionPointer = SectionPointer;
1640     DriverInfo->EntryPoint = (PVOID)EntryPoint;
1641     DriverInfo->ImageLength = NtHeader->OptionalHeader.SizeOfImage;
1642 
1643     /* All is good */
1644     return STATUS_SUCCESS;
1645 }
1646 
1647 /* Class 27 - Unload Image */
1648 SSI_DEF(SystemUnloadGdiDriverInformation)
1649 {
1650     PVOID *SectionPointer = Buffer;
1651 
1652     /* Validate size */
1653     if (Size != sizeof(PVOID))
1654     {
1655         /* Incorrect length, fail */
1656         return STATUS_INFO_LENGTH_MISMATCH;
1657     }
1658 
1659     /* Only kernel mode can call this function */
1660     if (ExGetPreviousMode() != KernelMode) return STATUS_PRIVILEGE_NOT_HELD;
1661 
1662     /* Unload the image */
1663     MmUnloadSystemImage(*SectionPointer);
1664     return STATUS_SUCCESS;
1665 }
1666 
1667 /* Class 28 - Time Adjustment Information */
1668 QSI_DEF(SystemTimeAdjustmentInformation)
1669 {
1670     PSYSTEM_QUERY_TIME_ADJUST_INFORMATION TimeInfo =
1671         (PSYSTEM_QUERY_TIME_ADJUST_INFORMATION)Buffer;
1672 
1673     /* Check if enough storage was provided */
1674     if (sizeof(SYSTEM_QUERY_TIME_ADJUST_INFORMATION) > Size)
1675     {
1676         * ReqSize = sizeof(SYSTEM_QUERY_TIME_ADJUST_INFORMATION);
1677         return STATUS_INFO_LENGTH_MISMATCH;
1678     }
1679 
1680     /* Give time values to our caller */
1681     TimeInfo->TimeIncrement = KeMaximumIncrement;
1682     TimeInfo->TimeAdjustment = KeTimeAdjustment;
1683     TimeInfo->Enable = !KiTimeAdjustmentEnabled;
1684 
1685     return STATUS_SUCCESS;
1686 }
1687 
1688 SSI_DEF(SystemTimeAdjustmentInformation)
1689 {
1690     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1691     PSYSTEM_SET_TIME_ADJUST_INFORMATION TimeInfo =
1692         (PSYSTEM_SET_TIME_ADJUST_INFORMATION)Buffer;
1693 
1694     /* Check size of a buffer, it must match our expectations */
1695     if (sizeof(SYSTEM_SET_TIME_ADJUST_INFORMATION) != Size)
1696         return STATUS_INFO_LENGTH_MISMATCH;
1697 
1698     /* Check who is calling */
1699     if (PreviousMode != KernelMode)
1700     {
1701         /* Check access rights */
1702         if (!SeSinglePrivilegeCheck(SeSystemtimePrivilege, PreviousMode))
1703         {
1704             return STATUS_PRIVILEGE_NOT_HELD;
1705         }
1706     }
1707 
1708     /* FIXME: behaviour suggests the member be named 'Disable' */
1709     if (TimeInfo->Enable)
1710     {
1711         /* Disable time adjustment and set default value */
1712         KiTimeAdjustmentEnabled = FALSE;
1713         KeTimeAdjustment = KeMaximumIncrement;
1714     }
1715     else
1716     {
1717         /* Check if a valid time adjustment value is given */
1718         if (TimeInfo->TimeAdjustment == 0) return STATUS_INVALID_PARAMETER_2;
1719 
1720         /* Enable time adjustment and set the adjustment value */
1721         KiTimeAdjustmentEnabled = TRUE;
1722         KeTimeAdjustment = TimeInfo->TimeAdjustment;
1723     }
1724 
1725     return STATUS_SUCCESS;
1726 }
1727 
1728 /* Class 29 - Summary Memory Information */
1729 QSI_DEF(SystemSummaryMemoryInformation)
1730 {
1731     /* FIXME */
1732     DPRINT1("NtQuerySystemInformation - SystemSummaryMemoryInformation not implemented\n");
1733     return STATUS_NOT_IMPLEMENTED;
1734 }
1735 
1736 /* Class 30 - Next Event Id Information */
1737 QSI_DEF(SystemNextEventIdInformation)
1738 {
1739     /* FIXME */
1740     DPRINT1("NtQuerySystemInformation - SystemNextEventIdInformation not implemented\n");
1741     return STATUS_NOT_IMPLEMENTED;
1742 }
1743 
1744 /* Class 31 */
1745 QSI_DEF(SystemPerformanceTraceInformation)
1746 {
1747     /* FIXME */
1748     DPRINT1("NtQuerySystemInformation - SystemPerformanceTraceInformation not implemented\n");
1749     return STATUS_NOT_IMPLEMENTED;
1750 }
1751 
1752 /* Class 32 - Crash Dump Information */
1753 QSI_DEF(SystemCrashDumpInformation)
1754 {
1755     /* FIXME */
1756     DPRINT1("NtQuerySystemInformation - SystemCrashDumpInformation not implemented\n");
1757     return STATUS_NOT_IMPLEMENTED;
1758 }
1759 
1760 /* Class 33 - Exception Information */
1761 QSI_DEF(SystemExceptionInformation)
1762 {
1763     PSYSTEM_EXCEPTION_INFORMATION ExceptionInformation =
1764         (PSYSTEM_EXCEPTION_INFORMATION)Buffer;
1765     PKPRCB Prcb;
1766     ULONG AlignmentFixupCount = 0, ExceptionDispatchCount = 0;
1767     ULONG FloatingEmulationCount = 0, ByteWordEmulationCount = 0;
1768     CHAR i;
1769 
1770     /* Check size of a buffer, it must match our expectations */
1771     if (sizeof(SYSTEM_EXCEPTION_INFORMATION) != Size)
1772         return STATUS_INFO_LENGTH_MISMATCH;
1773 
1774     /* Sum up exception count information from all processors */
1775     for (i = 0; i < KeNumberProcessors; i++)
1776     {
1777         Prcb = KiProcessorBlock[i];
1778         if (Prcb)
1779         {
1780             AlignmentFixupCount += Prcb->KeAlignmentFixupCount;
1781             ExceptionDispatchCount += Prcb->KeExceptionDispatchCount;
1782 #ifndef _M_ARM
1783             FloatingEmulationCount += Prcb->KeFloatingEmulationCount;
1784 #endif // _M_ARM
1785         }
1786     }
1787 
1788     /* Save information in user's buffer */
1789     ExceptionInformation->AlignmentFixupCount = AlignmentFixupCount;
1790     ExceptionInformation->ExceptionDispatchCount = ExceptionDispatchCount;
1791     ExceptionInformation->FloatingEmulationCount = FloatingEmulationCount;
1792     ExceptionInformation->ByteWordEmulationCount = ByteWordEmulationCount;
1793 
1794     return STATUS_SUCCESS;
1795 }
1796 
1797 /* Class 34 - Crash Dump State Information */
1798 QSI_DEF(SystemCrashDumpStateInformation)
1799 {
1800     /* FIXME */
1801     DPRINT1("NtQuerySystemInformation - SystemCrashDumpStateInformation not implemented\n");
1802     return STATUS_NOT_IMPLEMENTED;
1803 }
1804 
1805 /* Class 35 - Kernel Debugger Information */
1806 QSI_DEF(SystemKernelDebuggerInformation)
1807 {
1808     PSYSTEM_KERNEL_DEBUGGER_INFORMATION skdi = (PSYSTEM_KERNEL_DEBUGGER_INFORMATION) Buffer;
1809 
1810 #if (NTDDI_VERSION >= NTDDI_VISTA)
1811     *ReqSize = sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION);
1812 #endif
1813 
1814     if (Size < sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION))
1815     {
1816         return STATUS_INFO_LENGTH_MISMATCH;
1817     }
1818 
1819     skdi->KernelDebuggerEnabled = KD_DEBUGGER_ENABLED;
1820     skdi->KernelDebuggerNotPresent = KD_DEBUGGER_NOT_PRESENT;
1821 
1822 #if (NTDDI_VERSION < NTDDI_VISTA)
1823     *ReqSize = sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION);
1824 #endif
1825 
1826     return STATUS_SUCCESS;
1827 }
1828 
1829 /* Class 36 - Context Switch Information */
1830 QSI_DEF(SystemContextSwitchInformation)
1831 {
1832     PSYSTEM_CONTEXT_SWITCH_INFORMATION ContextSwitchInformation =
1833         (PSYSTEM_CONTEXT_SWITCH_INFORMATION)Buffer;
1834     ULONG ContextSwitches;
1835     PKPRCB Prcb;
1836     CHAR i;
1837 
1838     /* Check size of a buffer, it must match our expectations */
1839     if (sizeof(SYSTEM_CONTEXT_SWITCH_INFORMATION) != Size)
1840         return STATUS_INFO_LENGTH_MISMATCH;
1841 
1842     /* Calculate total value of context switches across all processors */
1843     ContextSwitches = 0;
1844     for (i = 0; i < KeNumberProcessors; i ++)
1845     {
1846         Prcb = KiProcessorBlock[i];
1847         if (Prcb)
1848         {
1849             ContextSwitches += KeGetContextSwitches(Prcb);
1850         }
1851     }
1852 
1853     ContextSwitchInformation->ContextSwitches = ContextSwitches;
1854 
1855     /* FIXME */
1856     ContextSwitchInformation->FindAny = 0;
1857     ContextSwitchInformation->FindLast = 0;
1858     ContextSwitchInformation->FindIdeal = 0;
1859     ContextSwitchInformation->IdleAny = 0;
1860     ContextSwitchInformation->IdleCurrent = 0;
1861     ContextSwitchInformation->IdleLast = 0;
1862     ContextSwitchInformation->IdleIdeal = 0;
1863     ContextSwitchInformation->PreemptAny = 0;
1864     ContextSwitchInformation->PreemptCurrent = 0;
1865     ContextSwitchInformation->PreemptLast = 0;
1866     ContextSwitchInformation->SwitchToIdle = 0;
1867 
1868     return STATUS_SUCCESS;
1869 }
1870 
1871 /* Class 37 - Registry Quota Information */
1872 QSI_DEF(SystemRegistryQuotaInformation)
1873 {
1874     PSYSTEM_REGISTRY_QUOTA_INFORMATION srqi = (PSYSTEM_REGISTRY_QUOTA_INFORMATION) Buffer;
1875 
1876     *ReqSize = sizeof(SYSTEM_REGISTRY_QUOTA_INFORMATION);
1877     if (Size < sizeof(SYSTEM_REGISTRY_QUOTA_INFORMATION))
1878     {
1879         return STATUS_INFO_LENGTH_MISMATCH;
1880     }
1881 
1882     DPRINT1("Faking max registry size of 32 MB\n");
1883     srqi->RegistryQuotaAllowed = 0x2000000;
1884     srqi->RegistryQuotaUsed = 0x200000;
1885     srqi->PagedPoolSize = 0x200000;
1886 
1887     return STATUS_SUCCESS;
1888 }
1889 
1890 SSI_DEF(SystemRegistryQuotaInformation)
1891 {
1892     /* FIXME */
1893     DPRINT1("NtSetSystemInformation - SystemRegistryQuotaInformation not implemented\n");
1894     return STATUS_NOT_IMPLEMENTED;
1895 }
1896 
1897 /* Class 38 - Load And Call Image */
1898 SSI_DEF(SystemExtendServiceTableInformation)
1899 {
1900     UNICODE_STRING ImageName;
1901     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1902     PLDR_DATA_TABLE_ENTRY ModuleObject;
1903     NTSTATUS Status;
1904     PIMAGE_NT_HEADERS NtHeader;
1905     DRIVER_OBJECT Win32k;
1906     PDRIVER_INITIALIZE DriverInit;
1907     PVOID ImageBase;
1908     ULONG_PTR EntryPoint;
1909 
1910     /* Validate the size */
1911     if (Size != sizeof(UNICODE_STRING)) return STATUS_INFO_LENGTH_MISMATCH;
1912 
1913     /* Check who is calling */
1914     if (PreviousMode != KernelMode)
1915     {
1916         static const UNICODE_STRING Win32kName =
1917             RTL_CONSTANT_STRING(L"\\SystemRoot\\System32\\win32k.sys");
1918 
1919         /* Make sure we can load drivers */
1920         if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, UserMode))
1921         {
1922             /* FIXME: We can't, fail */
1923             return STATUS_PRIVILEGE_NOT_HELD;
1924         }
1925 
1926         _SEH2_TRY
1927         {
1928             /* Probe and copy the unicode string */
1929             ProbeForRead(Buffer, sizeof(ImageName), 1);
1930             ImageName = *(PUNICODE_STRING)Buffer;
1931 
1932             /* Probe the string buffer */
1933             ProbeForRead(ImageName.Buffer, ImageName.Length, sizeof(WCHAR));
1934 
1935             /* Check if we have the correct name (nothing else is allowed!) */
1936             if (!RtlEqualUnicodeString(&ImageName, &Win32kName, FALSE))
1937             {
1938                 _SEH2_YIELD(return STATUS_PRIVILEGE_NOT_HELD);
1939             }
1940         }
1941         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1942         {
1943             _SEH2_YIELD(return _SEH2_GetExceptionCode());
1944         }
1945         _SEH2_END;
1946 
1947         /* Recursively call the function, so that we are from kernel mode */
1948         return ZwSetSystemInformation(SystemExtendServiceTableInformation,
1949                                       (PVOID)&Win32kName,
1950                                       sizeof(Win32kName));
1951     }
1952 
1953     /* Load the image */
1954     Status = MmLoadSystemImage((PUNICODE_STRING)Buffer,
1955                                NULL,
1956                                NULL,
1957                                0,
1958                                (PVOID)&ModuleObject,
1959                                &ImageBase);
1960 
1961     if (!NT_SUCCESS(Status)) return Status;
1962 
1963     /* Get the headers */
1964     NtHeader = RtlImageNtHeader(ImageBase);
1965     if (!NtHeader)
1966     {
1967         /* Fail */
1968         MmUnloadSystemImage(ModuleObject);
1969         return STATUS_INVALID_IMAGE_FORMAT;
1970     }
1971 
1972     /* Get the entrypoint */
1973     EntryPoint = NtHeader->OptionalHeader.AddressOfEntryPoint;
1974     EntryPoint += (ULONG_PTR)ImageBase;
1975     DriverInit = (PDRIVER_INITIALIZE)EntryPoint;
1976 
1977     /* Create a dummy device */
1978     RtlZeroMemory(&Win32k, sizeof(Win32k));
1979     ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
1980     Win32k.DriverStart = ImageBase;
1981 
1982     /* Call it */
1983     Status = (DriverInit)(&Win32k, NULL);
1984     ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
1985 
1986     /* Unload if we failed */
1987     if (!NT_SUCCESS(Status)) MmUnloadSystemImage(ModuleObject);
1988     return Status;
1989 }
1990 
1991 /* Class 39 - Priority Separation */
1992 SSI_DEF(SystemPrioritySeperation)
1993 {
1994     /* Check if the size is correct */
1995     if (Size != sizeof(ULONG))
1996     {
1997         return STATUS_INFO_LENGTH_MISMATCH;
1998     }
1999 
2000     /* We need the TCB privilege */
2001     if (!SeSinglePrivilegeCheck(SeTcbPrivilege, ExGetPreviousMode()))
2002     {
2003         return STATUS_PRIVILEGE_NOT_HELD;
2004     }
2005 
2006     /* Modify the quantum table */
2007     PsChangeQuantumTable(TRUE, *(PULONG)Buffer);
2008 
2009     return STATUS_SUCCESS;
2010 }
2011 
2012 /* Class 40 */
2013 QSI_DEF(SystemVerifierAddDriverInformation)
2014 {
2015     /* FIXME */
2016     DPRINT1("NtQuerySystemInformation - SystemVerifierAddDriverInformation not implemented\n");
2017     return STATUS_NOT_IMPLEMENTED;
2018 }
2019 
2020 /* Class 41 */
2021 QSI_DEF(SystemVerifierRemoveDriverInformation)
2022 {
2023     /* FIXME */
2024     DPRINT1("NtQuerySystemInformation - SystemVerifierRemoveDriverInformation not implemented\n");
2025     return STATUS_NOT_IMPLEMENTED;
2026 }
2027 
2028 /* Class 42 - Power Information */
2029 QSI_DEF(SystemProcessorIdleInformation)
2030 {
2031     *ReqSize = sizeof(PROCESSOR_POWER_INFORMATION) * KeNumberProcessors;
2032 
2033     if (sizeof(PROCESSOR_POWER_INFORMATION) * KeNumberProcessors > Size)
2034     {
2035         return STATUS_INFO_LENGTH_MISMATCH;
2036     }
2037 
2038     /* FIXME */
2039     DPRINT1("NtQuerySystemInformation - SystemPowerInformation not implemented\n");
2040     return STATUS_NOT_IMPLEMENTED;
2041 }
2042 
2043 /* Class 43 */
2044 QSI_DEF(SystemLegacyDriverInformation)
2045 {
2046     /* FIXME */
2047     DPRINT1("NtQuerySystemInformation - SystemLegacyDriverInformation not implemented\n");
2048     return STATUS_NOT_IMPLEMENTED;
2049 }
2050 
2051 /* Class 44 - Current Time Zone Information */
2052 QSI_DEF(SystemCurrentTimeZoneInformation)
2053 {
2054     *ReqSize = sizeof(RTL_TIME_ZONE_INFORMATION);
2055 
2056     if (sizeof(RTL_TIME_ZONE_INFORMATION) != Size)
2057     {
2058         return STATUS_INFO_LENGTH_MISMATCH;
2059     }
2060 
2061     /* Copy the time zone information struct */
2062     memcpy(Buffer,
2063            &ExpTimeZoneInfo,
2064            sizeof(RTL_TIME_ZONE_INFORMATION));
2065 
2066     return STATUS_SUCCESS;
2067 }
2068 
2069 
2070 SSI_DEF(SystemCurrentTimeZoneInformation)
2071 {
2072     /* Check user buffer's size */
2073     if (Size < sizeof(RTL_TIME_ZONE_INFORMATION))
2074     {
2075         return STATUS_INFO_LENGTH_MISMATCH;
2076     }
2077 
2078     return ExpSetTimeZoneInformation((PRTL_TIME_ZONE_INFORMATION)Buffer);
2079 }
2080 
2081 static
2082 VOID
2083 ExpCopyLookasideInformation(
2084     PSYSTEM_LOOKASIDE_INFORMATION *InfoPointer,
2085     PULONG RemainingPointer,
2086     PLIST_ENTRY ListHead,
2087     BOOLEAN ListUsesMisses)
2088 
2089 {
2090     PSYSTEM_LOOKASIDE_INFORMATION Info;
2091     PGENERAL_LOOKASIDE LookasideList;
2092     PLIST_ENTRY ListEntry;
2093     ULONG Remaining;
2094 
2095     /* Get info pointer and remaining count of free array element */
2096     Info = *InfoPointer;
2097     Remaining = *RemainingPointer;
2098 
2099     /* Loop as long as we have lookaside lists and free array elements */
2100     for (ListEntry = ListHead->Flink;
2101          (ListEntry != ListHead) && (Remaining > 0);
2102          ListEntry = ListEntry->Flink, Remaining--)
2103     {
2104         LookasideList = CONTAINING_RECORD(ListEntry, GENERAL_LOOKASIDE, ListEntry);
2105 
2106         /* Fill the next array element */
2107         Info->CurrentDepth = LookasideList->Depth;
2108         Info->MaximumDepth = LookasideList->MaximumDepth;
2109         Info->TotalAllocates = LookasideList->TotalAllocates;
2110         Info->TotalFrees = LookasideList->TotalFrees;
2111         Info->Type = LookasideList->Type;
2112         Info->Tag = LookasideList->Tag;
2113         Info->Size = LookasideList->Size;
2114 
2115         /* Check how the lists track misses/hits */
2116         if (ListUsesMisses)
2117         {
2118             /* Copy misses */
2119             Info->AllocateMisses = LookasideList->AllocateMisses;
2120             Info->FreeMisses = LookasideList->FreeMisses;
2121         }
2122         else
2123         {
2124             /* Calculate misses */
2125             Info->AllocateMisses = LookasideList->TotalAllocates
2126                                    - LookasideList->AllocateHits;
2127             Info->FreeMisses = LookasideList->TotalFrees
2128                                - LookasideList->FreeHits;
2129         }
2130     }
2131 
2132     /* Return the updated pointer and remaining count */
2133     *InfoPointer = Info;
2134     *RemainingPointer = Remaining;
2135 }
2136 
2137 /* Class 45 - Lookaside Information */
2138 QSI_DEF(SystemLookasideInformation)
2139 {
2140     KPROCESSOR_MODE PreviousMode;
2141     PSYSTEM_LOOKASIDE_INFORMATION Info;
2142     PMDL Mdl;
2143     ULONG MaxCount, Remaining;
2144     KIRQL OldIrql;
2145     NTSTATUS Status;
2146 
2147     /* First we need to lock down the memory, since we are going to access it
2148        at high IRQL */
2149     PreviousMode = ExGetPreviousMode();
2150     Status = ExLockUserBuffer(Buffer,
2151                               Size,
2152                               PreviousMode,
2153                               IoWriteAccess,
2154                               (PVOID*)&Info,
2155                               &Mdl);
2156     if (!NT_SUCCESS(Status))
2157     {
2158         DPRINT1("Failed to lock the user buffer: 0x%lx\n", Status);
2159         return Status;
2160     }
2161 
2162     /* Calculate how many items we can store */
2163     Remaining = MaxCount = Size / sizeof(SYSTEM_LOOKASIDE_INFORMATION);
2164     if (Remaining == 0)
2165     {
2166         goto Leave;
2167     }
2168 
2169     /* Copy info from pool lookaside lists */
2170     ExpCopyLookasideInformation(&Info,
2171                                 &Remaining,
2172                                 &ExPoolLookasideListHead,
2173                                 FALSE);
2174     if (Remaining == 0)
2175     {
2176         goto Leave;
2177     }
2178 
2179     /* Copy info from system lookaside lists */
2180     ExpCopyLookasideInformation(&Info,
2181                                 &Remaining,
2182                                 &ExSystemLookasideListHead,
2183                                 TRUE);
2184     if (Remaining == 0)
2185     {
2186         goto Leave;
2187     }
2188 
2189     /* Acquire spinlock for ExpNonPagedLookasideListHead */
2190     KeAcquireSpinLock(&ExpNonPagedLookasideListLock, &OldIrql);
2191 
2192     /* Copy info from non-paged lookaside lists */
2193     ExpCopyLookasideInformation(&Info,
2194                                 &Remaining,
2195                                 &ExpNonPagedLookasideListHead,
2196                                 TRUE);
2197 
2198     /* Release spinlock for ExpNonPagedLookasideListHead */
2199     KeReleaseSpinLock(&ExpNonPagedLookasideListLock, OldIrql);
2200 
2201     if (Remaining == 0)
2202     {
2203         goto Leave;
2204     }
2205 
2206     /* Acquire spinlock for ExpPagedLookasideListHead */
2207     KeAcquireSpinLock(&ExpPagedLookasideListLock, &OldIrql);
2208 
2209     /* Copy info from paged lookaside lists */
2210     ExpCopyLookasideInformation(&Info,
2211                                 &Remaining,
2212                                 &ExpPagedLookasideListHead,
2213                                 TRUE);
2214 
2215     /* Release spinlock for ExpPagedLookasideListHead */
2216     KeReleaseSpinLock(&ExpPagedLookasideListLock, OldIrql);
2217 
2218 Leave:
2219 
2220     /* Release the locked user buffer */
2221     ExUnlockUserBuffer(Mdl);
2222 
2223     /* Return the size of the actually written data */
2224     *ReqSize = (MaxCount - Remaining) * sizeof(SYSTEM_LOOKASIDE_INFORMATION);
2225     return STATUS_SUCCESS;
2226 }
2227 
2228 
2229 /* Class 46 - Set time slip event */
2230 SSI_DEF(SystemTimeSlipNotification)
2231 {
2232     /* FIXME */
2233     DPRINT1("NtSetSystemInformation - SystemTimeSlipNotification not implemented\n");
2234     return STATUS_NOT_IMPLEMENTED;
2235 }
2236 
2237 NTSTATUS
2238 NTAPI
2239 MmSessionCreate(OUT PULONG SessionId);
2240 
2241 NTSTATUS
2242 NTAPI
2243 MmSessionDelete(IN ULONG SessionId);
2244 
2245 /* Class 47 - Create a new session (TSE) */
2246 SSI_DEF(SystemSessionCreate)
2247 {
2248     ULONG SessionId;
2249     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2250     NTSTATUS Status;
2251 
2252     if (Size != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2253 
2254     if (PreviousMode != KernelMode)
2255     {
2256         if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2257         {
2258             return STATUS_PRIVILEGE_NOT_HELD;
2259         }
2260 
2261         ProbeForWriteUlong(Buffer);
2262     }
2263 
2264     Status = MmSessionCreate(&SessionId);
2265     if (NT_SUCCESS(Status)) *(PULONG)Buffer = SessionId;
2266 
2267     return Status;
2268 }
2269 
2270 
2271 /* Class 48 - Delete an existing session (TSE) */
2272 SSI_DEF(SystemSessionDetach)
2273 {
2274     ULONG SessionId;
2275     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2276 
2277     if (Size != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2278 
2279     if (PreviousMode != KernelMode)
2280     {
2281         if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2282         {
2283             return STATUS_PRIVILEGE_NOT_HELD;
2284         }
2285     }
2286 
2287     SessionId = *(PULONG)Buffer;
2288 
2289     return MmSessionDelete(SessionId);
2290 }
2291 
2292 
2293 /* Class 49 - UNKNOWN */
2294 QSI_DEF(SystemSessionInformation)
2295 {
2296     /* FIXME */
2297     DPRINT1("NtQuerySystemInformation - SystemSessionInformation not implemented\n");
2298     return STATUS_NOT_IMPLEMENTED;
2299 }
2300 
2301 
2302 /* Class 50 - System range start address */
2303 QSI_DEF(SystemRangeStartInformation)
2304 {
2305     /* Check user buffer's size */
2306     if (Size != sizeof(ULONG_PTR)) return STATUS_INFO_LENGTH_MISMATCH;
2307 
2308     *(PULONG_PTR)Buffer = (ULONG_PTR)MmSystemRangeStart;
2309 
2310     if (ReqSize) *ReqSize = sizeof(ULONG_PTR);
2311 
2312     return STATUS_SUCCESS;
2313 }
2314 
2315 /* Class 51 - Driver verifier information */
2316 QSI_DEF(SystemVerifierInformation)
2317 {
2318     /* FIXME */
2319     DPRINT1("NtQuerySystemInformation - SystemVerifierInformation not implemented\n");
2320     return STATUS_NOT_IMPLEMENTED;
2321 }
2322 
2323 
2324 SSI_DEF(SystemVerifierInformation)
2325 {
2326     /* FIXME */
2327     DPRINT1("NtSetSystemInformation - SystemVerifierInformation not implemented\n");
2328     return STATUS_NOT_IMPLEMENTED;
2329 }
2330 
2331 
2332 /* Class 52 */
2333 SSI_DEF(SystemVerifierThunkExtend)
2334 {
2335     /* FIXME */
2336     DPRINT1("NtSetSystemInformation - SystemVerifierThunkExtend not implemented\n");
2337     return STATUS_NOT_IMPLEMENTED;
2338 }
2339 
2340 
2341 /* Class 53 - A session's processes  */
2342 QSI_DEF(SystemSessionProcessesInformation)
2343 {
2344     /* FIXME */
2345     DPRINT1("NtQuerySystemInformation - SystemSessionProcessInformation not implemented\n");
2346     return STATUS_NOT_IMPLEMENTED;
2347 }
2348 
2349 
2350 /* Class 54 - Load & map in system space */
2351 SSI_DEF(SystemLoadGdiDriverInSystemSpaceInformation)
2352 {
2353     /* FIXME */
2354     DPRINT1("NtSetSystemInformation - SystemLoadGdiDriverInSystemSpaceInformation not implemented\n");
2355     return STATUS_NOT_IMPLEMENTED;
2356 }
2357 
2358 
2359 /* Class 55 - NUMA processor information  */
2360 QSI_DEF(SystemNumaProcessorMap)
2361 {
2362     ULONG MaxEntries, Node;
2363     PSYSTEM_NUMA_INFORMATION NumaInformation = (PSYSTEM_NUMA_INFORMATION)Buffer;
2364 
2365     /* Validate input size */
2366     if (Size < sizeof(ULONG))
2367     {
2368         return STATUS_INFO_LENGTH_MISMATCH;
2369     }
2370 
2371     /* Return highest node */
2372     NumaInformation->HighestNodeNumber = KeNumberNodes - 1;
2373 
2374     /* Compute how much entries we will be able to put in output structure */
2375     MaxEntries = (Size - FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, ActiveProcessorsAffinityMask)) / sizeof(ULONGLONG);
2376     /* Make sure we don't overflow KeNodeBlock */
2377     if (MaxEntries > KeNumberNodes)
2378     {
2379         MaxEntries = KeNumberNodes;
2380     }
2381 
2382     /* If we have entries to write, and room for it */
2383     if (Size >= FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, ActiveProcessorsAffinityMask) &&
2384         MaxEntries != 0)
2385     {
2386         /* Already set size we return */
2387         *ReqSize = FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, ActiveProcessorsAffinityMask) +
2388                    MaxEntries * sizeof(ULONGLONG);
2389 
2390         /* For each node, return processor mask */
2391         for (Node = 0; Node < MaxEntries; ++Node)
2392         {
2393             NumaInformation->ActiveProcessorsAffinityMask[Node] = KeNodeBlock[Node]->ProcessorMask;
2394         }
2395     }
2396     else
2397     {
2398         /* We only returned highest node number */
2399         *ReqSize = sizeof(ULONG);
2400     }
2401 
2402     return STATUS_SUCCESS;
2403 }
2404 
2405 
2406 /* Class 56 - Prefetcher information  */
2407 QSI_DEF(SystemPrefetcherInformation)
2408 {
2409     /* FIXME */
2410     DPRINT1("NtQuerySystemInformation - SystemPrefetcherInformation not implemented\n");
2411     return STATUS_NOT_IMPLEMENTED;
2412 }
2413 
2414 
2415 /* Class 57 - Extended process information  */
2416 QSI_DEF(SystemExtendedProcessInformation)
2417 {
2418     /* FIXME */
2419     DPRINT1("NtQuerySystemInformation - SystemExtendedProcessInformation not implemented\n");
2420     return STATUS_NOT_IMPLEMENTED;
2421 }
2422 
2423 
2424 /* Class 58 - Recommended shared ata alignment  */
2425 QSI_DEF(SystemRecommendedSharedDataAlignment)
2426 {
2427     /* FIXME */
2428     DPRINT1("NtQuerySystemInformation - SystemRecommendedSharedDataAlignment not implemented\n");
2429     return STATUS_NOT_IMPLEMENTED;
2430 }
2431 
2432 
2433 /* Class 60 - NUMA memory information  */
2434 QSI_DEF(SystemNumaAvailableMemory)
2435 {
2436     ULONG MaxEntries, Node;
2437     PSYSTEM_NUMA_INFORMATION NumaInformation = (PSYSTEM_NUMA_INFORMATION)Buffer;
2438 
2439     /* Validate input size */
2440     if (Size < sizeof(ULONG))
2441     {
2442         return STATUS_INFO_LENGTH_MISMATCH;
2443     }
2444 
2445     /* Return highest node */
2446     NumaInformation->HighestNodeNumber = KeNumberNodes - 1;
2447 
2448     /* Compute how much entries we will be able to put in output structure */
2449     MaxEntries = (Size - FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, AvailableMemory)) / sizeof(ULONGLONG);
2450     /* Make sure we don't overflow KeNodeBlock */
2451     if (MaxEntries > KeNumberNodes)
2452     {
2453         MaxEntries = KeNumberNodes;
2454     }
2455 
2456     /* If we have entries to write, and room for it */
2457     if (Size >= FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, AvailableMemory) &&
2458         MaxEntries != 0)
2459     {
2460         /* Already set size we return */
2461         *ReqSize = FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, AvailableMemory) +
2462                    MaxEntries * sizeof(ULONGLONG);
2463 
2464         /* If we have a single entry (us), directly return MM information */
2465         if (MaxEntries == 1)
2466         {
2467             NumaInformation->AvailableMemory[0] = MmAvailablePages << PAGE_SHIFT;
2468         }
2469         else
2470         {
2471             /* Otherwise, for each node, return available bytes */
2472             for (Node = 0; Node < MaxEntries; ++Node)
2473             {
2474                 NumaInformation->AvailableMemory[Node] = (KeNodeBlock[Node]->FreeCount[0] + KeNodeBlock[Node]->FreeCount[1]) << PAGE_SHIFT;
2475             }
2476         }
2477     }
2478     else
2479     {
2480         /* We only returned highest node number */
2481         *ReqSize = sizeof(ULONG);
2482     }
2483 
2484     return STATUS_SUCCESS;
2485 }
2486 
2487 /* Class 64 - Extended handle information  */
2488 QSI_DEF(SystemExtendedHandleInformation)
2489 {
2490     PSYSTEM_HANDLE_INFORMATION_EX HandleInformation;
2491     PLIST_ENTRY NextTableEntry;
2492     PHANDLE_TABLE HandleTable;
2493     PHANDLE_TABLE_ENTRY HandleTableEntry;
2494     EXHANDLE Handle;
2495     ULONG Index = 0;
2496     NTSTATUS Status;
2497     PMDL Mdl;
2498     PAGED_CODE();
2499 
2500     DPRINT("NtQuerySystemInformation - SystemExtendedHandleInformation\n");
2501 
2502     /* Set initial required buffer size */
2503     *ReqSize = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handle);
2504 
2505     /* Check user's buffer size */
2506     if (Size < *ReqSize)
2507     {
2508         return STATUS_INFO_LENGTH_MISMATCH;
2509     }
2510 
2511     /* We need to lock down the memory */
2512     Status = ExLockUserBuffer(Buffer,
2513                               Size,
2514                               ExGetPreviousMode(),
2515                               IoWriteAccess,
2516                               (PVOID*)&HandleInformation,
2517                               &Mdl);
2518     if (!NT_SUCCESS(Status))
2519     {
2520         DPRINT1("Failed to lock the user buffer: 0x%lx\n", Status);
2521         return Status;
2522     }
2523 
2524     /* Reset of count of handles */
2525     HandleInformation->Count = 0;
2526 
2527     /* Enter a critical region */
2528     KeEnterCriticalRegion();
2529 
2530     /* Acquire the handle table lock */
2531     ExAcquirePushLockShared(&HandleTableListLock);
2532 
2533     /* Enumerate all system handles */
2534     for (NextTableEntry = HandleTableListHead.Flink;
2535          NextTableEntry != &HandleTableListHead;
2536          NextTableEntry = NextTableEntry->Flink)
2537     {
2538         /* Get current handle table */
2539         HandleTable = CONTAINING_RECORD(NextTableEntry, HANDLE_TABLE, HandleTableList);
2540 
2541         /* Set the initial value and loop the entries */
2542         Handle.Value = 0;
2543         while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle)))
2544         {
2545             /* Validate the entry */
2546             if ((HandleTableEntry->Object) &&
2547                 (HandleTableEntry->NextFreeTableEntry != -2))
2548             {
2549                 /* Increase of count of handles */
2550                 ++HandleInformation->Count;
2551 
2552                 /* Lock the entry */
2553                 if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
2554                 {
2555                     /* Increase required buffer size */
2556                     *ReqSize += sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX);
2557 
2558                     /* Check user's buffer size */
2559                     if (*ReqSize > Size)
2560                     {
2561                         Status = STATUS_INFO_LENGTH_MISMATCH;
2562                     }
2563                     else
2564                     {
2565                         POBJECT_HEADER ObjectHeader = ObpGetHandleObject(HandleTableEntry);
2566 
2567                         /* Filling handle information */
2568                         HandleInformation->Handle[Index].UniqueProcessId =
2569                             (USHORT)(ULONG_PTR) HandleTable->UniqueProcessId;
2570 
2571                         HandleInformation->Handle[Index].CreatorBackTraceIndex = 0;
2572 
2573 #if 0 /* FIXME!!! Type field currupted */
2574                         HandleInformation->Handles[Index].ObjectTypeIndex =
2575                             (UCHAR) ObjectHeader->Type->Index;
2576 #else
2577                         HandleInformation->Handle[Index].ObjectTypeIndex = 0;
2578 #endif
2579 
2580                         HandleInformation->Handle[Index].HandleAttributes =
2581                             HandleTableEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
2582 
2583                         HandleInformation->Handle[Index].HandleValue =
2584                             (USHORT)(ULONG_PTR) Handle.GenericHandleOverlay;
2585 
2586                         HandleInformation->Handle[Index].Object = &ObjectHeader->Body;
2587 
2588                         HandleInformation->Handle[Index].GrantedAccess =
2589                             HandleTableEntry->GrantedAccess;
2590 
2591                         HandleInformation->Handle[Index].Reserved = 0;
2592 
2593                         ++Index;
2594                     }
2595 
2596                     /* Unlock it */
2597                     ExUnlockHandleTableEntry(HandleTable, HandleTableEntry);
2598                 }
2599             }
2600 
2601             /* Go to the next entry */
2602             Handle.Value += sizeof(HANDLE);
2603         }
2604     }
2605 
2606     /* Release the lock */
2607     ExReleasePushLockShared(&HandleTableListLock);
2608 
2609     /* Leave the critical region */
2610     KeLeaveCriticalRegion();
2611 
2612     /* Release the locked user buffer */
2613     ExUnlockUserBuffer(Mdl);
2614 
2615     return Status;
2616 }
2617 
2618 /* Class 76 - System firmware table information  */
2619 QSI_DEF(SystemFirmwareTableInformation)
2620 {
2621     PSYSTEM_FIRMWARE_TABLE_INFORMATION SysFirmwareInfo = (PSYSTEM_FIRMWARE_TABLE_INFORMATION)Buffer;
2622     NTSTATUS Status = STATUS_SUCCESS;
2623     ULONG InputBufSize;
2624     ULONG DataSize = 0;
2625     ULONG TableCount = 0;
2626 
2627     DPRINT("NtQuerySystemInformation - SystemFirmwareTableInformation\n");
2628 
2629     /* Set initial required buffer size */
2630     *ReqSize = FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
2631 
2632     /* Check user's buffer size */
2633     if (Size < *ReqSize)
2634     {
2635         return STATUS_INFO_LENGTH_MISMATCH;
2636     }
2637 
2638     InputBufSize = SysFirmwareInfo->TableBufferLength;
2639     switch (SysFirmwareInfo->ProviderSignature)
2640     {
2641         /*
2642          * ExpFirmwareTableResource and ExpFirmwareTableProviderListHead
2643          * variables should be used there somehow...
2644          */
2645         case SIG_ACPI:
2646         {
2647             /* FIXME: Not implemented yet */
2648             DPRINT1("ACPI provider not implemented\n");
2649             Status = STATUS_NOT_IMPLEMENTED;
2650             break;
2651         }
2652         case SIG_FIRM:
2653         {
2654             /* FIXME: Not implemented yet */
2655             DPRINT1("FIRM provider not implemented\n");
2656             Status = STATUS_NOT_IMPLEMENTED;
2657             break;
2658         }
2659         case SIG_RSMB:
2660         {
2661             Status = ExpGetRawSMBiosTable(NULL, &DataSize, 0);
2662             if (DataSize > 0)
2663             {
2664                 TableCount = 1;
2665                 if (SysFirmwareInfo->Action == SystemFirmwareTable_Enumerate)
2666                 {
2667                     DataSize = TableCount * sizeof(ULONG);
2668                     if (DataSize <= InputBufSize)
2669                     {
2670                         *(ULONG *)SysFirmwareInfo->TableBuffer = 0;
2671                     }
2672                 }
2673                 else if (SysFirmwareInfo->Action == SystemFirmwareTable_Get
2674                          && DataSize <= InputBufSize)
2675                 {
2676                     Status = ExpGetRawSMBiosTable(SysFirmwareInfo->TableBuffer, &DataSize, InputBufSize);
2677                 }
2678                 SysFirmwareInfo->TableBufferLength = DataSize;
2679             }
2680             break;
2681         }
2682         default:
2683         {
2684             DPRINT1("SystemFirmwareTableInformation: Unsupported provider (0x%x)\n",
2685                     SysFirmwareInfo->ProviderSignature);
2686             Status = STATUS_ILLEGAL_FUNCTION;
2687         }
2688     }
2689 
2690     if (NT_SUCCESS(Status))
2691     {
2692         switch (SysFirmwareInfo->Action)
2693         {
2694             case SystemFirmwareTable_Enumerate:
2695             case SystemFirmwareTable_Get:
2696             {
2697                 if (SysFirmwareInfo->TableBufferLength > InputBufSize)
2698                 {
2699                     Status = STATUS_BUFFER_TOO_SMALL;
2700                 }
2701                 break;
2702             }
2703             default:
2704             {
2705                 DPRINT1("SystemFirmwareTableInformation: Unsupported action (0x%x)\n",
2706                         SysFirmwareInfo->Action);
2707                 Status = STATUS_ILLEGAL_FUNCTION;
2708             }
2709         }
2710     }
2711     else
2712     {
2713         SysFirmwareInfo->TableBufferLength = 0;
2714     }
2715     return Status;
2716 }
2717 
2718 /* Query/Set Calls Table */
2719 typedef
2720 struct _QSSI_CALLS
2721 {
2722     NTSTATUS (* Query) (PVOID,ULONG,PULONG);
2723     NTSTATUS (* Set) (PVOID,ULONG);
2724 } QSSI_CALLS;
2725 
2726 // QS    Query & Set
2727 // QX    Query
2728 // XS    Set
2729 // XX    unknown behaviour
2730 //
2731 #define SI_QS(n) {QSI_USE(n),SSI_USE(n)}
2732 #define SI_QX(n) {QSI_USE(n),NULL}
2733 #define SI_XS(n) {NULL,SSI_USE(n)}
2734 #define SI_XX(n) {NULL,NULL}
2735 
2736 static
2737 QSSI_CALLS
2738 CallQS [] =
2739 {
2740     SI_QX(SystemBasicInformation),
2741     SI_QX(SystemProcessorInformation),
2742     SI_QX(SystemPerformanceInformation),
2743     SI_QX(SystemTimeOfDayInformation),
2744     SI_QX(SystemPathInformation), /* should be SI_XX */
2745     SI_QX(SystemProcessInformation),
2746     SI_QX(SystemCallCountInformation),
2747     SI_QX(SystemDeviceInformation),
2748     SI_QX(SystemProcessorPerformanceInformation),
2749     SI_QS(SystemFlagsInformation),
2750     SI_QX(SystemCallTimeInformation), /* should be SI_XX */
2751     SI_QX(SystemModuleInformation),
2752     SI_QX(SystemLocksInformation),
2753     SI_QX(SystemStackTraceInformation), /* should be SI_XX */
2754     SI_QX(SystemPagedPoolInformation), /* should be SI_XX */
2755     SI_QX(SystemNonPagedPoolInformation), /* should be SI_XX */
2756     SI_QX(SystemHandleInformation),
2757     SI_QX(SystemObjectInformation),
2758     SI_QX(SystemPageFileInformation),
2759     SI_QX(SystemVdmInstemulInformation),
2760     SI_QX(SystemVdmBopInformation), /* it should be SI_XX */
2761     SI_QS(SystemFileCacheInformation),
2762     SI_QX(SystemPoolTagInformation),
2763     SI_QX(SystemInterruptInformation),
2764     SI_QS(SystemDpcBehaviourInformation),
2765     SI_QX(SystemFullMemoryInformation), /* it should be SI_XX */
2766     SI_XS(SystemLoadGdiDriverInformation),
2767     SI_XS(SystemUnloadGdiDriverInformation),
2768     SI_QS(SystemTimeAdjustmentInformation),
2769     SI_QX(SystemSummaryMemoryInformation), /* it should be SI_XX */
2770     SI_QX(SystemNextEventIdInformation), /* it should be SI_XX */
2771     SI_QX(SystemPerformanceTraceInformation), /* it should be SI_XX */
2772     SI_QX(SystemCrashDumpInformation),
2773     SI_QX(SystemExceptionInformation),
2774     SI_QX(SystemCrashDumpStateInformation),
2775     SI_QX(SystemKernelDebuggerInformation),
2776     SI_QX(SystemContextSwitchInformation),
2777     SI_QS(SystemRegistryQuotaInformation),
2778     SI_XS(SystemExtendServiceTableInformation),
2779     SI_XS(SystemPrioritySeperation),
2780     SI_QX(SystemVerifierAddDriverInformation), /* it should be SI_XX */
2781     SI_QX(SystemVerifierRemoveDriverInformation), /* it should be SI_XX */
2782     SI_QX(SystemProcessorIdleInformation), /* it should be SI_XX */
2783     SI_QX(SystemLegacyDriverInformation), /* it should be SI_XX */
2784     SI_QS(SystemCurrentTimeZoneInformation), /* it should be SI_QX */
2785     SI_QX(SystemLookasideInformation),
2786     SI_XS(SystemTimeSlipNotification),
2787     SI_XS(SystemSessionCreate),
2788     SI_XS(SystemSessionDetach),
2789     SI_QX(SystemSessionInformation), /* it should be SI_XX */
2790     SI_QX(SystemRangeStartInformation),
2791     SI_QS(SystemVerifierInformation),
2792     SI_XS(SystemVerifierThunkExtend),
2793     SI_QX(SystemSessionProcessesInformation),
2794     SI_XS(SystemLoadGdiDriverInSystemSpaceInformation),
2795     SI_QX(SystemNumaProcessorMap),
2796     SI_QX(SystemPrefetcherInformation),
2797     SI_QX(SystemExtendedProcessInformation),
2798     SI_QX(SystemRecommendedSharedDataAlignment),
2799     SI_XX(SystemComPlusPackage),
2800     SI_QX(SystemNumaAvailableMemory),
2801     SI_XX(SystemProcessorPowerInformation), /* FIXME: not implemented */
2802     SI_XX(SystemEmulationBasicInformation), /* FIXME: not implemented */
2803     SI_XX(SystemEmulationProcessorInformation), /* FIXME: not implemented */
2804     SI_QX(SystemExtendedHandleInformation),
2805     SI_XX(SystemLostDelayedWriteInformation), /* FIXME: not implemented */
2806     SI_XX(SystemBigPoolInformation), /* FIXME: not implemented */
2807     SI_XX(SystemSessionPoolTagInformation), /* FIXME: not implemented */
2808     SI_XX(SystemSessionMappedViewInformation), /* FIXME: not implemented */
2809     SI_XX(SystemHotpatchInformation), /* FIXME: not implemented */
2810     SI_XX(SystemObjectSecurityMode), /* FIXME: not implemented */
2811     SI_XX(SystemWatchdogTimerHandler), /* FIXME: not implemented */
2812     SI_XX(SystemWatchdogTimerInformation), /* FIXME: not implemented */
2813     SI_XX(SystemLogicalProcessorInformation), /* FIXME: not implemented */
2814     SI_XX(SystemWow64SharedInformation), /* FIXME: not implemented */
2815     SI_XX(SystemRegisterFirmwareTableInformationHandler), /* FIXME: not implemented */
2816     SI_QX(SystemFirmwareTableInformation),
2817 };
2818 
2819 C_ASSERT(SystemBasicInformation == 0);
2820 #define MIN_SYSTEM_INFO_CLASS (SystemBasicInformation)
2821 #define MAX_SYSTEM_INFO_CLASS (sizeof(CallQS) / sizeof(CallQS[0]))
2822 
2823 /*
2824  * @implemented
2825  */
2826 __kernel_entry
2827 NTSTATUS
2828 NTAPI
2829 NtQuerySystemInformation(
2830     _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
2831     _Out_writes_bytes_to_opt_(SystemInformationLength, *ReturnLength) PVOID SystemInformation,
2832     _In_ ULONG Length,
2833     _Out_opt_ PULONG UnsafeResultLength)
2834 {
2835     KPROCESSOR_MODE PreviousMode;
2836     ULONG ResultLength = 0;
2837     ULONG Alignment = TYPE_ALIGNMENT(ULONG);
2838     NTSTATUS FStatus = STATUS_NOT_IMPLEMENTED;
2839 
2840     PAGED_CODE();
2841 
2842     PreviousMode = ExGetPreviousMode();
2843 
2844     _SEH2_TRY
2845     {
2846 #if (NTDDI_VERSION >= NTDDI_VISTA)
2847         /*
2848          * Check if the request is valid.
2849          */
2850         if (SystemInformationClass >= MAX_SYSTEM_INFO_CLASS)
2851         {
2852             _SEH2_YIELD(return STATUS_INVALID_INFO_CLASS);
2853         }
2854 #endif
2855 
2856         if (PreviousMode != KernelMode)
2857         {
2858             /* SystemKernelDebuggerInformation needs only BOOLEAN alignment */
2859             if (SystemInformationClass == SystemKernelDebuggerInformation)
2860                 Alignment = TYPE_ALIGNMENT(BOOLEAN);
2861 
2862             ProbeForWrite(SystemInformation, Length, Alignment);
2863             if (UnsafeResultLength != NULL)
2864                 ProbeForWriteUlong(UnsafeResultLength);
2865         }
2866 
2867         if (UnsafeResultLength)
2868             *UnsafeResultLength = 0;
2869 
2870 #if (NTDDI_VERSION < NTDDI_VISTA)
2871         /*
2872          * Check if the request is valid.
2873          */
2874         if (SystemInformationClass >= MAX_SYSTEM_INFO_CLASS)
2875         {
2876             _SEH2_YIELD(return STATUS_INVALID_INFO_CLASS);
2877         }
2878 #endif
2879 
2880         if (NULL != CallQS [SystemInformationClass].Query)
2881         {
2882             /*
2883              * Hand the request to a subhandler.
2884              */
2885             FStatus = CallQS [SystemInformationClass].Query(SystemInformation,
2886                                                             Length,
2887                                                             &ResultLength);
2888 
2889             /* Save the result length to the caller */
2890             if (UnsafeResultLength)
2891                 *UnsafeResultLength = ResultLength;
2892         }
2893     }
2894     _SEH2_EXCEPT(ExSystemExceptionFilter())
2895     {
2896         FStatus = _SEH2_GetExceptionCode();
2897     }
2898     _SEH2_END;
2899 
2900     return FStatus;
2901 }
2902 
2903 
2904 NTSTATUS
2905 NTAPI
2906 NtSetSystemInformation (IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
2907                         IN PVOID SystemInformation,
2908                         IN ULONG SystemInformationLength)
2909 {
2910     NTSTATUS Status = STATUS_INVALID_INFO_CLASS;
2911     KPROCESSOR_MODE PreviousMode;
2912 
2913     PAGED_CODE();
2914 
2915     PreviousMode = ExGetPreviousMode();
2916 
2917     _SEH2_TRY
2918     {
2919         /*
2920          * If called from user mode, check
2921          * possible unsafe arguments.
2922          */
2923         if (PreviousMode != KernelMode)
2924         {
2925             ProbeForRead(SystemInformation, SystemInformationLength, sizeof(ULONG));
2926         }
2927 
2928         /*
2929          * Check the request is valid.
2930          */
2931         if ((SystemInformationClass >= MIN_SYSTEM_INFO_CLASS) &&
2932             (SystemInformationClass < MAX_SYSTEM_INFO_CLASS))
2933         {
2934             if (NULL != CallQS [SystemInformationClass].Set)
2935             {
2936                 /*
2937                  * Hand the request to a subhandler.
2938                  */
2939                 Status = CallQS [SystemInformationClass].Set(SystemInformation,
2940                                                              SystemInformationLength);
2941             }
2942         }
2943     }
2944     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2945     {
2946         Status = _SEH2_GetExceptionCode();
2947     }
2948     _SEH2_END;
2949 
2950     return Status;
2951 }
2952 
2953 ULONG
2954 NTAPI
2955 NtGetCurrentProcessorNumber(VOID)
2956 {
2957     /* Just use Ke */
2958     return KeGetCurrentProcessorNumber();
2959 }
2960 
2961 #undef ExGetPreviousMode
2962 KPROCESSOR_MODE
2963 NTAPI
2964 ExGetPreviousMode(VOID)
2965 {
2966     /* Just use Ke */
2967     return KeGetPreviousMode();
2968 }
2969