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