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