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