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