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