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