xref: /reactos/ntoskrnl/ex/sysinfo.c (revision 9164e9f8)
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     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
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 IdleTime,
346                             PULONG KernelAndUserTime,
347                             PULONG ProcessorNumber)
348 {
349     PKPRCB Prcb;
350 
351     Prcb = KeGetCurrentPrcb();
352 
353     *IdleTime = Prcb->IdleThread->KernelTime;
354     *KernelAndUserTime = Prcb->KernelTime + Prcb->UserTime;
355     *ProcessorNumber = (ULONG)Prcb->Number;
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(
568     _In_ PUNICODE_STRING VariableName,
569     _In_ LPGUID VendorGuid,
570     _Out_opt_ PVOID Value,
571     _Inout_ PULONG ReturnLength,
572     _Out_opt_ PULONG Attributes)
573 {
574     UNIMPLEMENTED;
575     return STATUS_NOT_IMPLEMENTED;
576 }
577 
578 NTSTATUS
579 NTAPI
580 NtSetSystemEnvironmentValueEx(
581     _In_ PUNICODE_STRING VariableName,
582     _In_ LPGUID VendorGuid,
583     _In_reads_bytes_opt_(ValueLength) PVOID Value,
584     _In_ ULONG ValueLength,
585     _In_ ULONG Attributes)
586 {
587     UNIMPLEMENTED;
588     return STATUS_NOT_IMPLEMENTED;
589 }
590 
591 /* --- Query/Set System Information --- */
592 
593 /*
594  * NOTE: QSI_DEF(n) and SSI_DEF(n) define _cdecl function symbols
595  * so the stack is popped only in one place on x86 platform.
596  */
597 #define QSI_USE(n) QSI##n
598 #define QSI_DEF(n) \
599 static NTSTATUS QSI_USE(n) (PVOID Buffer, ULONG Size, PULONG ReqSize)
600 
601 #define SSI_USE(n) SSI##n
602 #define SSI_DEF(n) \
603 static NTSTATUS SSI_USE(n) (PVOID Buffer, ULONG Size)
604 
605 VOID
606 NTAPI
607 ExQueryPoolUsage(OUT PULONG PagedPoolPages,
608                  OUT PULONG NonPagedPoolPages,
609                  OUT PULONG PagedPoolAllocs,
610                  OUT PULONG PagedPoolFrees,
611                  OUT PULONG PagedPoolLookasideHits,
612                  OUT PULONG NonPagedPoolAllocs,
613                  OUT PULONG NonPagedPoolFrees,
614                  OUT PULONG NonPagedPoolLookasideHits);
615 
616 /* Class 0 - Basic Information */
617 QSI_DEF(SystemBasicInformation)
618 {
619     PSYSTEM_BASIC_INFORMATION Sbi
620         = (PSYSTEM_BASIC_INFORMATION) Buffer;
621 
622     *ReqSize = sizeof(SYSTEM_BASIC_INFORMATION);
623 
624     /* Check user buffer's size */
625     if (Size != sizeof(SYSTEM_BASIC_INFORMATION))
626     {
627         return STATUS_INFO_LENGTH_MISMATCH;
628     }
629 
630     RtlZeroMemory(Sbi, Size);
631     Sbi->Reserved = 0;
632     Sbi->TimerResolution = KeMaximumIncrement;
633     Sbi->PageSize = PAGE_SIZE;
634     Sbi->NumberOfPhysicalPages = MmNumberOfPhysicalPages;
635     Sbi->LowestPhysicalPageNumber = (ULONG)MmLowestPhysicalPage;
636     Sbi->HighestPhysicalPageNumber = (ULONG)MmHighestPhysicalPage;
637     Sbi->AllocationGranularity = MM_VIRTMEM_GRANULARITY; /* hard coded on Intel? */
638     Sbi->MinimumUserModeAddress = 0x10000; /* Top of 64k */
639     Sbi->MaximumUserModeAddress = (ULONG_PTR)MmHighestUserAddress;
640     Sbi->ActiveProcessorsAffinityMask = KeActiveProcessors;
641     Sbi->NumberOfProcessors = KeNumberProcessors;
642 
643     return STATUS_SUCCESS;
644 }
645 
646 /* Class 1 - Processor Information */
647 QSI_DEF(SystemProcessorInformation)
648 {
649     PSYSTEM_PROCESSOR_INFORMATION Spi
650         = (PSYSTEM_PROCESSOR_INFORMATION) Buffer;
651 
652     *ReqSize = sizeof(SYSTEM_PROCESSOR_INFORMATION);
653 
654     /* Check user buffer's size */
655     if (Size < sizeof(SYSTEM_PROCESSOR_INFORMATION))
656     {
657         return STATUS_INFO_LENGTH_MISMATCH;
658     }
659     Spi->ProcessorArchitecture = KeProcessorArchitecture;
660     Spi->ProcessorLevel = KeProcessorLevel;
661     Spi->ProcessorRevision = KeProcessorRevision;
662 #if (NTDDI_VERSION < NTDDI_WIN8)
663     Spi->Reserved = 0;
664 #else
665     Spi->MaximumProcessors = 0;
666 #endif
667 
668     /* According to Geoff Chappell, on Win 8.1 x64 / Win 10 x86, where this
669        field is extended to 64 bits, it continues to produce only the low 32
670        bits. For the full value, use SYSTEM_PROCESSOR_FEATURES_INFORMATION.
671        See https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/processor.htm
672      */
673     Spi->ProcessorFeatureBits = (ULONG)KeFeatureBits;
674 
675     DPRINT("Arch %u Level %u Rev 0x%x\n", Spi->ProcessorArchitecture,
676         Spi->ProcessorLevel, Spi->ProcessorRevision);
677 
678     return STATUS_SUCCESS;
679 }
680 
681 /* Class 2 - Performance Information */
682 QSI_DEF(SystemPerformanceInformation)
683 {
684     LONG i;
685     ULONG IdleUser, IdleKernel;
686     PKPRCB Prcb;
687     PSYSTEM_PERFORMANCE_INFORMATION Spi
688         = (PSYSTEM_PERFORMANCE_INFORMATION) Buffer;
689 
690     PEPROCESS TheIdleProcess;
691 
692     *ReqSize = sizeof(SYSTEM_PERFORMANCE_INFORMATION);
693 
694     /* Check user buffer's size */
695     if (Size < sizeof(SYSTEM_PERFORMANCE_INFORMATION))
696     {
697         return STATUS_INFO_LENGTH_MISMATCH;
698     }
699 
700     TheIdleProcess = PsIdleProcess;
701 
702     IdleKernel = KeQueryRuntimeProcess(&TheIdleProcess->Pcb, &IdleUser);
703     Spi->IdleProcessTime.QuadPart = UInt32x32To64(IdleKernel, KeMaximumIncrement);
704     Spi->IoReadTransferCount = IoReadTransferCount;
705     Spi->IoWriteTransferCount = IoWriteTransferCount;
706     Spi->IoOtherTransferCount = IoOtherTransferCount;
707     Spi->IoReadOperationCount = IoReadOperationCount;
708     Spi->IoWriteOperationCount = IoWriteOperationCount;
709     Spi->IoOtherOperationCount = IoOtherOperationCount;
710     for (i = 0; i < KeNumberProcessors; i ++)
711     {
712         Prcb = KiProcessorBlock[i];
713         if (Prcb)
714         {
715             Spi->IoReadTransferCount.QuadPart += Prcb->IoReadTransferCount.QuadPart;
716             Spi->IoWriteTransferCount.QuadPart += Prcb->IoWriteTransferCount.QuadPart;
717             Spi->IoOtherTransferCount.QuadPart += Prcb->IoOtherTransferCount.QuadPart;
718             Spi->IoReadOperationCount += Prcb->IoReadOperationCount;
719             Spi->IoWriteOperationCount += Prcb->IoWriteOperationCount;
720             Spi->IoOtherOperationCount += Prcb->IoOtherOperationCount;
721         }
722     }
723 
724     Spi->AvailablePages = (ULONG)MmAvailablePages;
725 
726     Spi->CommittedPages = MmTotalCommittedPages;
727     /*
728      *  Add up the full system total + pagefile.
729      *  All this make Taskmgr happy but not sure it is the right numbers.
730      *  This too, fixes some of GlobalMemoryStatusEx numbers.
731      */
732     Spi->CommitLimit = MmNumberOfPhysicalPages + MiFreeSwapPages + MiUsedSwapPages;
733 
734     Spi->PeakCommitment = MmPeakCommitment;
735     Spi->PageFaultCount = 0; /* FIXME */
736     Spi->CopyOnWriteCount = 0; /* FIXME */
737     Spi->TransitionCount = 0; /* FIXME */
738     Spi->CacheTransitionCount = 0; /* FIXME */
739     Spi->DemandZeroCount = 0; /* FIXME */
740     Spi->PageReadCount = 0; /* FIXME */
741     Spi->PageReadIoCount = 0; /* FIXME */
742     Spi->CacheReadCount = 0; /* FIXME */
743     Spi->CacheIoCount = 0; /* FIXME */
744     Spi->DirtyPagesWriteCount = 0; /* FIXME */
745     Spi->DirtyWriteIoCount = 0; /* FIXME */
746     Spi->MappedPagesWriteCount = 0; /* FIXME */
747     Spi->MappedWriteIoCount = 0; /* FIXME */
748 
749     Spi->PagedPoolPages = 0;
750     Spi->NonPagedPoolPages = 0;
751     Spi->PagedPoolAllocs = 0;
752     Spi->PagedPoolFrees = 0;
753     Spi->PagedPoolLookasideHits = 0;
754     Spi->NonPagedPoolAllocs = 0;
755     Spi->NonPagedPoolFrees = 0;
756     Spi->NonPagedPoolLookasideHits = 0;
757     ExQueryPoolUsage(&Spi->PagedPoolPages,
758                      &Spi->NonPagedPoolPages,
759                      &Spi->PagedPoolAllocs,
760                      &Spi->PagedPoolFrees,
761                      &Spi->PagedPoolLookasideHits,
762                      &Spi->NonPagedPoolAllocs,
763                      &Spi->NonPagedPoolFrees,
764                      &Spi->NonPagedPoolLookasideHits);
765     Spi->FreeSystemPtes = 0; /* FIXME */
766 
767     Spi->ResidentSystemCodePage = 0; /* FIXME */
768 
769     Spi->TotalSystemDriverPages = 0; /* FIXME */
770     Spi->Spare3Count = 0; /* FIXME */
771 
772     Spi->ResidentSystemCachePage = MiMemoryConsumers[MC_USER].PagesUsed; /* FIXME */
773     Spi->ResidentPagedPoolPage = 0; /* FIXME */
774 
775     Spi->ResidentSystemDriverPage = 0; /* FIXME */
776     Spi->CcFastReadNoWait = 0; /* FIXME */
777     Spi->CcFastReadWait = 0; /* FIXME */
778     Spi->CcFastReadResourceMiss = 0; /* FIXME */
779     Spi->CcFastReadNotPossible = 0; /* FIXME */
780 
781     Spi->CcFastMdlReadNoWait = 0; /* FIXME */
782     Spi->CcFastMdlReadWait = 0; /* FIXME */
783     Spi->CcFastMdlReadResourceMiss = 0; /* FIXME */
784     Spi->CcFastMdlReadNotPossible = 0; /* FIXME */
785 
786     Spi->CcMapDataNoWait = CcMapDataNoWait;
787     Spi->CcMapDataWait = CcMapDataWait;
788     Spi->CcMapDataNoWaitMiss = 0; /* FIXME */
789     Spi->CcMapDataWaitMiss = 0; /* FIXME */
790 
791     Spi->CcPinMappedDataCount = CcPinMappedDataCount;
792     Spi->CcPinReadNoWait = CcPinReadNoWait;
793     Spi->CcPinReadWait = CcPinReadWait;
794     Spi->CcPinReadNoWaitMiss = 0; /* FIXME */
795     Spi->CcPinReadWaitMiss = 0; /* FIXME */
796     Spi->CcCopyReadNoWait = 0; /* FIXME */
797     Spi->CcCopyReadWait = 0; /* FIXME */
798     Spi->CcCopyReadNoWaitMiss = 0; /* FIXME */
799     Spi->CcCopyReadWaitMiss = 0; /* FIXME */
800 
801     Spi->CcMdlReadNoWait = 0; /* FIXME */
802     Spi->CcMdlReadWait = 0; /* FIXME */
803     Spi->CcMdlReadNoWaitMiss = 0; /* FIXME */
804     Spi->CcMdlReadWaitMiss = 0; /* FIXME */
805     Spi->CcReadAheadIos = 0; /* FIXME */
806     Spi->CcLazyWriteIos = CcLazyWriteIos;
807     Spi->CcLazyWritePages = CcLazyWritePages;
808     Spi->CcDataFlushes = CcDataFlushes;
809     Spi->CcDataPages = CcDataPages;
810 
811     Spi->ContextSwitches = 0;
812     Spi->FirstLevelTbFills = 0;
813     Spi->SecondLevelTbFills = 0;
814     Spi->SystemCalls = 0;
815     for (i = 0; i < KeNumberProcessors; i ++)
816     {
817         Prcb = KiProcessorBlock[i];
818         if (Prcb)
819         {
820             Spi->ContextSwitches += KeGetContextSwitches(Prcb);
821             Spi->FirstLevelTbFills += Prcb->KeFirstLevelTbFills;
822             Spi->SecondLevelTbFills += Prcb->KeSecondLevelTbFills;
823             Spi->SystemCalls += Prcb->KeSystemCalls;
824         }
825     }
826 
827     return STATUS_SUCCESS;
828 }
829 
830 /* Class 3 - Time Of Day Information */
831 QSI_DEF(SystemTimeOfDayInformation)
832 {
833     SYSTEM_TIMEOFDAY_INFORMATION Sti;
834     LARGE_INTEGER CurrentTime;
835 
836     /* Set amount of written information to 0 */
837     *ReqSize = 0;
838 
839     /* Check user buffer's size */
840     if (Size > sizeof(SYSTEM_TIMEOFDAY_INFORMATION))
841     {
842         return STATUS_INFO_LENGTH_MISMATCH;
843     }
844 
845     /* Get current time */
846     KeQuerySystemTime(&CurrentTime);
847 
848     /* Zero local buffer */
849     RtlZeroMemory(&Sti, sizeof(SYSTEM_TIMEOFDAY_INFORMATION));
850 
851     /* Fill local time structure */
852     Sti.BootTime= KeBootTime;
853     Sti.CurrentTime = CurrentTime;
854     Sti.TimeZoneBias.QuadPart = ExpTimeZoneBias.QuadPart;
855     Sti.TimeZoneId = ExpTimeZoneId;
856     Sti.Reserved = 0;
857 
858     /* Copy as much as requested by caller */
859     RtlCopyMemory(Buffer, &Sti, Size);
860 
861     /* Set amount of information we copied */
862     *ReqSize = Size;
863 
864     return STATUS_SUCCESS;
865 }
866 
867 /* Class 4 - Path Information (DEPRECATED) */
868 QSI_DEF(SystemPathInformation)
869 {
870     /*
871      * Since NT 3.51, this information class is trivially implemented.
872      * The path to the NT directory is now stored in KUSER_SHARED_DATA
873      * as the NtSystemRoot member.
874      * Windows Checked builds show the following message and break to
875      * the debugger before failing the function as not implemented.
876      */
877 #if DBG
878     DPRINT1("EX: SystemPathInformation now available via SharedUserData\n");
879     // DbgBreakPoint(); // Not needed in ReactOS.
880 #endif
881     return STATUS_NOT_IMPLEMENTED;
882 }
883 
884 /* Class 5 - Process Information */
885 QSI_DEF(SystemProcessInformation)
886 {
887     PSYSTEM_PROCESS_INFORMATION SpiCurrent;
888     PSYSTEM_THREAD_INFORMATION ThreadInfo;
889     PEPROCESS Process = NULL, SystemProcess;
890     PETHREAD CurrentThread;
891     ANSI_STRING ImageName;
892     ULONG CurrentSize;
893     USHORT ImageNameMaximumLength; // image name length in bytes
894     USHORT ImageNameLength;
895     PLIST_ENTRY CurrentEntry;
896     ULONG TotalSize = 0, ThreadsCount;
897     ULONG TotalUser, TotalKernel;
898     PUCHAR Current;
899     NTSTATUS Status = STATUS_SUCCESS;
900     PUNICODE_STRING TempProcessImageName;
901     _SEH2_VOLATILE PUNICODE_STRING ProcessImageName = NULL;
902     PWCHAR szSrc;
903     BOOLEAN Overflow = FALSE;
904 
905     _SEH2_TRY
906     {
907         /* scan the process list */
908 
909         PSYSTEM_PROCESS_INFORMATION Spi
910             = (PSYSTEM_PROCESS_INFORMATION) Buffer;
911 
912         *ReqSize = sizeof(SYSTEM_PROCESS_INFORMATION);
913 
914         /* Check for overflow */
915         if (Size < sizeof(SYSTEM_PROCESS_INFORMATION))
916         {
917             Overflow = TRUE;
918         }
919 
920         /* Zero user's buffer */
921         if (!Overflow) RtlZeroMemory(Spi, Size);
922 
923         SystemProcess = PsIdleProcess;
924         Process = SystemProcess;
925         Current = (PUCHAR) Spi;
926 
927         do
928         {
929             SpiCurrent = (PSYSTEM_PROCESS_INFORMATION) Current;
930 
931             /* Lock the Process */
932             KeEnterCriticalRegion();
933             ExAcquirePushLockShared(&Process->ProcessLock);
934 
935             if ((Process->ProcessExiting) &&
936                 (Process->Pcb.Header.SignalState) &&
937                 !(Process->ActiveThreads) &&
938                 (IsListEmpty(&Process->Pcb.ThreadListHead)))
939             {
940                 DPRINT1("Process %p (%s:%p) is a zombie\n",
941                         Process, Process->ImageFileName, Process->UniqueProcessId);
942                 CurrentSize = 0;
943                 ImageNameMaximumLength = 0;
944 
945                 /* Unlock the Process */
946                 ExReleasePushLockShared(&Process->ProcessLock);
947                 KeLeaveCriticalRegion();
948                 goto Skip;
949             }
950 
951             ThreadsCount = 0;
952             CurrentEntry = Process->Pcb.ThreadListHead.Flink;
953             while (CurrentEntry != &Process->Pcb.ThreadListHead)
954             {
955                 ThreadsCount++;
956                 CurrentEntry = CurrentEntry->Flink;
957             }
958 
959             // size of the structure for every process
960             CurrentSize = sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_THREAD_INFORMATION) * ThreadsCount;
961             ImageNameLength = 0;
962             Status = SeLocateProcessImageName(Process, &TempProcessImageName);
963             ProcessImageName = TempProcessImageName;
964             szSrc = NULL;
965             if (NT_SUCCESS(Status) && (ProcessImageName->Length > 0))
966             {
967               szSrc = (PWCHAR)((PCHAR)ProcessImageName->Buffer + ProcessImageName->Length);
968               /* Loop the file name*/
969               while (szSrc > ProcessImageName->Buffer)
970               {
971                 /* Make sure this isn't a backslash */
972                 if (*--szSrc == OBJ_NAME_PATH_SEPARATOR)
973                 {
974                     szSrc++;
975                     break;
976                 }
977                 else
978                 {
979                     ImageNameLength += sizeof(WCHAR);
980                 }
981               }
982             }
983             if (!ImageNameLength && Process != PsIdleProcess)
984             {
985               ImageNameLength = (USHORT)strlen(Process->ImageFileName) * sizeof(WCHAR);
986             }
987 
988             /* Round up the image name length as NT does */
989             if (ImageNameLength > 0)
990                 ImageNameMaximumLength = ROUND_UP(ImageNameLength + sizeof(WCHAR), 8);
991             else
992                 ImageNameMaximumLength = 0;
993 
994             TotalSize += CurrentSize + ImageNameMaximumLength;
995 
996             /* Check for overflow */
997             if (TotalSize > Size)
998             {
999                 Overflow = TRUE;
1000             }
1001 
1002             /* Fill system information */
1003             if (!Overflow)
1004             {
1005                 SpiCurrent->NextEntryOffset = CurrentSize + ImageNameMaximumLength; // relative offset to the beginning of the next structure
1006                 SpiCurrent->NumberOfThreads = ThreadsCount;
1007                 SpiCurrent->CreateTime = Process->CreateTime;
1008                 SpiCurrent->ImageName.Length = ImageNameLength;
1009                 SpiCurrent->ImageName.MaximumLength = ImageNameMaximumLength;
1010                 SpiCurrent->ImageName.Buffer = (void*)(Current + CurrentSize);
1011 
1012                 /* Copy name to the end of the struct */
1013                 if(Process != PsIdleProcess)
1014                 {
1015                     if (szSrc)
1016                     {
1017                         RtlCopyMemory(SpiCurrent->ImageName.Buffer, szSrc, SpiCurrent->ImageName.Length);
1018                     }
1019                     else
1020                     {
1021                         RtlInitAnsiString(&ImageName, Process->ImageFileName);
1022                         Status = RtlAnsiStringToUnicodeString(&SpiCurrent->ImageName, &ImageName, FALSE);
1023                         if (!NT_SUCCESS(Status))
1024                         {
1025                             SpiCurrent->ImageName.Length = 0;
1026                         }
1027                     }
1028                 }
1029                 else
1030                 {
1031                     RtlInitUnicodeString(&SpiCurrent->ImageName, NULL);
1032                 }
1033 
1034                 SpiCurrent->BasePriority = Process->Pcb.BasePriority;
1035                 SpiCurrent->UniqueProcessId = Process->UniqueProcessId;
1036                 SpiCurrent->InheritedFromUniqueProcessId = Process->InheritedFromUniqueProcessId;
1037 
1038                 /* PsIdleProcess shares its handle table with PsInitialSystemProcess,
1039                  * so return the handle count for System only, not Idle one. */
1040                 SpiCurrent->HandleCount = (Process == PsIdleProcess) ? 0 : ObGetProcessHandleCount(Process);
1041 
1042                 SpiCurrent->PeakVirtualSize = Process->PeakVirtualSize;
1043                 SpiCurrent->VirtualSize = Process->VirtualSize;
1044                 SpiCurrent->PageFaultCount = Process->Vm.PageFaultCount;
1045                 SpiCurrent->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
1046                 SpiCurrent->WorkingSetSize = Process->Vm.WorkingSetSize;
1047                 SpiCurrent->QuotaPeakPagedPoolUsage = Process->QuotaPeak[PsPagedPool];
1048                 SpiCurrent->QuotaPagedPoolUsage = Process->QuotaUsage[PsPagedPool];
1049                 SpiCurrent->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[PsNonPagedPool];
1050                 SpiCurrent->QuotaNonPagedPoolUsage = Process->QuotaUsage[PsNonPagedPool];
1051                 SpiCurrent->PagefileUsage = Process->QuotaUsage[PsPageFile];
1052                 SpiCurrent->PeakPagefileUsage = Process->QuotaPeak[PsPageFile];
1053                 SpiCurrent->PrivatePageCount = Process->CommitCharge;
1054                 ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(SpiCurrent + 1);
1055 
1056                 CurrentEntry = Process->Pcb.ThreadListHead.Flink;
1057                 while (CurrentEntry != &Process->Pcb.ThreadListHead)
1058                 {
1059                     CurrentThread = CONTAINING_RECORD(CurrentEntry, ETHREAD, Tcb.ThreadListEntry);
1060 
1061                     ThreadInfo->KernelTime.QuadPart = UInt32x32To64(CurrentThread->Tcb.KernelTime, KeMaximumIncrement);
1062                     ThreadInfo->UserTime.QuadPart = UInt32x32To64(CurrentThread->Tcb.UserTime, KeMaximumIncrement);
1063                     ThreadInfo->CreateTime.QuadPart = CurrentThread->CreateTime.QuadPart;
1064                     ThreadInfo->WaitTime = CurrentThread->Tcb.WaitTime;
1065                     ThreadInfo->StartAddress = (PVOID) CurrentThread->StartAddress;
1066                     ThreadInfo->ClientId = CurrentThread->Cid;
1067                     ThreadInfo->Priority = CurrentThread->Tcb.Priority;
1068                     ThreadInfo->BasePriority = CurrentThread->Tcb.BasePriority;
1069                     ThreadInfo->ContextSwitches = CurrentThread->Tcb.ContextSwitches;
1070                     ThreadInfo->ThreadState = CurrentThread->Tcb.State;
1071                     ThreadInfo->WaitReason = CurrentThread->Tcb.WaitReason;
1072 
1073                     ThreadInfo++;
1074                     CurrentEntry = CurrentEntry->Flink;
1075                 }
1076 
1077                 /* Query total user/kernel times of a process */
1078                 TotalKernel = KeQueryRuntimeProcess(&Process->Pcb, &TotalUser);
1079                 SpiCurrent->UserTime.QuadPart = UInt32x32To64(TotalUser, KeMaximumIncrement);
1080                 SpiCurrent->KernelTime.QuadPart = UInt32x32To64(TotalKernel, KeMaximumIncrement);
1081             }
1082 
1083             if (ProcessImageName)
1084             {
1085                 /* Release the memory allocated by SeLocateProcessImageName */
1086                 ExFreePoolWithTag(ProcessImageName, TAG_SEPA);
1087                 ProcessImageName = NULL;
1088             }
1089 
1090             /* Unlock the Process */
1091             ExReleasePushLockShared(&Process->ProcessLock);
1092             KeLeaveCriticalRegion();
1093 
1094             /* Handle idle process entry */
1095 Skip:
1096             if (Process == PsIdleProcess) Process = NULL;
1097 
1098             Process = PsGetNextProcess(Process);
1099             ThreadsCount = 0;
1100             if ((Process == SystemProcess) || (Process == NULL))
1101             {
1102                 if (!Overflow)
1103                     SpiCurrent->NextEntryOffset = 0;
1104                 break;
1105             }
1106             else
1107                 Current += CurrentSize + ImageNameMaximumLength;
1108           }  while ((Process != SystemProcess) && (Process != NULL));
1109 
1110           if(Process != NULL)
1111             ObDereferenceObject(Process);
1112           Status = STATUS_SUCCESS;
1113     }
1114     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1115     {
1116         if(Process != NULL)
1117             ObDereferenceObject(Process);
1118         if (ProcessImageName)
1119         {
1120             /* Release the memory allocated by SeLocateProcessImageName */
1121             ExFreePoolWithTag(ProcessImageName, TAG_SEPA);
1122         }
1123 
1124         Status = _SEH2_GetExceptionCode();
1125     }
1126     _SEH2_END
1127 
1128     if (Overflow)
1129         Status = STATUS_INFO_LENGTH_MISMATCH;
1130 
1131     *ReqSize = TotalSize;
1132     return Status;
1133 }
1134 
1135 /* Class 6 - Call Count Information */
1136 QSI_DEF(SystemCallCountInformation)
1137 {
1138     /* FIXME */
1139     DPRINT1("NtQuerySystemInformation - SystemCallCountInformation not implemented\n");
1140     return STATUS_NOT_IMPLEMENTED;
1141 }
1142 
1143 /* Class 7 - Device Information */
1144 QSI_DEF(SystemDeviceInformation)
1145 {
1146     PSYSTEM_DEVICE_INFORMATION Sdi
1147         = (PSYSTEM_DEVICE_INFORMATION) Buffer;
1148     PCONFIGURATION_INFORMATION ConfigInfo;
1149 
1150     *ReqSize = sizeof(SYSTEM_DEVICE_INFORMATION);
1151 
1152     /* Check user buffer's size */
1153     if (Size < sizeof(SYSTEM_DEVICE_INFORMATION))
1154     {
1155         return STATUS_INFO_LENGTH_MISMATCH;
1156     }
1157 
1158     ConfigInfo = IoGetConfigurationInformation();
1159 
1160     Sdi->NumberOfDisks = ConfigInfo->DiskCount;
1161     Sdi->NumberOfFloppies = ConfigInfo->FloppyCount;
1162     Sdi->NumberOfCdRoms = ConfigInfo->CdRomCount;
1163     Sdi->NumberOfTapes = ConfigInfo->TapeCount;
1164     Sdi->NumberOfSerialPorts = ConfigInfo->SerialCount;
1165     Sdi->NumberOfParallelPorts = ConfigInfo->ParallelCount;
1166 
1167     return STATUS_SUCCESS;
1168 }
1169 
1170 /* Class 8 - Processor Performance Information */
1171 QSI_DEF(SystemProcessorPerformanceInformation)
1172 {
1173     PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION Spi
1174         = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) Buffer;
1175 
1176     LONG i;
1177     ULONG TotalTime;
1178     PKPRCB Prcb;
1179 
1180     *ReqSize = KeNumberProcessors * sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
1181 
1182     /* Check user buffer's size */
1183     if (Size < *ReqSize)
1184     {
1185         return STATUS_INFO_LENGTH_MISMATCH;
1186     }
1187 
1188     for (i = 0; i < KeNumberProcessors; i++)
1189     {
1190         /* Get the PRCB on this processor */
1191         Prcb = KiProcessorBlock[i];
1192 
1193         /* Calculate total user and kernel times */
1194         TotalTime = Prcb->IdleThread->KernelTime + Prcb->IdleThread->UserTime;
1195         Spi->IdleTime.QuadPart = UInt32x32To64(TotalTime, KeMaximumIncrement);
1196         Spi->KernelTime.QuadPart =  UInt32x32To64(Prcb->KernelTime, KeMaximumIncrement);
1197         Spi->UserTime.QuadPart = UInt32x32To64(Prcb->UserTime, KeMaximumIncrement);
1198         Spi->DpcTime.QuadPart = UInt32x32To64(Prcb->DpcTime, KeMaximumIncrement);
1199         Spi->InterruptTime.QuadPart = UInt32x32To64(Prcb->InterruptTime, KeMaximumIncrement);
1200         Spi->InterruptCount = Prcb->InterruptCount;
1201         Spi++;
1202     }
1203 
1204     return STATUS_SUCCESS;
1205 }
1206 
1207 /* Class 9 - Flags Information */
1208 QSI_DEF(SystemFlagsInformation)
1209 {
1210 #if (NTDDI_VERSION >= NTDDI_VISTA)
1211     *ReqSize = sizeof(SYSTEM_FLAGS_INFORMATION);
1212 #endif
1213 
1214     if (sizeof(SYSTEM_FLAGS_INFORMATION) != Size)
1215     {
1216         return STATUS_INFO_LENGTH_MISMATCH;
1217     }
1218 
1219     ((PSYSTEM_FLAGS_INFORMATION) Buffer)->Flags = NtGlobalFlag;
1220 #if (NTDDI_VERSION < NTDDI_VISTA)
1221     *ReqSize = sizeof(SYSTEM_FLAGS_INFORMATION);
1222 #endif
1223 
1224     return STATUS_SUCCESS;
1225 }
1226 
1227 SSI_DEF(SystemFlagsInformation)
1228 {
1229     if (sizeof(SYSTEM_FLAGS_INFORMATION) != Size)
1230     {
1231         return STATUS_INFO_LENGTH_MISMATCH;
1232     }
1233 
1234     if (!SeSinglePrivilegeCheck(SeDebugPrivilege, ExGetPreviousMode()))
1235     {
1236 #if (NTDDI_VERSION < NTDDI_WIN7)
1237         return STATUS_ACCESS_VIOLATION;
1238 #else
1239         return STATUS_ACCESS_DENIED;
1240 #endif
1241     }
1242 
1243     NtGlobalFlag = ((PSYSTEM_FLAGS_INFORMATION) Buffer)->Flags;
1244     return STATUS_SUCCESS;
1245 }
1246 
1247 /* Class 10 - Call Time Information */
1248 QSI_DEF(SystemCallTimeInformation)
1249 {
1250     /* FIXME */
1251     DPRINT1("NtQuerySystemInformation - SystemCallTimeInformation not implemented\n");
1252     return STATUS_NOT_IMPLEMENTED;
1253 }
1254 
1255 /* Class 11 - Module Information */
1256 QSI_DEF(SystemModuleInformation)
1257 {
1258     NTSTATUS Status;
1259 
1260     /* Acquire system module list lock */
1261     KeEnterCriticalRegion();
1262     ExAcquireResourceExclusiveLite(&PsLoadedModuleResource, TRUE);
1263 
1264     /* Call the generic handler with the system module list */
1265     Status = ExpQueryModuleInformation(&PsLoadedModuleList,
1266                                        &MmLoadedUserImageList,
1267                                        (PRTL_PROCESS_MODULES)Buffer,
1268                                        Size,
1269                                        ReqSize);
1270 
1271     /* Release list lock and return status */
1272     ExReleaseResourceLite(&PsLoadedModuleResource);
1273     KeLeaveCriticalRegion();
1274     return Status;
1275 }
1276 
1277 /* Class 12 - Locks Information */
1278 QSI_DEF(SystemLocksInformation)
1279 {
1280     /* FIXME */
1281     DPRINT1("NtQuerySystemInformation - SystemLocksInformation not implemented\n");
1282     return STATUS_NOT_IMPLEMENTED;
1283 }
1284 
1285 /* Class 13 - Stack Trace Information */
1286 QSI_DEF(SystemStackTraceInformation)
1287 {
1288     /* FIXME */
1289     DPRINT1("NtQuerySystemInformation - SystemStackTraceInformation not implemented\n");
1290     return STATUS_NOT_IMPLEMENTED;
1291 }
1292 
1293 /* Class 14 - Paged Pool Information */
1294 QSI_DEF(SystemPagedPoolInformation)
1295 {
1296     /* FIXME */
1297     DPRINT1("NtQuerySystemInformation - SystemPagedPoolInformation not implemented\n");
1298     return STATUS_NOT_IMPLEMENTED;
1299 }
1300 
1301 /* Class 15 - Non Paged Pool Information */
1302 QSI_DEF(SystemNonPagedPoolInformation)
1303 {
1304     /* FIXME */
1305     DPRINT1("NtQuerySystemInformation - SystemNonPagedPoolInformation not implemented\n");
1306     return STATUS_NOT_IMPLEMENTED;
1307 }
1308 
1309 /* Class 16 - Handle Information */
1310 QSI_DEF(SystemHandleInformation)
1311 {
1312     PSYSTEM_HANDLE_INFORMATION HandleInformation;
1313     PLIST_ENTRY NextTableEntry;
1314     PHANDLE_TABLE HandleTable;
1315     PHANDLE_TABLE_ENTRY HandleTableEntry;
1316     EXHANDLE Handle;
1317     ULONG Index = 0;
1318     NTSTATUS Status;
1319     PMDL Mdl;
1320     PAGED_CODE();
1321 
1322     DPRINT("NtQuerySystemInformation - SystemHandleInformation\n");
1323 
1324     /* Set initial required buffer size */
1325     *ReqSize = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION, Handles);
1326 
1327     /* Check user's buffer size */
1328     if (Size < *ReqSize)
1329     {
1330         return STATUS_INFO_LENGTH_MISMATCH;
1331     }
1332 
1333     /* We need to lock down the memory */
1334     Status = ExLockUserBuffer(Buffer,
1335                               Size,
1336                               ExGetPreviousMode(),
1337                               IoWriteAccess,
1338                               (PVOID*)&HandleInformation,
1339                               &Mdl);
1340     if (!NT_SUCCESS(Status))
1341     {
1342         DPRINT1("Failed to lock the user buffer: 0x%lx\n", Status);
1343         return Status;
1344     }
1345 
1346     /* Reset of count of handles */
1347     HandleInformation->NumberOfHandles = 0;
1348 
1349     /* Enter a critical region */
1350     KeEnterCriticalRegion();
1351 
1352     /* Acquire the handle table lock */
1353     ExAcquirePushLockShared(&HandleTableListLock);
1354 
1355     /* Enumerate all system handles */
1356     for (NextTableEntry = HandleTableListHead.Flink;
1357          NextTableEntry != &HandleTableListHead;
1358          NextTableEntry = NextTableEntry->Flink)
1359     {
1360         /* Get current handle table */
1361         HandleTable = CONTAINING_RECORD(NextTableEntry, HANDLE_TABLE, HandleTableList);
1362 
1363         /* Set the initial value and loop the entries */
1364         Handle.Value = 0;
1365         while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle)))
1366         {
1367             /* Validate the entry */
1368             if ((HandleTableEntry->Object) &&
1369                 (HandleTableEntry->NextFreeTableEntry != -2))
1370             {
1371                 /* Increase of count of handles */
1372                 ++HandleInformation->NumberOfHandles;
1373 
1374                 /* Lock the entry */
1375                 if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
1376                 {
1377                     /* Increase required buffer size */
1378                     *ReqSize += sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO);
1379 
1380                     /* Check user's buffer size */
1381                     if (*ReqSize > Size)
1382                     {
1383                         Status = STATUS_INFO_LENGTH_MISMATCH;
1384                     }
1385                     else
1386                     {
1387                         POBJECT_HEADER ObjectHeader = ObpGetHandleObject(HandleTableEntry);
1388 
1389                         /* Filling handle information */
1390                         HandleInformation->Handles[Index].UniqueProcessId =
1391                             (USHORT)(ULONG_PTR) HandleTable->UniqueProcessId;
1392 
1393                         HandleInformation->Handles[Index].CreatorBackTraceIndex = 0;
1394 
1395 #if 0 /* FIXME!!! Type field corrupted */
1396                         HandleInformation->Handles[Index].ObjectTypeIndex =
1397                             (UCHAR) ObjectHeader->Type->Index;
1398 #else
1399                         HandleInformation->Handles[Index].ObjectTypeIndex = 0;
1400 #endif
1401 
1402                         HandleInformation->Handles[Index].HandleAttributes =
1403                             HandleTableEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
1404 
1405                         HandleInformation->Handles[Index].HandleValue =
1406                             (USHORT)(ULONG_PTR) Handle.GenericHandleOverlay;
1407 
1408                         HandleInformation->Handles[Index].Object = &ObjectHeader->Body;
1409 
1410                         HandleInformation->Handles[Index].GrantedAccess =
1411                             HandleTableEntry->GrantedAccess;
1412 
1413                         ++Index;
1414                     }
1415 
1416                     /* Unlock it */
1417                     ExUnlockHandleTableEntry(HandleTable, HandleTableEntry);
1418                 }
1419             }
1420 
1421             /* Go to the next entry */
1422             Handle.Value += sizeof(HANDLE);
1423         }
1424     }
1425 
1426     /* Release the lock */
1427     ExReleasePushLockShared(&HandleTableListLock);
1428 
1429     /* Leave the critical region */
1430     KeLeaveCriticalRegion();
1431 
1432     /* Release the locked user buffer */
1433     ExUnlockUserBuffer(Mdl);
1434 
1435     return Status;
1436 }
1437 
1438 /* Class 17 -  Information */
1439 QSI_DEF(SystemObjectInformation)
1440 {
1441     /* FIXME */
1442     DPRINT1("NtQuerySystemInformation - SystemObjectInformation not implemented\n");
1443     return STATUS_NOT_IMPLEMENTED;
1444 }
1445 
1446 /* Class 18 -  Information */
1447 QSI_DEF(SystemPageFileInformation)
1448 {
1449     UNICODE_STRING FileName; /* FIXME */
1450     SYSTEM_PAGEFILE_INFORMATION *Spfi = (SYSTEM_PAGEFILE_INFORMATION *) Buffer;
1451 
1452     if (Size < sizeof(SYSTEM_PAGEFILE_INFORMATION))
1453     {
1454         * ReqSize = sizeof(SYSTEM_PAGEFILE_INFORMATION);
1455         return STATUS_INFO_LENGTH_MISMATCH;
1456     }
1457 
1458     RtlInitUnicodeString(&FileName, NULL); /* FIXME */
1459 
1460     /* FIXME */
1461     Spfi->NextEntryOffset = 0;
1462 
1463     Spfi->TotalSize = MiFreeSwapPages + MiUsedSwapPages;
1464     Spfi->TotalInUse = MiUsedSwapPages;
1465     Spfi->PeakUsage = MiUsedSwapPages; /* FIXME */
1466     Spfi->PageFileName = FileName;
1467     return STATUS_SUCCESS;
1468 }
1469 
1470 /* Class 19 - Vdm Instemul Information */
1471 QSI_DEF(SystemVdmInstemulInformation)
1472 {
1473     /* FIXME */
1474     DPRINT1("NtQuerySystemInformation - SystemVdmInstemulInformation not implemented\n");
1475     return STATUS_NOT_IMPLEMENTED;
1476 }
1477 
1478 /* Class 20 - Vdm Bop Information */
1479 QSI_DEF(SystemVdmBopInformation)
1480 {
1481     /* FIXME */
1482     DPRINT1("NtQuerySystemInformation - SystemVdmBopInformation not implemented\n");
1483     return STATUS_NOT_IMPLEMENTED;
1484 }
1485 
1486 /* Class 21 - File Cache Information */
1487 QSI_DEF(SystemFileCacheInformation)
1488 {
1489     SYSTEM_FILECACHE_INFORMATION *Sci = (SYSTEM_FILECACHE_INFORMATION *) Buffer;
1490 
1491     *ReqSize = sizeof(SYSTEM_FILECACHE_INFORMATION);
1492 
1493     if (Size < *ReqSize)
1494     {
1495         return STATUS_INFO_LENGTH_MISMATCH;
1496     }
1497 
1498     RtlZeroMemory(Sci, sizeof(SYSTEM_FILECACHE_INFORMATION));
1499 
1500     /* Return the Byte size not the page size. */
1501     Sci->CurrentSize = MiMemoryConsumers[MC_USER].PagesUsed; /* FIXME */
1502     Sci->PeakSize = MiMemoryConsumers[MC_USER].PagesUsed; /* FIXME */
1503     /* Taskmgr multiplies this one by page size right away */
1504     Sci->CurrentSizeIncludingTransitionInPages = MiMemoryConsumers[MC_USER].PagesUsed; /* FIXME: Should be */
1505     /* system working set and standby pages. */
1506     Sci->PageFaultCount = 0; /* FIXME */
1507     Sci->MinimumWorkingSet = 0; /* FIXME */
1508     Sci->MaximumWorkingSet = 0; /* FIXME */
1509 
1510     return STATUS_SUCCESS;
1511 }
1512 
1513 SSI_DEF(SystemFileCacheInformation)
1514 {
1515     if (Size < sizeof(SYSTEM_FILECACHE_INFORMATION))
1516     {
1517         return STATUS_INFO_LENGTH_MISMATCH;
1518     }
1519     /* FIXME */
1520     DPRINT1("NtSetSystemInformation - SystemFileCacheInformation not implemented\n");
1521     return STATUS_NOT_IMPLEMENTED;
1522 }
1523 
1524 /* Class 22 - Pool Tag Information */
1525 QSI_DEF(SystemPoolTagInformation)
1526 {
1527     if (Size < sizeof(SYSTEM_POOLTAG_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
1528     return ExGetPoolTagInfo(Buffer, Size, ReqSize);
1529 }
1530 
1531 /* Class 23 - Interrupt Information for all processors */
1532 QSI_DEF(SystemInterruptInformation)
1533 {
1534     PKPRCB Prcb;
1535     LONG i;
1536     ULONG ti;
1537     PSYSTEM_INTERRUPT_INFORMATION sii = (PSYSTEM_INTERRUPT_INFORMATION)Buffer;
1538 
1539     if(Size < KeNumberProcessors * sizeof(SYSTEM_INTERRUPT_INFORMATION))
1540     {
1541         return STATUS_INFO_LENGTH_MISMATCH;
1542     }
1543 
1544     ti = KeQueryTimeIncrement();
1545 
1546     for (i = 0; i < KeNumberProcessors; i++)
1547     {
1548         Prcb = KiProcessorBlock[i];
1549         sii->ContextSwitches = KeGetContextSwitches(Prcb);
1550         sii->DpcCount = Prcb->DpcData[0].DpcCount;
1551         sii->DpcRate = Prcb->DpcRequestRate;
1552         sii->TimeIncrement = ti;
1553         sii->DpcBypassCount = 0;
1554         sii->ApcBypassCount = 0;
1555         sii++;
1556     }
1557 
1558     return STATUS_SUCCESS;
1559 }
1560 
1561 /* Class 24 - DPC Behaviour Information */
1562 QSI_DEF(SystemDpcBehaviourInformation)
1563 {
1564     PSYSTEM_DPC_BEHAVIOR_INFORMATION sdbi = (PSYSTEM_DPC_BEHAVIOR_INFORMATION)Buffer;
1565 
1566     if (Size < sizeof(SYSTEM_DPC_BEHAVIOR_INFORMATION))
1567     {
1568         return STATUS_INFO_LENGTH_MISMATCH;
1569     }
1570 
1571     sdbi->DpcQueueDepth = KiMaximumDpcQueueDepth;
1572     sdbi->MinimumDpcRate = KiMinimumDpcRate;
1573     sdbi->AdjustDpcThreshold = KiAdjustDpcThreshold;
1574     sdbi->IdealDpcRate = KiIdealDpcRate;
1575 
1576     return STATUS_SUCCESS;
1577 }
1578 
1579 SSI_DEF(SystemDpcBehaviourInformation)
1580 {
1581     /* FIXME */
1582     DPRINT1("NtSetSystemInformation - SystemDpcBehaviourInformation not implemented\n");
1583     return STATUS_NOT_IMPLEMENTED;
1584 }
1585 
1586 /* Class 25 - Full Memory Information */
1587 QSI_DEF(SystemFullMemoryInformation)
1588 {
1589     PULONG Spi = (PULONG) Buffer;
1590 
1591     PEPROCESS TheIdleProcess;
1592 
1593     *ReqSize = sizeof(ULONG);
1594 
1595     if (sizeof(ULONG) != Size)
1596     {
1597         return STATUS_INFO_LENGTH_MISMATCH;
1598     }
1599 
1600     DPRINT("SystemFullMemoryInformation\n");
1601 
1602     TheIdleProcess = PsIdleProcess;
1603 
1604     DPRINT("PID: %p, KernelTime: %u PFFree: %lu PFUsed: %lu\n",
1605            TheIdleProcess->UniqueProcessId,
1606            TheIdleProcess->Pcb.KernelTime,
1607            MiFreeSwapPages,
1608            MiUsedSwapPages);
1609 
1610     *Spi = MiMemoryConsumers[MC_USER].PagesUsed;
1611 
1612     return STATUS_SUCCESS;
1613 }
1614 
1615 /* Class 26 - Load Image */
1616 SSI_DEF(SystemLoadGdiDriverInformation)
1617 {
1618     PSYSTEM_GDI_DRIVER_INFORMATION DriverInfo = (PVOID)Buffer;
1619     UNICODE_STRING ImageName;
1620     PVOID ImageBase;
1621     PVOID SectionPointer;
1622     ULONG_PTR EntryPoint;
1623     NTSTATUS Status;
1624     ULONG DirSize;
1625     PIMAGE_NT_HEADERS NtHeader;
1626 
1627     /* Validate size */
1628     if (Size != sizeof(SYSTEM_GDI_DRIVER_INFORMATION))
1629     {
1630         /* Incorrect buffer length, fail */
1631         return STATUS_INFO_LENGTH_MISMATCH;
1632     }
1633 
1634     /* Only kernel mode can call this function */
1635     if (ExGetPreviousMode() != KernelMode) return STATUS_PRIVILEGE_NOT_HELD;
1636 
1637     /* Load the driver */
1638     ImageName = DriverInfo->DriverName;
1639     Status = MmLoadSystemImage(&ImageName,
1640                                NULL,
1641                                NULL,
1642                                0,
1643                                &SectionPointer,
1644                                &ImageBase);
1645     if (!NT_SUCCESS(Status)) return Status;
1646 
1647     /* Return the export pointer */
1648     DriverInfo->ExportSectionPointer =
1649         RtlImageDirectoryEntryToData(ImageBase,
1650                                      TRUE,
1651                                      IMAGE_DIRECTORY_ENTRY_EXPORT,
1652                                      &DirSize);
1653 
1654     /* Get the entrypoint */
1655     NtHeader = RtlImageNtHeader(ImageBase);
1656     EntryPoint = NtHeader->OptionalHeader.AddressOfEntryPoint;
1657     EntryPoint += (ULONG_PTR)ImageBase;
1658 
1659     /* Save other data */
1660     DriverInfo->ImageAddress = ImageBase;
1661     DriverInfo->SectionPointer = SectionPointer;
1662     DriverInfo->EntryPoint = (PVOID)EntryPoint;
1663     DriverInfo->ImageLength = NtHeader->OptionalHeader.SizeOfImage;
1664 
1665     /* All is good */
1666     return STATUS_SUCCESS;
1667 }
1668 
1669 /* Class 27 - Unload Image */
1670 SSI_DEF(SystemUnloadGdiDriverInformation)
1671 {
1672     PVOID *SectionPointer = Buffer;
1673 
1674     /* Validate size */
1675     if (Size != sizeof(PVOID))
1676     {
1677         /* Incorrect length, fail */
1678         return STATUS_INFO_LENGTH_MISMATCH;
1679     }
1680 
1681     /* Only kernel mode can call this function */
1682     if (ExGetPreviousMode() != KernelMode) return STATUS_PRIVILEGE_NOT_HELD;
1683 
1684     /* Unload the image */
1685     MmUnloadSystemImage(*SectionPointer);
1686     return STATUS_SUCCESS;
1687 }
1688 
1689 /* Class 28 - Time Adjustment Information */
1690 QSI_DEF(SystemTimeAdjustmentInformation)
1691 {
1692     PSYSTEM_QUERY_TIME_ADJUST_INFORMATION TimeInfo =
1693         (PSYSTEM_QUERY_TIME_ADJUST_INFORMATION)Buffer;
1694 
1695     /* Check if enough storage was provided */
1696     if (sizeof(SYSTEM_QUERY_TIME_ADJUST_INFORMATION) > Size)
1697     {
1698         * ReqSize = sizeof(SYSTEM_QUERY_TIME_ADJUST_INFORMATION);
1699         return STATUS_INFO_LENGTH_MISMATCH;
1700     }
1701 
1702     /* Give time values to our caller */
1703     TimeInfo->TimeIncrement = KeMaximumIncrement;
1704     TimeInfo->TimeAdjustment = KeTimeAdjustment;
1705     TimeInfo->Enable = !KiTimeAdjustmentEnabled;
1706 
1707     return STATUS_SUCCESS;
1708 }
1709 
1710 SSI_DEF(SystemTimeAdjustmentInformation)
1711 {
1712     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1713     PSYSTEM_SET_TIME_ADJUST_INFORMATION TimeInfo =
1714         (PSYSTEM_SET_TIME_ADJUST_INFORMATION)Buffer;
1715 
1716     /* Check size of a buffer, it must match our expectations */
1717     if (sizeof(SYSTEM_SET_TIME_ADJUST_INFORMATION) != Size)
1718         return STATUS_INFO_LENGTH_MISMATCH;
1719 
1720     /* Check who is calling */
1721     if (PreviousMode != KernelMode)
1722     {
1723         /* Check access rights */
1724         if (!SeSinglePrivilegeCheck(SeSystemtimePrivilege, PreviousMode))
1725         {
1726             return STATUS_PRIVILEGE_NOT_HELD;
1727         }
1728     }
1729 
1730     /* FIXME: behaviour suggests the member be named 'Disable' */
1731     if (TimeInfo->Enable)
1732     {
1733         /* Disable time adjustment and set default value */
1734         KiTimeAdjustmentEnabled = FALSE;
1735         KeTimeAdjustment = KeMaximumIncrement;
1736     }
1737     else
1738     {
1739         /* Check if a valid time adjustment value is given */
1740         if (TimeInfo->TimeAdjustment == 0) return STATUS_INVALID_PARAMETER_2;
1741 
1742         /* Enable time adjustment and set the adjustment value */
1743         KiTimeAdjustmentEnabled = TRUE;
1744         KeTimeAdjustment = TimeInfo->TimeAdjustment;
1745     }
1746 
1747     return STATUS_SUCCESS;
1748 }
1749 
1750 /* Class 29 - Summary Memory Information */
1751 QSI_DEF(SystemSummaryMemoryInformation)
1752 {
1753     /* FIXME */
1754     DPRINT1("NtQuerySystemInformation - SystemSummaryMemoryInformation not implemented\n");
1755     return STATUS_NOT_IMPLEMENTED;
1756 }
1757 
1758 /* Class 30 - Next Event Id Information */
1759 QSI_DEF(SystemNextEventIdInformation)
1760 {
1761     /* FIXME */
1762     DPRINT1("NtQuerySystemInformation - SystemNextEventIdInformation not implemented\n");
1763     return STATUS_NOT_IMPLEMENTED;
1764 }
1765 
1766 /* Class 31 */
1767 QSI_DEF(SystemPerformanceTraceInformation)
1768 {
1769     /* FIXME */
1770     DPRINT1("NtQuerySystemInformation - SystemPerformanceTraceInformation not implemented\n");
1771     return STATUS_NOT_IMPLEMENTED;
1772 }
1773 
1774 /* Class 32 - Crash Dump Information */
1775 QSI_DEF(SystemCrashDumpInformation)
1776 {
1777     /* FIXME */
1778     DPRINT1("NtQuerySystemInformation - SystemCrashDumpInformation not implemented\n");
1779     return STATUS_NOT_IMPLEMENTED;
1780 }
1781 
1782 /* Class 33 - Exception Information */
1783 QSI_DEF(SystemExceptionInformation)
1784 {
1785     PSYSTEM_EXCEPTION_INFORMATION ExceptionInformation =
1786         (PSYSTEM_EXCEPTION_INFORMATION)Buffer;
1787     PKPRCB Prcb;
1788     ULONG AlignmentFixupCount = 0, ExceptionDispatchCount = 0;
1789     ULONG FloatingEmulationCount = 0, ByteWordEmulationCount = 0;
1790     CHAR i;
1791 
1792     /* Check size of a buffer, it must match our expectations */
1793     if (sizeof(SYSTEM_EXCEPTION_INFORMATION) != Size)
1794         return STATUS_INFO_LENGTH_MISMATCH;
1795 
1796     /* Sum up exception count information from all processors */
1797     for (i = 0; i < KeNumberProcessors; i++)
1798     {
1799         Prcb = KiProcessorBlock[i];
1800         if (Prcb)
1801         {
1802             AlignmentFixupCount += Prcb->KeAlignmentFixupCount;
1803             ExceptionDispatchCount += Prcb->KeExceptionDispatchCount;
1804 #ifndef _M_ARM
1805             FloatingEmulationCount += Prcb->KeFloatingEmulationCount;
1806 #endif // _M_ARM
1807         }
1808     }
1809 
1810     /* Save information in user's buffer */
1811     ExceptionInformation->AlignmentFixupCount = AlignmentFixupCount;
1812     ExceptionInformation->ExceptionDispatchCount = ExceptionDispatchCount;
1813     ExceptionInformation->FloatingEmulationCount = FloatingEmulationCount;
1814     ExceptionInformation->ByteWordEmulationCount = ByteWordEmulationCount;
1815 
1816     return STATUS_SUCCESS;
1817 }
1818 
1819 /* Class 34 - Crash Dump State Information */
1820 QSI_DEF(SystemCrashDumpStateInformation)
1821 {
1822     /* FIXME */
1823     DPRINT1("NtQuerySystemInformation - SystemCrashDumpStateInformation not implemented\n");
1824     return STATUS_NOT_IMPLEMENTED;
1825 }
1826 
1827 /* Class 35 - Kernel Debugger Information */
1828 QSI_DEF(SystemKernelDebuggerInformation)
1829 {
1830     PSYSTEM_KERNEL_DEBUGGER_INFORMATION skdi = (PSYSTEM_KERNEL_DEBUGGER_INFORMATION) Buffer;
1831 
1832 #if (NTDDI_VERSION >= NTDDI_VISTA)
1833     *ReqSize = sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION);
1834 #endif
1835 
1836     if (Size < sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION))
1837     {
1838         return STATUS_INFO_LENGTH_MISMATCH;
1839     }
1840 
1841     skdi->KernelDebuggerEnabled = KD_DEBUGGER_ENABLED;
1842     skdi->KernelDebuggerNotPresent = KD_DEBUGGER_NOT_PRESENT;
1843 
1844 #if (NTDDI_VERSION < NTDDI_VISTA)
1845     *ReqSize = sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION);
1846 #endif
1847 
1848     return STATUS_SUCCESS;
1849 }
1850 
1851 /* Class 36 - Context Switch Information */
1852 QSI_DEF(SystemContextSwitchInformation)
1853 {
1854     PSYSTEM_CONTEXT_SWITCH_INFORMATION ContextSwitchInformation =
1855         (PSYSTEM_CONTEXT_SWITCH_INFORMATION)Buffer;
1856     ULONG ContextSwitches;
1857     PKPRCB Prcb;
1858     CHAR i;
1859 
1860     /* Check size of a buffer, it must match our expectations */
1861     if (sizeof(SYSTEM_CONTEXT_SWITCH_INFORMATION) != Size)
1862         return STATUS_INFO_LENGTH_MISMATCH;
1863 
1864     /* Calculate total value of context switches across all processors */
1865     ContextSwitches = 0;
1866     for (i = 0; i < KeNumberProcessors; i ++)
1867     {
1868         Prcb = KiProcessorBlock[i];
1869         if (Prcb)
1870         {
1871             ContextSwitches += KeGetContextSwitches(Prcb);
1872         }
1873     }
1874 
1875     ContextSwitchInformation->ContextSwitches = ContextSwitches;
1876 
1877     /* FIXME */
1878     ContextSwitchInformation->FindAny = 0;
1879     ContextSwitchInformation->FindLast = 0;
1880     ContextSwitchInformation->FindIdeal = 0;
1881     ContextSwitchInformation->IdleAny = 0;
1882     ContextSwitchInformation->IdleCurrent = 0;
1883     ContextSwitchInformation->IdleLast = 0;
1884     ContextSwitchInformation->IdleIdeal = 0;
1885     ContextSwitchInformation->PreemptAny = 0;
1886     ContextSwitchInformation->PreemptCurrent = 0;
1887     ContextSwitchInformation->PreemptLast = 0;
1888     ContextSwitchInformation->SwitchToIdle = 0;
1889 
1890     return STATUS_SUCCESS;
1891 }
1892 
1893 /* Class 37 - Registry Quota Information */
1894 QSI_DEF(SystemRegistryQuotaInformation)
1895 {
1896     PSYSTEM_REGISTRY_QUOTA_INFORMATION srqi = (PSYSTEM_REGISTRY_QUOTA_INFORMATION) Buffer;
1897 
1898     *ReqSize = sizeof(SYSTEM_REGISTRY_QUOTA_INFORMATION);
1899     if (Size < sizeof(SYSTEM_REGISTRY_QUOTA_INFORMATION))
1900     {
1901         return STATUS_INFO_LENGTH_MISMATCH;
1902     }
1903 
1904     DPRINT1("Faking max registry size of 32 MB\n");
1905     srqi->RegistryQuotaAllowed = 0x2000000;
1906     srqi->RegistryQuotaUsed = 0x200000;
1907     srqi->PagedPoolSize = 0x200000;
1908 
1909     return STATUS_SUCCESS;
1910 }
1911 
1912 SSI_DEF(SystemRegistryQuotaInformation)
1913 {
1914     /* FIXME */
1915     DPRINT1("NtSetSystemInformation - SystemRegistryQuotaInformation not implemented\n");
1916     return STATUS_NOT_IMPLEMENTED;
1917 }
1918 
1919 /* Class 38 - Load And Call Image */
1920 SSI_DEF(SystemExtendServiceTableInformation)
1921 {
1922     UNICODE_STRING ImageName;
1923     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1924     PLDR_DATA_TABLE_ENTRY ModuleObject;
1925     NTSTATUS Status;
1926     PIMAGE_NT_HEADERS NtHeader;
1927     DRIVER_OBJECT Win32k;
1928     PDRIVER_INITIALIZE DriverInit;
1929     PVOID ImageBase;
1930     ULONG_PTR EntryPoint;
1931 
1932     /* Validate the size */
1933     if (Size != sizeof(UNICODE_STRING)) return STATUS_INFO_LENGTH_MISMATCH;
1934 
1935     /* Check who is calling */
1936     if (PreviousMode != KernelMode)
1937     {
1938         static const UNICODE_STRING Win32kName =
1939             RTL_CONSTANT_STRING(L"\\SystemRoot\\System32\\win32k.sys");
1940 
1941         /* Make sure we can load drivers */
1942         if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, UserMode))
1943         {
1944             /* FIXME: We can't, fail */
1945             return STATUS_PRIVILEGE_NOT_HELD;
1946         }
1947 
1948         _SEH2_TRY
1949         {
1950             /* Probe and copy the unicode string */
1951             ProbeForRead(Buffer, sizeof(ImageName), 1);
1952             ImageName = *(PUNICODE_STRING)Buffer;
1953 
1954             /* Probe the string buffer */
1955             ProbeForRead(ImageName.Buffer, ImageName.Length, sizeof(WCHAR));
1956 
1957             /* Check if we have the correct name (nothing else is allowed!) */
1958             if (!RtlEqualUnicodeString(&ImageName, &Win32kName, FALSE))
1959             {
1960                 _SEH2_YIELD(return STATUS_PRIVILEGE_NOT_HELD);
1961             }
1962         }
1963         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1964         {
1965             _SEH2_YIELD(return _SEH2_GetExceptionCode());
1966         }
1967         _SEH2_END;
1968 
1969         /* Recursively call the function, so that we are from kernel mode */
1970         return ZwSetSystemInformation(SystemExtendServiceTableInformation,
1971                                       (PVOID)&Win32kName,
1972                                       sizeof(Win32kName));
1973     }
1974 
1975     /* Load the image */
1976     Status = MmLoadSystemImage((PUNICODE_STRING)Buffer,
1977                                NULL,
1978                                NULL,
1979                                0,
1980                                (PVOID)&ModuleObject,
1981                                &ImageBase);
1982 
1983     if (!NT_SUCCESS(Status)) return Status;
1984 
1985     /* Get the headers */
1986     NtHeader = RtlImageNtHeader(ImageBase);
1987     if (!NtHeader)
1988     {
1989         /* Fail */
1990         MmUnloadSystemImage(ModuleObject);
1991         return STATUS_INVALID_IMAGE_FORMAT;
1992     }
1993 
1994     /* Get the entrypoint */
1995     EntryPoint = NtHeader->OptionalHeader.AddressOfEntryPoint;
1996     EntryPoint += (ULONG_PTR)ImageBase;
1997     DriverInit = (PDRIVER_INITIALIZE)EntryPoint;
1998 
1999     /* Create a dummy device */
2000     RtlZeroMemory(&Win32k, sizeof(Win32k));
2001     ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
2002     Win32k.DriverStart = ImageBase;
2003 
2004     /* Call it */
2005     Status = (DriverInit)(&Win32k, NULL);
2006     ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
2007 
2008     /* Unload if we failed */
2009     if (!NT_SUCCESS(Status)) MmUnloadSystemImage(ModuleObject);
2010     return Status;
2011 }
2012 
2013 /* Class 39 - Priority Separation */
2014 SSI_DEF(SystemPrioritySeperation)
2015 {
2016     /* Check if the size is correct */
2017     if (Size != sizeof(ULONG))
2018     {
2019         return STATUS_INFO_LENGTH_MISMATCH;
2020     }
2021 
2022     /* We need the TCB privilege */
2023     if (!SeSinglePrivilegeCheck(SeTcbPrivilege, ExGetPreviousMode()))
2024     {
2025         return STATUS_PRIVILEGE_NOT_HELD;
2026     }
2027 
2028     /* Modify the quantum table */
2029     PsChangeQuantumTable(TRUE, *(PULONG)Buffer);
2030 
2031     return STATUS_SUCCESS;
2032 }
2033 
2034 /* Class 40 */
2035 QSI_DEF(SystemVerifierAddDriverInformation)
2036 {
2037     /* FIXME */
2038     DPRINT1("NtQuerySystemInformation - SystemVerifierAddDriverInformation not implemented\n");
2039     return STATUS_NOT_IMPLEMENTED;
2040 }
2041 
2042 /* Class 41 */
2043 QSI_DEF(SystemVerifierRemoveDriverInformation)
2044 {
2045     /* FIXME */
2046     DPRINT1("NtQuerySystemInformation - SystemVerifierRemoveDriverInformation not implemented\n");
2047     return STATUS_NOT_IMPLEMENTED;
2048 }
2049 
2050 /* Class 42 - Power Information */
2051 QSI_DEF(SystemProcessorIdleInformation)
2052 {
2053     *ReqSize = sizeof(PROCESSOR_POWER_INFORMATION) * KeNumberProcessors;
2054 
2055     if (sizeof(PROCESSOR_POWER_INFORMATION) * KeNumberProcessors > Size)
2056     {
2057         return STATUS_INFO_LENGTH_MISMATCH;
2058     }
2059 
2060     /* FIXME */
2061     DPRINT1("NtQuerySystemInformation - SystemPowerInformation not implemented\n");
2062     return STATUS_NOT_IMPLEMENTED;
2063 }
2064 
2065 /* Class 43 */
2066 QSI_DEF(SystemLegacyDriverInformation)
2067 {
2068     /* FIXME */
2069     DPRINT1("NtQuerySystemInformation - SystemLegacyDriverInformation not implemented\n");
2070     return STATUS_NOT_IMPLEMENTED;
2071 }
2072 
2073 /* Class 44 - Current Time Zone Information */
2074 QSI_DEF(SystemCurrentTimeZoneInformation)
2075 {
2076     *ReqSize = sizeof(RTL_TIME_ZONE_INFORMATION);
2077 
2078     if (sizeof(RTL_TIME_ZONE_INFORMATION) != Size)
2079     {
2080         return STATUS_INFO_LENGTH_MISMATCH;
2081     }
2082 
2083     /* Copy the time zone information struct */
2084     memcpy(Buffer,
2085            &ExpTimeZoneInfo,
2086            sizeof(RTL_TIME_ZONE_INFORMATION));
2087 
2088     return STATUS_SUCCESS;
2089 }
2090 
2091 SSI_DEF(SystemCurrentTimeZoneInformation)
2092 {
2093     /* Check user buffer's size */
2094     if (Size < sizeof(RTL_TIME_ZONE_INFORMATION))
2095     {
2096         return STATUS_INFO_LENGTH_MISMATCH;
2097     }
2098 
2099     return ExpSetTimeZoneInformation((PRTL_TIME_ZONE_INFORMATION)Buffer);
2100 }
2101 
2102 static
2103 VOID
2104 ExpCopyLookasideInformation(
2105     PSYSTEM_LOOKASIDE_INFORMATION *InfoPointer,
2106     PULONG RemainingPointer,
2107     PLIST_ENTRY ListHead,
2108     BOOLEAN ListUsesMisses)
2109 
2110 {
2111     PSYSTEM_LOOKASIDE_INFORMATION Info;
2112     PGENERAL_LOOKASIDE LookasideList;
2113     PLIST_ENTRY ListEntry;
2114     ULONG Remaining;
2115 
2116     /* Get info pointer and remaining count of free array element */
2117     Info = *InfoPointer;
2118     Remaining = *RemainingPointer;
2119 
2120     /* Loop as long as we have lookaside lists and free array elements */
2121     for (ListEntry = ListHead->Flink;
2122          (ListEntry != ListHead) && (Remaining > 0);
2123          ListEntry = ListEntry->Flink, Remaining--)
2124     {
2125         LookasideList = CONTAINING_RECORD(ListEntry, GENERAL_LOOKASIDE, ListEntry);
2126 
2127         /* Fill the next array element */
2128         Info->CurrentDepth = LookasideList->Depth;
2129         Info->MaximumDepth = LookasideList->MaximumDepth;
2130         Info->TotalAllocates = LookasideList->TotalAllocates;
2131         Info->TotalFrees = LookasideList->TotalFrees;
2132         Info->Type = LookasideList->Type;
2133         Info->Tag = LookasideList->Tag;
2134         Info->Size = LookasideList->Size;
2135 
2136         /* Check how the lists track misses/hits */
2137         if (ListUsesMisses)
2138         {
2139             /* Copy misses */
2140             Info->AllocateMisses = LookasideList->AllocateMisses;
2141             Info->FreeMisses = LookasideList->FreeMisses;
2142         }
2143         else
2144         {
2145             /* Calculate misses */
2146             Info->AllocateMisses = LookasideList->TotalAllocates
2147                                    - LookasideList->AllocateHits;
2148             Info->FreeMisses = LookasideList->TotalFrees
2149                                - LookasideList->FreeHits;
2150         }
2151     }
2152 
2153     /* Return the updated pointer and remaining count */
2154     *InfoPointer = Info;
2155     *RemainingPointer = Remaining;
2156 }
2157 
2158 /* Class 45 - Lookaside Information */
2159 QSI_DEF(SystemLookasideInformation)
2160 {
2161     KPROCESSOR_MODE PreviousMode;
2162     PSYSTEM_LOOKASIDE_INFORMATION Info;
2163     PMDL Mdl;
2164     ULONG MaxCount, Remaining;
2165     KIRQL OldIrql;
2166     NTSTATUS Status;
2167 
2168     /* First we need to lock down the memory, since we are going to access it
2169        at high IRQL */
2170     PreviousMode = ExGetPreviousMode();
2171     Status = ExLockUserBuffer(Buffer,
2172                               Size,
2173                               PreviousMode,
2174                               IoWriteAccess,
2175                               (PVOID*)&Info,
2176                               &Mdl);
2177     if (!NT_SUCCESS(Status))
2178     {
2179         DPRINT1("Failed to lock the user buffer: 0x%lx\n", Status);
2180         return Status;
2181     }
2182 
2183     /* Calculate how many items we can store */
2184     Remaining = MaxCount = Size / sizeof(SYSTEM_LOOKASIDE_INFORMATION);
2185     if (Remaining == 0)
2186     {
2187         goto Leave;
2188     }
2189 
2190     /* Copy info from pool lookaside lists */
2191     ExpCopyLookasideInformation(&Info,
2192                                 &Remaining,
2193                                 &ExPoolLookasideListHead,
2194                                 FALSE);
2195     if (Remaining == 0)
2196     {
2197         goto Leave;
2198     }
2199 
2200     /* Copy info from system lookaside lists */
2201     ExpCopyLookasideInformation(&Info,
2202                                 &Remaining,
2203                                 &ExSystemLookasideListHead,
2204                                 TRUE);
2205     if (Remaining == 0)
2206     {
2207         goto Leave;
2208     }
2209 
2210     /* Acquire spinlock for ExpNonPagedLookasideListHead */
2211     KeAcquireSpinLock(&ExpNonPagedLookasideListLock, &OldIrql);
2212 
2213     /* Copy info from non-paged lookaside lists */
2214     ExpCopyLookasideInformation(&Info,
2215                                 &Remaining,
2216                                 &ExpNonPagedLookasideListHead,
2217                                 TRUE);
2218 
2219     /* Release spinlock for ExpNonPagedLookasideListHead */
2220     KeReleaseSpinLock(&ExpNonPagedLookasideListLock, OldIrql);
2221 
2222     if (Remaining == 0)
2223     {
2224         goto Leave;
2225     }
2226 
2227     /* Acquire spinlock for ExpPagedLookasideListHead */
2228     KeAcquireSpinLock(&ExpPagedLookasideListLock, &OldIrql);
2229 
2230     /* Copy info from paged lookaside lists */
2231     ExpCopyLookasideInformation(&Info,
2232                                 &Remaining,
2233                                 &ExpPagedLookasideListHead,
2234                                 TRUE);
2235 
2236     /* Release spinlock for ExpPagedLookasideListHead */
2237     KeReleaseSpinLock(&ExpPagedLookasideListLock, OldIrql);
2238 
2239 Leave:
2240 
2241     /* Release the locked user buffer */
2242     ExUnlockUserBuffer(Mdl);
2243 
2244     /* Return the size of the actually written data */
2245     *ReqSize = (MaxCount - Remaining) * sizeof(SYSTEM_LOOKASIDE_INFORMATION);
2246     return STATUS_SUCCESS;
2247 }
2248 
2249 /* Class 46 - Set time slip event */
2250 SSI_DEF(SystemTimeSlipNotification)
2251 {
2252     /* FIXME */
2253     DPRINT1("NtSetSystemInformation - SystemTimeSlipNotification not implemented\n");
2254     return STATUS_NOT_IMPLEMENTED;
2255 }
2256 
2257 NTSTATUS
2258 NTAPI
2259 MmSessionCreate(OUT PULONG SessionId);
2260 
2261 NTSTATUS
2262 NTAPI
2263 MmSessionDelete(IN ULONG SessionId);
2264 
2265 /* Class 47 - Create a new session (TSE) */
2266 SSI_DEF(SystemSessionCreate)
2267 {
2268     ULONG SessionId;
2269     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2270     NTSTATUS Status;
2271 
2272     if (Size != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2273 
2274     if (PreviousMode != KernelMode)
2275     {
2276         if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2277         {
2278             return STATUS_PRIVILEGE_NOT_HELD;
2279         }
2280 
2281         ProbeForWriteUlong(Buffer);
2282     }
2283 
2284     Status = MmSessionCreate(&SessionId);
2285     if (NT_SUCCESS(Status)) *(PULONG)Buffer = SessionId;
2286 
2287     return Status;
2288 }
2289 
2290 /* Class 48 - Delete an existing session (TSE) */
2291 SSI_DEF(SystemSessionDetach)
2292 {
2293     ULONG SessionId;
2294     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2295 
2296     if (Size != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2297 
2298     if (PreviousMode != KernelMode)
2299     {
2300         if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2301         {
2302             return STATUS_PRIVILEGE_NOT_HELD;
2303         }
2304     }
2305 
2306     SessionId = *(PULONG)Buffer;
2307 
2308     return MmSessionDelete(SessionId);
2309 }
2310 
2311 /* Class 49 - UNKNOWN */
2312 QSI_DEF(SystemSessionInformation)
2313 {
2314     /* FIXME */
2315     DPRINT1("NtQuerySystemInformation - SystemSessionInformation not implemented\n");
2316     return STATUS_NOT_IMPLEMENTED;
2317 }
2318 
2319 /* Class 50 - System range start address */
2320 QSI_DEF(SystemRangeStartInformation)
2321 {
2322     /* Check user buffer's size */
2323     if (Size != sizeof(ULONG_PTR)) return STATUS_INFO_LENGTH_MISMATCH;
2324 
2325     *(PULONG_PTR)Buffer = (ULONG_PTR)MmSystemRangeStart;
2326 
2327     if (ReqSize) *ReqSize = sizeof(ULONG_PTR);
2328 
2329     return STATUS_SUCCESS;
2330 }
2331 
2332 /* Class 51 - Driver verifier information */
2333 QSI_DEF(SystemVerifierInformation)
2334 {
2335     /* FIXME */
2336     DPRINT1("NtQuerySystemInformation - SystemVerifierInformation not implemented\n");
2337     return STATUS_NOT_IMPLEMENTED;
2338 }
2339 
2340 SSI_DEF(SystemVerifierInformation)
2341 {
2342     /* FIXME */
2343     DPRINT1("NtSetSystemInformation - SystemVerifierInformation not implemented\n");
2344     return STATUS_NOT_IMPLEMENTED;
2345 }
2346 
2347 /* Class 52 */
2348 SSI_DEF(SystemVerifierThunkExtend)
2349 {
2350     /* FIXME */
2351     DPRINT1("NtSetSystemInformation - SystemVerifierThunkExtend not implemented\n");
2352     return STATUS_NOT_IMPLEMENTED;
2353 }
2354 
2355 /* Class 53 - A session's processes */
2356 QSI_DEF(SystemSessionProcessesInformation)
2357 {
2358     /* FIXME */
2359     DPRINT1("NtQuerySystemInformation - SystemSessionProcessInformation not implemented\n");
2360     return STATUS_NOT_IMPLEMENTED;
2361 }
2362 
2363 /* Class 54 - Load & map in system space */
2364 SSI_DEF(SystemLoadGdiDriverInSystemSpaceInformation)
2365 {
2366     /* FIXME */
2367     DPRINT1("NtSetSystemInformation - SystemLoadGdiDriverInSystemSpaceInformation not implemented\n");
2368     return STATUS_NOT_IMPLEMENTED;
2369 }
2370 
2371 /* Class 55 - NUMA processor information */
2372 QSI_DEF(SystemNumaProcessorMap)
2373 {
2374     ULONG MaxEntries, Node;
2375     PSYSTEM_NUMA_INFORMATION NumaInformation = (PSYSTEM_NUMA_INFORMATION)Buffer;
2376 
2377     /* Validate input size */
2378     if (Size < sizeof(ULONG))
2379     {
2380         return STATUS_INFO_LENGTH_MISMATCH;
2381     }
2382 
2383     /* Return highest node */
2384     NumaInformation->HighestNodeNumber = KeNumberNodes - 1;
2385 
2386     /* Compute how much entries we will be able to put in output structure */
2387     MaxEntries = (Size - FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, ActiveProcessorsAffinityMask)) / sizeof(ULONGLONG);
2388     /* Make sure we don't overflow KeNodeBlock */
2389     if (MaxEntries > KeNumberNodes)
2390     {
2391         MaxEntries = KeNumberNodes;
2392     }
2393 
2394     /* If we have entries to write, and room for it */
2395     if (Size >= FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, ActiveProcessorsAffinityMask) &&
2396         MaxEntries != 0)
2397     {
2398         /* Already set size we return */
2399         *ReqSize = FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, ActiveProcessorsAffinityMask) +
2400                    MaxEntries * sizeof(ULONGLONG);
2401 
2402         /* For each node, return processor mask */
2403         for (Node = 0; Node < MaxEntries; ++Node)
2404         {
2405             NumaInformation->ActiveProcessorsAffinityMask[Node] = KeNodeBlock[Node]->ProcessorMask;
2406         }
2407     }
2408     else
2409     {
2410         /* We only returned highest node number */
2411         *ReqSize = sizeof(ULONG);
2412     }
2413 
2414     return STATUS_SUCCESS;
2415 }
2416 
2417 /* Class 56 - Prefetcher information */
2418 QSI_DEF(SystemPrefetcherInformation)
2419 {
2420     /* FIXME */
2421     DPRINT1("NtQuerySystemInformation - SystemPrefetcherInformation not implemented\n");
2422     return STATUS_NOT_IMPLEMENTED;
2423 }
2424 
2425 /* Class 57 - Extended process information */
2426 QSI_DEF(SystemExtendedProcessInformation)
2427 {
2428     /* FIXME */
2429     DPRINT1("NtQuerySystemInformation - SystemExtendedProcessInformation not implemented\n");
2430     return STATUS_NOT_IMPLEMENTED;
2431 }
2432 
2433 /* Class 58 - Recommended shared data alignment */
2434 QSI_DEF(SystemRecommendedSharedDataAlignment)
2435 {
2436     /* FIXME */
2437     DPRINT1("NtQuerySystemInformation - SystemRecommendedSharedDataAlignment not implemented\n");
2438     return STATUS_NOT_IMPLEMENTED;
2439 }
2440 
2441 /* Class 60 - NUMA memory information */
2442 QSI_DEF(SystemNumaAvailableMemory)
2443 {
2444     ULONG MaxEntries, Node;
2445     PSYSTEM_NUMA_INFORMATION NumaInformation = (PSYSTEM_NUMA_INFORMATION)Buffer;
2446 
2447     /* Validate input size */
2448     if (Size < sizeof(ULONG))
2449     {
2450         return STATUS_INFO_LENGTH_MISMATCH;
2451     }
2452 
2453     /* Return highest node */
2454     NumaInformation->HighestNodeNumber = KeNumberNodes - 1;
2455 
2456     /* Compute how much entries we will be able to put in output structure */
2457     MaxEntries = (Size - FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, AvailableMemory)) / sizeof(ULONGLONG);
2458     /* Make sure we don't overflow KeNodeBlock */
2459     if (MaxEntries > KeNumberNodes)
2460     {
2461         MaxEntries = KeNumberNodes;
2462     }
2463 
2464     /* If we have entries to write, and room for it */
2465     if (Size >= FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, AvailableMemory) &&
2466         MaxEntries != 0)
2467     {
2468         /* Already set size we return */
2469         *ReqSize = FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, AvailableMemory) +
2470                    MaxEntries * sizeof(ULONGLONG);
2471 
2472         /* If we have a single entry (us), directly return MM information */
2473         if (MaxEntries == 1)
2474         {
2475             NumaInformation->AvailableMemory[0] = MmAvailablePages << PAGE_SHIFT;
2476         }
2477         else
2478         {
2479             /* Otherwise, for each node, return available bytes */
2480             for (Node = 0; Node < MaxEntries; ++Node)
2481             {
2482                 NumaInformation->AvailableMemory[Node] = (KeNodeBlock[Node]->FreeCount[0] + KeNodeBlock[Node]->FreeCount[1]) << PAGE_SHIFT;
2483             }
2484         }
2485     }
2486     else
2487     {
2488         /* We only returned highest node number */
2489         *ReqSize = sizeof(ULONG);
2490     }
2491 
2492     return STATUS_SUCCESS;
2493 }
2494 
2495 /* Class 64 - Extended handle information */
2496 QSI_DEF(SystemExtendedHandleInformation)
2497 {
2498     PSYSTEM_HANDLE_INFORMATION_EX HandleInformation;
2499     PLIST_ENTRY NextTableEntry;
2500     PHANDLE_TABLE HandleTable;
2501     PHANDLE_TABLE_ENTRY HandleTableEntry;
2502     EXHANDLE Handle;
2503     ULONG Index = 0;
2504     NTSTATUS Status;
2505     PMDL Mdl;
2506     PAGED_CODE();
2507 
2508     DPRINT("NtQuerySystemInformation - SystemExtendedHandleInformation\n");
2509 
2510     /* Set initial required buffer size */
2511     *ReqSize = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handle);
2512 
2513     /* Check user's buffer size */
2514     if (Size < *ReqSize)
2515     {
2516         return STATUS_INFO_LENGTH_MISMATCH;
2517     }
2518 
2519     /* We need to lock down the memory */
2520     Status = ExLockUserBuffer(Buffer,
2521                               Size,
2522                               ExGetPreviousMode(),
2523                               IoWriteAccess,
2524                               (PVOID*)&HandleInformation,
2525                               &Mdl);
2526     if (!NT_SUCCESS(Status))
2527     {
2528         DPRINT1("Failed to lock the user buffer: 0x%lx\n", Status);
2529         return Status;
2530     }
2531 
2532     /* Reset of count of handles */
2533     HandleInformation->Count = 0;
2534 
2535     /* Enter a critical region */
2536     KeEnterCriticalRegion();
2537 
2538     /* Acquire the handle table lock */
2539     ExAcquirePushLockShared(&HandleTableListLock);
2540 
2541     /* Enumerate all system handles */
2542     for (NextTableEntry = HandleTableListHead.Flink;
2543          NextTableEntry != &HandleTableListHead;
2544          NextTableEntry = NextTableEntry->Flink)
2545     {
2546         /* Get current handle table */
2547         HandleTable = CONTAINING_RECORD(NextTableEntry, HANDLE_TABLE, HandleTableList);
2548 
2549         /* Set the initial value and loop the entries */
2550         Handle.Value = 0;
2551         while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle)))
2552         {
2553             /* Validate the entry */
2554             if ((HandleTableEntry->Object) &&
2555                 (HandleTableEntry->NextFreeTableEntry != -2))
2556             {
2557                 /* Increase of count of handles */
2558                 ++HandleInformation->Count;
2559 
2560                 /* Lock the entry */
2561                 if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
2562                 {
2563                     /* Increase required buffer size */
2564                     *ReqSize += sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX);
2565 
2566                     /* Check user's buffer size */
2567                     if (*ReqSize > Size)
2568                     {
2569                         Status = STATUS_INFO_LENGTH_MISMATCH;
2570                     }
2571                     else
2572                     {
2573                         POBJECT_HEADER ObjectHeader = ObpGetHandleObject(HandleTableEntry);
2574 
2575                         /* Filling handle information */
2576                         HandleInformation->Handle[Index].UniqueProcessId =
2577                             (USHORT)(ULONG_PTR) HandleTable->UniqueProcessId;
2578 
2579                         HandleInformation->Handle[Index].CreatorBackTraceIndex = 0;
2580 
2581 #if 0 /* FIXME!!! Type field corrupted */
2582                         HandleInformation->Handles[Index].ObjectTypeIndex =
2583                             (UCHAR) ObjectHeader->Type->Index;
2584 #else
2585                         HandleInformation->Handle[Index].ObjectTypeIndex = 0;
2586 #endif
2587 
2588                         HandleInformation->Handle[Index].HandleAttributes =
2589                             HandleTableEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
2590 
2591                         HandleInformation->Handle[Index].HandleValue =
2592                             (USHORT)(ULONG_PTR) Handle.GenericHandleOverlay;
2593 
2594                         HandleInformation->Handle[Index].Object = &ObjectHeader->Body;
2595 
2596                         HandleInformation->Handle[Index].GrantedAccess =
2597                             HandleTableEntry->GrantedAccess;
2598 
2599                         HandleInformation->Handle[Index].Reserved = 0;
2600 
2601                         ++Index;
2602                     }
2603 
2604                     /* Unlock it */
2605                     ExUnlockHandleTableEntry(HandleTable, HandleTableEntry);
2606                 }
2607             }
2608 
2609             /* Go to the next entry */
2610             Handle.Value += sizeof(HANDLE);
2611         }
2612     }
2613 
2614     /* Release the lock */
2615     ExReleasePushLockShared(&HandleTableListLock);
2616 
2617     /* Leave the critical region */
2618     KeLeaveCriticalRegion();
2619 
2620     /* Release the locked user buffer */
2621     ExUnlockUserBuffer(Mdl);
2622 
2623     return Status;
2624 }
2625 
2626 /* Class 70 - System object security mode information */
2627 QSI_DEF(SystemObjectSecurityMode)
2628 {
2629     PULONG ObjectSecurityInfo = (PULONG)Buffer;
2630 
2631     /* Validate input size */
2632     if (Size != sizeof(ULONG))
2633     {
2634         return STATUS_INFO_LENGTH_MISMATCH;
2635     }
2636 
2637     *ObjectSecurityInfo = ObpObjectSecurityMode;
2638 
2639     return STATUS_SUCCESS;
2640 }
2641 
2642 /* Class 73 - Logical processor information */
2643 QSI_DEF(SystemLogicalProcessorInformation)
2644 {
2645     LONG i;
2646     PKPRCB Prcb;
2647     KAFFINITY CurrentProc;
2648     NTSTATUS Status = STATUS_SUCCESS;
2649     ULONG DataSize = 0, ProcessorFlags;
2650     PSYSTEM_LOGICAL_PROCESSOR_INFORMATION CurrentInfo;
2651 
2652     /* First, browse active processors, thanks to the map */
2653     i = 0;
2654     CurrentInfo = Buffer;
2655     CurrentProc = KeActiveProcessors;
2656     do
2657     {
2658         /* If current processor is active and is main in case of HT/MC, return it */
2659         Prcb = KiProcessorBlock[i];
2660         if ((CurrentProc & 1) &&
2661             Prcb == Prcb->MultiThreadSetMaster)
2662         {
2663             /* Assume processor can do HT or multicore */
2664             ProcessorFlags = 1;
2665 
2666             /* If set is the same for PRCB and multithread, then
2667              * actually, the processor is single core
2668              */
2669             if (Prcb->SetMember == Prcb->MultiThreadProcessorSet)
2670             {
2671                 ProcessorFlags = 0;
2672             }
2673 
2674             /* Check we have enough room to return */
2675             DataSize += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
2676             if (DataSize > Size)
2677             {
2678                 Status = STATUS_INFO_LENGTH_MISMATCH;
2679             }
2680             else
2681             {
2682                 /* Zero output and return */
2683                 RtlZeroMemory(CurrentInfo, sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
2684                 CurrentInfo->ProcessorMask = Prcb->MultiThreadProcessorSet;
2685 
2686                 /* Processor core needs 1 if HT/MC is supported */
2687                 CurrentInfo->Relationship = RelationProcessorCore;
2688                 CurrentInfo->ProcessorCore.Flags = ProcessorFlags;
2689                 ++CurrentInfo;
2690             }
2691         }
2692 
2693         /* Move to the next proc */
2694         CurrentProc >>= 1;
2695         ++i;
2696     /* Loop while there's someone in the bitmask */
2697     } while (CurrentProc != 0);
2698 
2699     /* Now, return the NUMA nodes */
2700     for (i = 0; i < KeNumberNodes; ++i)
2701     {
2702         /* Check we have enough room to return */
2703         DataSize += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
2704         if (DataSize > Size)
2705         {
2706             Status = STATUS_INFO_LENGTH_MISMATCH;
2707         }
2708         else
2709         {
2710             /* Zero output and return */
2711             RtlZeroMemory(CurrentInfo, sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
2712             CurrentInfo->ProcessorMask = KeActiveProcessors;
2713 
2714             /* NUMA node needs its ID */
2715             CurrentInfo->Relationship = RelationNumaNode;
2716             CurrentInfo->NumaNode.NodeNumber = i;
2717             ++CurrentInfo;
2718         }
2719     }
2720 
2721     *ReqSize = DataSize;
2722 
2723     return Status;
2724 }
2725 
2726 /* Class 76 - System firmware table information */
2727 QSI_DEF(SystemFirmwareTableInformation)
2728 {
2729     PSYSTEM_FIRMWARE_TABLE_INFORMATION SysFirmwareInfo = (PSYSTEM_FIRMWARE_TABLE_INFORMATION)Buffer;
2730     NTSTATUS Status = STATUS_SUCCESS;
2731     ULONG InputBufSize;
2732     ULONG DataSize = 0;
2733     ULONG TableCount = 0;
2734 
2735     DPRINT("NtQuerySystemInformation - SystemFirmwareTableInformation\n");
2736 
2737     /* Set initial required buffer size */
2738     *ReqSize = FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
2739 
2740     /* Check user's buffer size */
2741     if (Size < *ReqSize)
2742     {
2743         return STATUS_INFO_LENGTH_MISMATCH;
2744     }
2745 
2746     InputBufSize = SysFirmwareInfo->TableBufferLength;
2747     switch (SysFirmwareInfo->ProviderSignature)
2748     {
2749         /*
2750          * ExpFirmwareTableResource and ExpFirmwareTableProviderListHead
2751          * variables should be used there somehow...
2752          */
2753         case SIG_ACPI:
2754         {
2755             /* FIXME: Not implemented yet */
2756             DPRINT1("ACPI provider not implemented\n");
2757             Status = STATUS_NOT_IMPLEMENTED;
2758             break;
2759         }
2760         case SIG_FIRM:
2761         {
2762             /* FIXME: Not implemented yet */
2763             DPRINT1("FIRM provider not implemented\n");
2764             Status = STATUS_NOT_IMPLEMENTED;
2765             break;
2766         }
2767         case SIG_RSMB:
2768         {
2769             Status = ExpGetRawSMBiosTable(NULL, &DataSize, 0);
2770             if (DataSize > 0)
2771             {
2772                 TableCount = 1;
2773                 if (SysFirmwareInfo->Action == SystemFirmwareTable_Enumerate)
2774                 {
2775                     DataSize = TableCount * sizeof(ULONG);
2776                     if (DataSize <= InputBufSize)
2777                     {
2778                         *(ULONG *)SysFirmwareInfo->TableBuffer = 0;
2779                     }
2780                 }
2781                 else if (SysFirmwareInfo->Action == SystemFirmwareTable_Get
2782                          && DataSize <= InputBufSize)
2783                 {
2784                     Status = ExpGetRawSMBiosTable(SysFirmwareInfo->TableBuffer, &DataSize, InputBufSize);
2785                 }
2786                 SysFirmwareInfo->TableBufferLength = DataSize;
2787             }
2788             break;
2789         }
2790         default:
2791         {
2792             DPRINT1("SystemFirmwareTableInformation: Unsupported provider (0x%x)\n",
2793                     SysFirmwareInfo->ProviderSignature);
2794             Status = STATUS_ILLEGAL_FUNCTION;
2795         }
2796     }
2797 
2798     if (NT_SUCCESS(Status))
2799     {
2800         switch (SysFirmwareInfo->Action)
2801         {
2802             case SystemFirmwareTable_Enumerate:
2803             case SystemFirmwareTable_Get:
2804             {
2805                 if (SysFirmwareInfo->TableBufferLength > InputBufSize)
2806                 {
2807                     Status = STATUS_BUFFER_TOO_SMALL;
2808                 }
2809                 break;
2810             }
2811             default:
2812             {
2813                 DPRINT1("SystemFirmwareTableInformation: Unsupported action (0x%x)\n",
2814                         SysFirmwareInfo->Action);
2815                 Status = STATUS_ILLEGAL_FUNCTION;
2816             }
2817         }
2818     }
2819     else
2820     {
2821         SysFirmwareInfo->TableBufferLength = 0;
2822     }
2823     return Status;
2824 }
2825 
2826 /* Query/Set Calls Table */
2827 typedef
2828 struct _QSSI_CALLS
2829 {
2830     NTSTATUS (* Query) (PVOID,ULONG,PULONG);
2831     NTSTATUS (* Set) (PVOID,ULONG);
2832 } QSSI_CALLS;
2833 
2834 // QS    Query & Set
2835 // QX    Query
2836 // XS    Set
2837 // XX    unknown behaviour
2838 //
2839 #define SI_QS(n) {QSI_USE(n),SSI_USE(n)}
2840 #define SI_QX(n) {QSI_USE(n),NULL}
2841 #define SI_XS(n) {NULL,SSI_USE(n)}
2842 #define SI_XX(n) {NULL,NULL}
2843 
2844 static
2845 QSSI_CALLS
2846 CallQS[] =
2847 {
2848     SI_QX(SystemBasicInformation),
2849     SI_QX(SystemProcessorInformation),
2850     SI_QX(SystemPerformanceInformation),
2851     SI_QX(SystemTimeOfDayInformation),
2852     SI_QX(SystemPathInformation),
2853     SI_QX(SystemProcessInformation),
2854     SI_QX(SystemCallCountInformation),
2855     SI_QX(SystemDeviceInformation),
2856     SI_QX(SystemProcessorPerformanceInformation),
2857     SI_QS(SystemFlagsInformation),
2858     SI_QX(SystemCallTimeInformation), /* should be SI_XX */
2859     SI_QX(SystemModuleInformation),
2860     SI_QX(SystemLocksInformation),
2861     SI_QX(SystemStackTraceInformation), /* should be SI_XX */
2862     SI_QX(SystemPagedPoolInformation), /* should be SI_XX */
2863     SI_QX(SystemNonPagedPoolInformation), /* should be SI_XX */
2864     SI_QX(SystemHandleInformation),
2865     SI_QX(SystemObjectInformation),
2866     SI_QX(SystemPageFileInformation),
2867     SI_QX(SystemVdmInstemulInformation),
2868     SI_QX(SystemVdmBopInformation), /* it should be SI_XX */
2869     SI_QS(SystemFileCacheInformation),
2870     SI_QX(SystemPoolTagInformation),
2871     SI_QX(SystemInterruptInformation),
2872     SI_QS(SystemDpcBehaviourInformation),
2873     SI_QX(SystemFullMemoryInformation), /* it should be SI_XX */
2874     SI_XS(SystemLoadGdiDriverInformation),
2875     SI_XS(SystemUnloadGdiDriverInformation),
2876     SI_QS(SystemTimeAdjustmentInformation),
2877     SI_QX(SystemSummaryMemoryInformation), /* it should be SI_XX */
2878     SI_QX(SystemNextEventIdInformation), /* it should be SI_XX */
2879     SI_QX(SystemPerformanceTraceInformation), /* it should be SI_XX */
2880     SI_QX(SystemCrashDumpInformation),
2881     SI_QX(SystemExceptionInformation),
2882     SI_QX(SystemCrashDumpStateInformation),
2883     SI_QX(SystemKernelDebuggerInformation),
2884     SI_QX(SystemContextSwitchInformation),
2885     SI_QS(SystemRegistryQuotaInformation),
2886     SI_XS(SystemExtendServiceTableInformation),
2887     SI_XS(SystemPrioritySeperation),
2888     SI_QX(SystemVerifierAddDriverInformation), /* it should be SI_XX */
2889     SI_QX(SystemVerifierRemoveDriverInformation), /* it should be SI_XX */
2890     SI_QX(SystemProcessorIdleInformation), /* it should be SI_XX */
2891     SI_QX(SystemLegacyDriverInformation), /* it should be SI_XX */
2892     SI_QS(SystemCurrentTimeZoneInformation), /* it should be SI_QX */
2893     SI_QX(SystemLookasideInformation),
2894     SI_XS(SystemTimeSlipNotification),
2895     SI_XS(SystemSessionCreate),
2896     SI_XS(SystemSessionDetach),
2897     SI_QX(SystemSessionInformation), /* it should be SI_XX */
2898     SI_QX(SystemRangeStartInformation),
2899     SI_QS(SystemVerifierInformation),
2900     SI_XS(SystemVerifierThunkExtend),
2901     SI_QX(SystemSessionProcessesInformation),
2902     SI_XS(SystemLoadGdiDriverInSystemSpaceInformation),
2903     SI_QX(SystemNumaProcessorMap),
2904     SI_QX(SystemPrefetcherInformation),
2905     SI_QX(SystemExtendedProcessInformation),
2906     SI_QX(SystemRecommendedSharedDataAlignment),
2907     SI_XX(SystemComPlusPackage),
2908     SI_QX(SystemNumaAvailableMemory),
2909     SI_XX(SystemProcessorPowerInformation), /* FIXME: not implemented */
2910     SI_XX(SystemEmulationBasicInformation), /* FIXME: not implemented */
2911     SI_XX(SystemEmulationProcessorInformation), /* FIXME: not implemented */
2912     SI_QX(SystemExtendedHandleInformation),
2913     SI_XX(SystemLostDelayedWriteInformation), /* FIXME: not implemented */
2914     SI_XX(SystemBigPoolInformation), /* FIXME: not implemented */
2915     SI_XX(SystemSessionPoolTagInformation), /* FIXME: not implemented */
2916     SI_XX(SystemSessionMappedViewInformation), /* FIXME: not implemented */
2917     SI_XX(SystemHotpatchInformation), /* FIXME: not implemented */
2918     SI_QX(SystemObjectSecurityMode),
2919     SI_XX(SystemWatchdogTimerHandler), /* FIXME: not implemented */
2920     SI_XX(SystemWatchdogTimerInformation), /* FIXME: not implemented */
2921     SI_QX(SystemLogicalProcessorInformation),
2922     SI_XX(SystemWow64SharedInformation), /* FIXME: not implemented */
2923     SI_XX(SystemRegisterFirmwareTableInformationHandler), /* FIXME: not implemented */
2924     SI_QX(SystemFirmwareTableInformation),
2925 };
2926 
2927 C_ASSERT(SystemBasicInformation == 0);
2928 #define MIN_SYSTEM_INFO_CLASS (SystemBasicInformation)
2929 #define MAX_SYSTEM_INFO_CLASS RTL_NUMBER_OF(CallQS)
2930 
2931 /*
2932  * @implemented
2933  */
2934 __kernel_entry
2935 NTSTATUS
2936 NTAPI
2937 NtQuerySystemInformation(
2938     _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
2939     _Out_writes_bytes_to_opt_(SystemInformationLength, *ReturnLength) PVOID SystemInformation,
2940     _In_ ULONG SystemInformationLength,
2941     _Out_opt_ PULONG ReturnLength)
2942 {
2943     NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
2944     ULONG CapturedResultLength = 0;
2945     ULONG Alignment = TYPE_ALIGNMENT(ULONG);
2946     KPROCESSOR_MODE PreviousMode;
2947 
2948     PAGED_CODE();
2949 
2950     PreviousMode = ExGetPreviousMode();
2951 
2952     _SEH2_TRY
2953     {
2954 #if (NTDDI_VERSION >= NTDDI_VISTA)
2955         /*
2956          * Check whether the request is valid.
2957          */
2958         if (SystemInformationClass < MIN_SYSTEM_INFO_CLASS ||
2959             SystemInformationClass >= MAX_SYSTEM_INFO_CLASS)
2960         {
2961             _SEH2_YIELD(return STATUS_INVALID_INFO_CLASS);
2962         }
2963 #endif
2964 
2965         if (PreviousMode != KernelMode)
2966         {
2967             /* SystemKernelDebuggerInformation needs only BOOLEAN alignment */
2968             if (SystemInformationClass == SystemKernelDebuggerInformation)
2969                 Alignment = TYPE_ALIGNMENT(BOOLEAN);
2970 
2971             ProbeForWrite(SystemInformation, SystemInformationLength, Alignment);
2972             if (ReturnLength != NULL)
2973                 ProbeForWriteUlong(ReturnLength);
2974         }
2975 
2976         if (ReturnLength)
2977             *ReturnLength = 0;
2978 
2979 #if (NTDDI_VERSION < NTDDI_VISTA)
2980         /*
2981          * Check whether the request is valid.
2982          */
2983         if (SystemInformationClass < MIN_SYSTEM_INFO_CLASS ||
2984             SystemInformationClass >= MAX_SYSTEM_INFO_CLASS)
2985         {
2986             _SEH2_YIELD(return STATUS_INVALID_INFO_CLASS);
2987         }
2988 #endif
2989 
2990         if (CallQS[SystemInformationClass].Query != NULL)
2991         {
2992             /* Hand the request to a subhandler */
2993             Status = CallQS[SystemInformationClass].Query(SystemInformation,
2994                                                           SystemInformationLength,
2995                                                           &CapturedResultLength);
2996 
2997             /* Save the result length to the caller */
2998             if (ReturnLength)
2999                 *ReturnLength = CapturedResultLength;
3000         }
3001     }
3002     _SEH2_EXCEPT(ExSystemExceptionFilter())
3003     {
3004         Status = _SEH2_GetExceptionCode();
3005     }
3006     _SEH2_END;
3007 
3008     return Status;
3009 }
3010 
3011 __kernel_entry
3012 NTSTATUS
3013 NTAPI
3014 NtSetSystemInformation(
3015     _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
3016     _In_reads_bytes_(SystemInformationLength) PVOID SystemInformation,
3017     _In_ ULONG SystemInformationLength)
3018 {
3019     NTSTATUS Status = STATUS_INVALID_INFO_CLASS;
3020     KPROCESSOR_MODE PreviousMode;
3021 
3022     PAGED_CODE();
3023 
3024     PreviousMode = ExGetPreviousMode();
3025 
3026     _SEH2_TRY
3027     {
3028         /*
3029          * If called from user mode, check possible unsafe arguments.
3030          */
3031         if (PreviousMode != KernelMode)
3032         {
3033             ProbeForRead(SystemInformation, SystemInformationLength, sizeof(ULONG));
3034         }
3035 
3036         /*
3037          * Check whether the request is valid.
3038          */
3039         if ((SystemInformationClass >= MIN_SYSTEM_INFO_CLASS) &&
3040             (SystemInformationClass < MAX_SYSTEM_INFO_CLASS))
3041         {
3042             if (CallQS[SystemInformationClass].Set != NULL)
3043             {
3044                 /* Hand the request to a subhandler */
3045                 Status = CallQS[SystemInformationClass].Set(SystemInformation,
3046                                                             SystemInformationLength);
3047             }
3048         }
3049     }
3050     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3051     {
3052         Status = _SEH2_GetExceptionCode();
3053     }
3054     _SEH2_END;
3055 
3056     return Status;
3057 }
3058 
3059 ULONG
3060 NTAPI
3061 NtGetCurrentProcessorNumber(VOID)
3062 {
3063     /* Just use Ke */
3064     return KeGetCurrentProcessorNumber();
3065 }
3066 
3067 #undef ExGetPreviousMode
3068 KPROCESSOR_MODE
3069 NTAPI
3070 ExGetPreviousMode(VOID)
3071 {
3072     /* Just use Ke */
3073     return KeGetPreviousMode();
3074 }
3075