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