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