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