[NTOSKRNL] Also account PRCBs for Io operations counters
[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 /* FIXME */
1543 DPRINT1("NtQuerySystemInformation - SystemDpcBehaviourInformation not implemented\n");
1544 return STATUS_NOT_IMPLEMENTED;
1545 }
1546
1547 SSI_DEF(SystemDpcBehaviourInformation)
1548 {
1549 /* FIXME */
1550 DPRINT1("NtSetSystemInformation - SystemDpcBehaviourInformation not implemented\n");
1551 return STATUS_NOT_IMPLEMENTED;
1552 }
1553
1554 /* Class 25 - Full Memory Information */
1555 QSI_DEF(SystemFullMemoryInformation)
1556 {
1557 PULONG Spi = (PULONG) Buffer;
1558
1559 PEPROCESS TheIdleProcess;
1560
1561 *ReqSize = sizeof(ULONG);
1562
1563 if (sizeof(ULONG) != Size)
1564 {
1565 return STATUS_INFO_LENGTH_MISMATCH;
1566 }
1567
1568 DPRINT("SystemFullMemoryInformation\n");
1569
1570 TheIdleProcess = PsIdleProcess;
1571
1572 DPRINT("PID: %p, KernelTime: %u PFFree: %lu PFUsed: %lu\n",
1573 TheIdleProcess->UniqueProcessId,
1574 TheIdleProcess->Pcb.KernelTime,
1575 MiFreeSwapPages,
1576 MiUsedSwapPages);
1577
1578 *Spi = MiMemoryConsumers[MC_USER].PagesUsed;
1579
1580 return STATUS_SUCCESS;
1581 }
1582
1583 /* Class 26 - Load Image */
1584 SSI_DEF(SystemLoadGdiDriverInformation)
1585 {
1586 PSYSTEM_GDI_DRIVER_INFORMATION DriverInfo = (PVOID)Buffer;
1587 UNICODE_STRING ImageName;
1588 PVOID ImageBase;
1589 PVOID SectionPointer;
1590 ULONG_PTR EntryPoint;
1591 NTSTATUS Status;
1592 ULONG DirSize;
1593 PIMAGE_NT_HEADERS NtHeader;
1594
1595 /* Validate size */
1596 if (Size != sizeof(SYSTEM_GDI_DRIVER_INFORMATION))
1597 {
1598 /* Incorrect buffer length, fail */
1599 return STATUS_INFO_LENGTH_MISMATCH;
1600 }
1601
1602 /* Only kernel mode can call this function */
1603 if (ExGetPreviousMode() != KernelMode) return STATUS_PRIVILEGE_NOT_HELD;
1604
1605 /* Load the driver */
1606 ImageName = DriverInfo->DriverName;
1607 Status = MmLoadSystemImage(&ImageName,
1608 NULL,
1609 NULL,
1610 0,
1611 &SectionPointer,
1612 &ImageBase);
1613 if (!NT_SUCCESS(Status)) return Status;
1614
1615 /* Return the export pointer */
1616 DriverInfo->ExportSectionPointer =
1617 RtlImageDirectoryEntryToData(ImageBase,
1618 TRUE,
1619 IMAGE_DIRECTORY_ENTRY_EXPORT,
1620 &DirSize);
1621
1622 /* Get the entrypoint */
1623 NtHeader = RtlImageNtHeader(ImageBase);
1624 EntryPoint = NtHeader->OptionalHeader.AddressOfEntryPoint;
1625 EntryPoint += (ULONG_PTR)ImageBase;
1626
1627 /* Save other data */
1628 DriverInfo->ImageAddress = ImageBase;
1629 DriverInfo->SectionPointer = SectionPointer;
1630 DriverInfo->EntryPoint = (PVOID)EntryPoint;
1631 DriverInfo->ImageLength = NtHeader->OptionalHeader.SizeOfImage;
1632
1633 /* All is good */
1634 return STATUS_SUCCESS;
1635 }
1636
1637 /* Class 27 - Unload Image */
1638 SSI_DEF(SystemUnloadGdiDriverInformation)
1639 {
1640 PVOID *SectionPointer = Buffer;
1641
1642 /* Validate size */
1643 if (Size != sizeof(PVOID))
1644 {
1645 /* Incorrect length, fail */
1646 return STATUS_INFO_LENGTH_MISMATCH;
1647 }
1648
1649 /* Only kernel mode can call this function */
1650 if (ExGetPreviousMode() != KernelMode) return STATUS_PRIVILEGE_NOT_HELD;
1651
1652 /* Unload the image */
1653 MmUnloadSystemImage(*SectionPointer);
1654 return STATUS_SUCCESS;
1655 }
1656
1657 /* Class 28 - Time Adjustment Information */
1658 QSI_DEF(SystemTimeAdjustmentInformation)
1659 {
1660 PSYSTEM_QUERY_TIME_ADJUST_INFORMATION TimeInfo =
1661 (PSYSTEM_QUERY_TIME_ADJUST_INFORMATION)Buffer;
1662
1663 /* Check if enough storage was provided */
1664 if (sizeof(SYSTEM_QUERY_TIME_ADJUST_INFORMATION) > Size)
1665 {
1666 * ReqSize = sizeof(SYSTEM_QUERY_TIME_ADJUST_INFORMATION);
1667 return STATUS_INFO_LENGTH_MISMATCH;
1668 }
1669
1670 /* Give time values to our caller */
1671 TimeInfo->TimeIncrement = KeMaximumIncrement;
1672 TimeInfo->TimeAdjustment = KeTimeAdjustment;
1673 TimeInfo->Enable = !KiTimeAdjustmentEnabled;
1674
1675 return STATUS_SUCCESS;
1676 }
1677
1678 SSI_DEF(SystemTimeAdjustmentInformation)
1679 {
1680 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1681 PSYSTEM_SET_TIME_ADJUST_INFORMATION TimeInfo =
1682 (PSYSTEM_SET_TIME_ADJUST_INFORMATION)Buffer;
1683
1684 /* Check size of a buffer, it must match our expectations */
1685 if (sizeof(SYSTEM_SET_TIME_ADJUST_INFORMATION) != Size)
1686 return STATUS_INFO_LENGTH_MISMATCH;
1687
1688 /* Check who is calling */
1689 if (PreviousMode != KernelMode)
1690 {
1691 /* Check access rights */
1692 if (!SeSinglePrivilegeCheck(SeSystemtimePrivilege, PreviousMode))
1693 {
1694 return STATUS_PRIVILEGE_NOT_HELD;
1695 }
1696 }
1697
1698 /* FIXME: behaviour suggests the member be named 'Disable' */
1699 if (TimeInfo->Enable)
1700 {
1701 /* Disable time adjustment and set default value */
1702 KiTimeAdjustmentEnabled = FALSE;
1703 KeTimeAdjustment = KeMaximumIncrement;
1704 }
1705 else
1706 {
1707 /* Check if a valid time adjustment value is given */
1708 if (TimeInfo->TimeAdjustment == 0) return STATUS_INVALID_PARAMETER_2;
1709
1710 /* Enable time adjustment and set the adjustment value */
1711 KiTimeAdjustmentEnabled = TRUE;
1712 KeTimeAdjustment = TimeInfo->TimeAdjustment;
1713 }
1714
1715 return STATUS_SUCCESS;
1716 }
1717
1718 /* Class 29 - Summary Memory Information */
1719 QSI_DEF(SystemSummaryMemoryInformation)
1720 {
1721 /* FIXME */
1722 DPRINT1("NtQuerySystemInformation - SystemSummaryMemoryInformation not implemented\n");
1723 return STATUS_NOT_IMPLEMENTED;
1724 }
1725
1726 /* Class 30 - Next Event Id Information */
1727 QSI_DEF(SystemNextEventIdInformation)
1728 {
1729 /* FIXME */
1730 DPRINT1("NtQuerySystemInformation - SystemNextEventIdInformation not implemented\n");
1731 return STATUS_NOT_IMPLEMENTED;
1732 }
1733
1734 /* Class 31 */
1735 QSI_DEF(SystemPerformanceTraceInformation)
1736 {
1737 /* FIXME */
1738 DPRINT1("NtQuerySystemInformation - SystemPerformanceTraceInformation not implemented\n");
1739 return STATUS_NOT_IMPLEMENTED;
1740 }
1741
1742 /* Class 32 - Crash Dump Information */
1743 QSI_DEF(SystemCrashDumpInformation)
1744 {
1745 /* FIXME */
1746 DPRINT1("NtQuerySystemInformation - SystemCrashDumpInformation not implemented\n");
1747 return STATUS_NOT_IMPLEMENTED;
1748 }
1749
1750 /* Class 33 - Exception Information */
1751 QSI_DEF(SystemExceptionInformation)
1752 {
1753 PSYSTEM_EXCEPTION_INFORMATION ExceptionInformation =
1754 (PSYSTEM_EXCEPTION_INFORMATION)Buffer;
1755 PKPRCB Prcb;
1756 ULONG AlignmentFixupCount = 0, ExceptionDispatchCount = 0;
1757 ULONG FloatingEmulationCount = 0, ByteWordEmulationCount = 0;
1758 CHAR i;
1759
1760 /* Check size of a buffer, it must match our expectations */
1761 if (sizeof(SYSTEM_EXCEPTION_INFORMATION) != Size)
1762 return STATUS_INFO_LENGTH_MISMATCH;
1763
1764 /* Sum up exception count information from all processors */
1765 for (i = 0; i < KeNumberProcessors; i++)
1766 {
1767 Prcb = KiProcessorBlock[i];
1768 if (Prcb)
1769 {
1770 AlignmentFixupCount += Prcb->KeAlignmentFixupCount;
1771 ExceptionDispatchCount += Prcb->KeExceptionDispatchCount;
1772 #ifndef _M_ARM
1773 FloatingEmulationCount += Prcb->KeFloatingEmulationCount;
1774 #endif // _M_ARM
1775 }
1776 }
1777
1778 /* Save information in user's buffer */
1779 ExceptionInformation->AlignmentFixupCount = AlignmentFixupCount;
1780 ExceptionInformation->ExceptionDispatchCount = ExceptionDispatchCount;
1781 ExceptionInformation->FloatingEmulationCount = FloatingEmulationCount;
1782 ExceptionInformation->ByteWordEmulationCount = ByteWordEmulationCount;
1783
1784 return STATUS_SUCCESS;
1785 }
1786
1787 /* Class 34 - Crash Dump State Information */
1788 QSI_DEF(SystemCrashDumpStateInformation)
1789 {
1790 /* FIXME */
1791 DPRINT1("NtQuerySystemInformation - SystemCrashDumpStateInformation not implemented\n");
1792 return STATUS_NOT_IMPLEMENTED;
1793 }
1794
1795 /* Class 35 - Kernel Debugger Information */
1796 QSI_DEF(SystemKernelDebuggerInformation)
1797 {
1798 PSYSTEM_KERNEL_DEBUGGER_INFORMATION skdi = (PSYSTEM_KERNEL_DEBUGGER_INFORMATION) Buffer;
1799
1800 #if (NTDDI_VERSION >= NTDDI_VISTA)
1801 *ReqSize = sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION);
1802 #endif
1803
1804 if (Size < sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION))
1805 {
1806 return STATUS_INFO_LENGTH_MISMATCH;
1807 }
1808
1809 skdi->KernelDebuggerEnabled = KD_DEBUGGER_ENABLED;
1810 skdi->KernelDebuggerNotPresent = KD_DEBUGGER_NOT_PRESENT;
1811
1812 #if (NTDDI_VERSION < NTDDI_VISTA)
1813 *ReqSize = sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION);
1814 #endif
1815
1816 return STATUS_SUCCESS;
1817 }
1818
1819 /* Class 36 - Context Switch Information */
1820 QSI_DEF(SystemContextSwitchInformation)
1821 {
1822 PSYSTEM_CONTEXT_SWITCH_INFORMATION ContextSwitchInformation =
1823 (PSYSTEM_CONTEXT_SWITCH_INFORMATION)Buffer;
1824 ULONG ContextSwitches;
1825 PKPRCB Prcb;
1826 CHAR i;
1827
1828 /* Check size of a buffer, it must match our expectations */
1829 if (sizeof(SYSTEM_CONTEXT_SWITCH_INFORMATION) != Size)
1830 return STATUS_INFO_LENGTH_MISMATCH;
1831
1832 /* Calculate total value of context switches across all processors */
1833 ContextSwitches = 0;
1834 for (i = 0; i < KeNumberProcessors; i ++)
1835 {
1836 Prcb = KiProcessorBlock[i];
1837 if (Prcb)
1838 {
1839 ContextSwitches += KeGetContextSwitches(Prcb);
1840 }
1841 }
1842
1843 ContextSwitchInformation->ContextSwitches = ContextSwitches;
1844
1845 /* FIXME */
1846 ContextSwitchInformation->FindAny = 0;
1847 ContextSwitchInformation->FindLast = 0;
1848 ContextSwitchInformation->FindIdeal = 0;
1849 ContextSwitchInformation->IdleAny = 0;
1850 ContextSwitchInformation->IdleCurrent = 0;
1851 ContextSwitchInformation->IdleLast = 0;
1852 ContextSwitchInformation->IdleIdeal = 0;
1853 ContextSwitchInformation->PreemptAny = 0;
1854 ContextSwitchInformation->PreemptCurrent = 0;
1855 ContextSwitchInformation->PreemptLast = 0;
1856 ContextSwitchInformation->SwitchToIdle = 0;
1857
1858 return STATUS_SUCCESS;
1859 }
1860
1861 /* Class 37 - Registry Quota Information */
1862 QSI_DEF(SystemRegistryQuotaInformation)
1863 {
1864 PSYSTEM_REGISTRY_QUOTA_INFORMATION srqi = (PSYSTEM_REGISTRY_QUOTA_INFORMATION) Buffer;
1865
1866 *ReqSize = sizeof(SYSTEM_REGISTRY_QUOTA_INFORMATION);
1867 if (Size < sizeof(SYSTEM_REGISTRY_QUOTA_INFORMATION))
1868 {
1869 return STATUS_INFO_LENGTH_MISMATCH;
1870 }
1871
1872 DPRINT1("Faking max registry size of 32 MB\n");
1873 srqi->RegistryQuotaAllowed = 0x2000000;
1874 srqi->RegistryQuotaUsed = 0x200000;
1875 srqi->PagedPoolSize = 0x200000;
1876
1877 return STATUS_SUCCESS;
1878 }
1879
1880 SSI_DEF(SystemRegistryQuotaInformation)
1881 {
1882 /* FIXME */
1883 DPRINT1("NtSetSystemInformation - SystemRegistryQuotaInformation not implemented\n");
1884 return STATUS_NOT_IMPLEMENTED;
1885 }
1886
1887 /* Class 38 - Load And Call Image */
1888 SSI_DEF(SystemExtendServiceTableInformation)
1889 {
1890 UNICODE_STRING ImageName;
1891 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1892 PLDR_DATA_TABLE_ENTRY ModuleObject;
1893 NTSTATUS Status;
1894 PIMAGE_NT_HEADERS NtHeader;
1895 DRIVER_OBJECT Win32k;
1896 PDRIVER_INITIALIZE DriverInit;
1897 PVOID ImageBase;
1898 ULONG_PTR EntryPoint;
1899
1900 /* Validate the size */
1901 if (Size != sizeof(UNICODE_STRING)) return STATUS_INFO_LENGTH_MISMATCH;
1902
1903 /* Check who is calling */
1904 if (PreviousMode != KernelMode)
1905 {
1906 static const UNICODE_STRING Win32kName =
1907 RTL_CONSTANT_STRING(L"\\SystemRoot\\System32\\win32k.sys");
1908
1909 /* Make sure we can load drivers */
1910 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, UserMode))
1911 {
1912 /* FIXME: We can't, fail */
1913 return STATUS_PRIVILEGE_NOT_HELD;
1914 }
1915
1916 _SEH2_TRY
1917 {
1918 /* Probe and copy the unicode string */
1919 ProbeForRead(Buffer, sizeof(ImageName), 1);
1920 ImageName = *(PUNICODE_STRING)Buffer;
1921
1922 /* Probe the string buffer */
1923 ProbeForRead(ImageName.Buffer, ImageName.Length, sizeof(WCHAR));
1924
1925 /* Check if we have the correct name (nothing else is allowed!) */
1926 if (!RtlEqualUnicodeString(&ImageName, &Win32kName, FALSE))
1927 {
1928 _SEH2_YIELD(return STATUS_PRIVILEGE_NOT_HELD);
1929 }
1930 }
1931 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1932 {
1933 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1934 }
1935 _SEH2_END;
1936
1937 /* Recursively call the function, so that we are from kernel mode */
1938 return ZwSetSystemInformation(SystemExtendServiceTableInformation,
1939 (PVOID)&Win32kName,
1940 sizeof(Win32kName));
1941 }
1942
1943 /* Load the image */
1944 Status = MmLoadSystemImage((PUNICODE_STRING)Buffer,
1945 NULL,
1946 NULL,
1947 0,
1948 (PVOID)&ModuleObject,
1949 &ImageBase);
1950
1951 if (!NT_SUCCESS(Status)) return Status;
1952
1953 /* Get the headers */
1954 NtHeader = RtlImageNtHeader(ImageBase);
1955 if (!NtHeader)
1956 {
1957 /* Fail */
1958 MmUnloadSystemImage(ModuleObject);
1959 return STATUS_INVALID_IMAGE_FORMAT;
1960 }
1961
1962 /* Get the entrypoint */
1963 EntryPoint = NtHeader->OptionalHeader.AddressOfEntryPoint;
1964 EntryPoint += (ULONG_PTR)ImageBase;
1965 DriverInit = (PDRIVER_INITIALIZE)EntryPoint;
1966
1967 /* Create a dummy device */
1968 RtlZeroMemory(&Win32k, sizeof(Win32k));
1969 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
1970 Win32k.DriverStart = ImageBase;
1971
1972 /* Call it */
1973 Status = (DriverInit)(&Win32k, NULL);
1974 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
1975
1976 /* Unload if we failed */
1977 if (!NT_SUCCESS(Status)) MmUnloadSystemImage(ModuleObject);
1978 return Status;
1979 }
1980
1981 /* Class 39 - Priority Separation */
1982 SSI_DEF(SystemPrioritySeperation)
1983 {
1984 /* Check if the size is correct */
1985 if (Size != sizeof(ULONG))
1986 {
1987 return STATUS_INFO_LENGTH_MISMATCH;
1988 }
1989
1990 /* We need the TCB privilege */
1991 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, ExGetPreviousMode()))
1992 {
1993 return STATUS_PRIVILEGE_NOT_HELD;
1994 }
1995
1996 /* Modify the quantum table */
1997 PsChangeQuantumTable(TRUE, *(PULONG)Buffer);
1998
1999 return STATUS_SUCCESS;
2000 }
2001
2002 /* Class 40 */
2003 QSI_DEF(SystemVerifierAddDriverInformation)
2004 {
2005 /* FIXME */
2006 DPRINT1("NtQuerySystemInformation - SystemVerifierAddDriverInformation not implemented\n");
2007 return STATUS_NOT_IMPLEMENTED;
2008 }
2009
2010 /* Class 41 */
2011 QSI_DEF(SystemVerifierRemoveDriverInformation)
2012 {
2013 /* FIXME */
2014 DPRINT1("NtQuerySystemInformation - SystemVerifierRemoveDriverInformation not implemented\n");
2015 return STATUS_NOT_IMPLEMENTED;
2016 }
2017
2018 /* Class 42 - Power Information */
2019 QSI_DEF(SystemProcessorIdleInformation)
2020 {
2021 *ReqSize = sizeof(PROCESSOR_POWER_INFORMATION) * KeNumberProcessors;
2022
2023 if (sizeof(PROCESSOR_POWER_INFORMATION) * KeNumberProcessors > Size)
2024 {
2025 return STATUS_INFO_LENGTH_MISMATCH;
2026 }
2027
2028 /* FIXME */
2029 DPRINT1("NtQuerySystemInformation - SystemPowerInformation not implemented\n");
2030 return STATUS_NOT_IMPLEMENTED;
2031 }
2032
2033 /* Class 43 */
2034 QSI_DEF(SystemLegacyDriverInformation)
2035 {
2036 /* FIXME */
2037 DPRINT1("NtQuerySystemInformation - SystemLegacyDriverInformation not implemented\n");
2038 return STATUS_NOT_IMPLEMENTED;
2039 }
2040
2041 /* Class 44 - Current Time Zone Information */
2042 QSI_DEF(SystemCurrentTimeZoneInformation)
2043 {
2044 *ReqSize = sizeof(RTL_TIME_ZONE_INFORMATION);
2045
2046 if (sizeof(RTL_TIME_ZONE_INFORMATION) != Size)
2047 {
2048 return STATUS_INFO_LENGTH_MISMATCH;
2049 }
2050
2051 /* Copy the time zone information struct */
2052 memcpy(Buffer,
2053 &ExpTimeZoneInfo,
2054 sizeof(RTL_TIME_ZONE_INFORMATION));
2055
2056 return STATUS_SUCCESS;
2057 }
2058
2059
2060 SSI_DEF(SystemCurrentTimeZoneInformation)
2061 {
2062 /* Check user buffer's size */
2063 if (Size < sizeof(RTL_TIME_ZONE_INFORMATION))
2064 {
2065 return STATUS_INFO_LENGTH_MISMATCH;
2066 }
2067
2068 return ExpSetTimeZoneInformation((PRTL_TIME_ZONE_INFORMATION)Buffer);
2069 }
2070
2071 static
2072 VOID
2073 ExpCopyLookasideInformation(
2074 PSYSTEM_LOOKASIDE_INFORMATION *InfoPointer,
2075 PULONG RemainingPointer,
2076 PLIST_ENTRY ListHead,
2077 BOOLEAN ListUsesMisses)
2078
2079 {
2080 PSYSTEM_LOOKASIDE_INFORMATION Info;
2081 PGENERAL_LOOKASIDE LookasideList;
2082 PLIST_ENTRY ListEntry;
2083 ULONG Remaining;
2084
2085 /* Get info pointer and remaining count of free array element */
2086 Info = *InfoPointer;
2087 Remaining = *RemainingPointer;
2088
2089 /* Loop as long as we have lookaside lists and free array elements */
2090 for (ListEntry = ListHead->Flink;
2091 (ListEntry != ListHead) && (Remaining > 0);
2092 ListEntry = ListEntry->Flink, Remaining--)
2093 {
2094 LookasideList = CONTAINING_RECORD(ListEntry, GENERAL_LOOKASIDE, ListEntry);
2095
2096 /* Fill the next array element */
2097 Info->CurrentDepth = LookasideList->Depth;
2098 Info->MaximumDepth = LookasideList->MaximumDepth;
2099 Info->TotalAllocates = LookasideList->TotalAllocates;
2100 Info->TotalFrees = LookasideList->TotalFrees;
2101 Info->Type = LookasideList->Type;
2102 Info->Tag = LookasideList->Tag;
2103 Info->Size = LookasideList->Size;
2104
2105 /* Check how the lists track misses/hits */
2106 if (ListUsesMisses)
2107 {
2108 /* Copy misses */
2109 Info->AllocateMisses = LookasideList->AllocateMisses;
2110 Info->FreeMisses = LookasideList->FreeMisses;
2111 }
2112 else
2113 {
2114 /* Calculate misses */
2115 Info->AllocateMisses = LookasideList->TotalAllocates
2116 - LookasideList->AllocateHits;
2117 Info->FreeMisses = LookasideList->TotalFrees
2118 - LookasideList->FreeHits;
2119 }
2120 }
2121
2122 /* Return the updated pointer and remaining count */
2123 *InfoPointer = Info;
2124 *RemainingPointer = Remaining;
2125 }
2126
2127 /* Class 45 - Lookaside Information */
2128 QSI_DEF(SystemLookasideInformation)
2129 {
2130 KPROCESSOR_MODE PreviousMode;
2131 PSYSTEM_LOOKASIDE_INFORMATION Info;
2132 PMDL Mdl;
2133 ULONG MaxCount, Remaining;
2134 KIRQL OldIrql;
2135 NTSTATUS Status;
2136
2137 /* First we need to lock down the memory, since we are going to access it
2138 at high IRQL */
2139 PreviousMode = ExGetPreviousMode();
2140 Status = ExLockUserBuffer(Buffer,
2141 Size,
2142 PreviousMode,
2143 IoWriteAccess,
2144 (PVOID*)&Info,
2145 &Mdl);
2146 if (!NT_SUCCESS(Status))
2147 {
2148 DPRINT1("Failed to lock the user buffer: 0x%lx\n", Status);
2149 return Status;
2150 }
2151
2152 /* Calculate how many items we can store */
2153 Remaining = MaxCount = Size / sizeof(SYSTEM_LOOKASIDE_INFORMATION);
2154 if (Remaining == 0)
2155 {
2156 goto Leave;
2157 }
2158
2159 /* Copy info from pool lookaside lists */
2160 ExpCopyLookasideInformation(&Info,
2161 &Remaining,
2162 &ExPoolLookasideListHead,
2163 FALSE);
2164 if (Remaining == 0)
2165 {
2166 goto Leave;
2167 }
2168
2169 /* Copy info from system lookaside lists */
2170 ExpCopyLookasideInformation(&Info,
2171 &Remaining,
2172 &ExSystemLookasideListHead,
2173 TRUE);
2174 if (Remaining == 0)
2175 {
2176 goto Leave;
2177 }
2178
2179 /* Acquire spinlock for ExpNonPagedLookasideListHead */
2180 KeAcquireSpinLock(&ExpNonPagedLookasideListLock, &OldIrql);
2181
2182 /* Copy info from non-paged lookaside lists */
2183 ExpCopyLookasideInformation(&Info,
2184 &Remaining,
2185 &ExpNonPagedLookasideListHead,
2186 TRUE);
2187
2188 /* Release spinlock for ExpNonPagedLookasideListHead */
2189 KeReleaseSpinLock(&ExpNonPagedLookasideListLock, OldIrql);
2190
2191 if (Remaining == 0)
2192 {
2193 goto Leave;
2194 }
2195
2196 /* Acquire spinlock for ExpPagedLookasideListHead */
2197 KeAcquireSpinLock(&ExpPagedLookasideListLock, &OldIrql);
2198
2199 /* Copy info from paged lookaside lists */
2200 ExpCopyLookasideInformation(&Info,
2201 &Remaining,
2202 &ExpPagedLookasideListHead,
2203 TRUE);
2204
2205 /* Release spinlock for ExpPagedLookasideListHead */
2206 KeReleaseSpinLock(&ExpPagedLookasideListLock, OldIrql);
2207
2208 Leave:
2209
2210 /* Release the locked user buffer */
2211 ExUnlockUserBuffer(Mdl);
2212
2213 /* Return the size of the actually written data */
2214 *ReqSize = (MaxCount - Remaining) * sizeof(SYSTEM_LOOKASIDE_INFORMATION);
2215 return STATUS_SUCCESS;
2216 }
2217
2218
2219 /* Class 46 - Set time slip event */
2220 SSI_DEF(SystemTimeSlipNotification)
2221 {
2222 /* FIXME */
2223 DPRINT1("NtSetSystemInformation - SystemTimeSlipNotification not implemented\n");
2224 return STATUS_NOT_IMPLEMENTED;
2225 }
2226
2227 NTSTATUS
2228 NTAPI
2229 MmSessionCreate(OUT PULONG SessionId);
2230
2231 NTSTATUS
2232 NTAPI
2233 MmSessionDelete(IN ULONG SessionId);
2234
2235 /* Class 47 - Create a new session (TSE) */
2236 SSI_DEF(SystemSessionCreate)
2237 {
2238 ULONG SessionId;
2239 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2240 NTSTATUS Status;
2241
2242 if (Size != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2243
2244 if (PreviousMode != KernelMode)
2245 {
2246 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2247 {
2248 return STATUS_PRIVILEGE_NOT_HELD;
2249 }
2250
2251 ProbeForWriteUlong(Buffer);
2252 }
2253
2254 Status = MmSessionCreate(&SessionId);
2255 if (NT_SUCCESS(Status)) *(PULONG)Buffer = SessionId;
2256
2257 return Status;
2258 }
2259
2260
2261 /* Class 48 - Delete an existing session (TSE) */
2262 SSI_DEF(SystemSessionDetach)
2263 {
2264 ULONG SessionId;
2265 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2266
2267 if (Size != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2268
2269 if (PreviousMode != KernelMode)
2270 {
2271 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2272 {
2273 return STATUS_PRIVILEGE_NOT_HELD;
2274 }
2275 }
2276
2277 SessionId = *(PULONG)Buffer;
2278
2279 return MmSessionDelete(SessionId);
2280 }
2281
2282
2283 /* Class 49 - UNKNOWN */
2284 QSI_DEF(SystemSessionInformation)
2285 {
2286 /* FIXME */
2287 DPRINT1("NtQuerySystemInformation - SystemSessionInformation not implemented\n");
2288 return STATUS_NOT_IMPLEMENTED;
2289 }
2290
2291
2292 /* Class 50 - System range start address */
2293 QSI_DEF(SystemRangeStartInformation)
2294 {
2295 /* Check user buffer's size */
2296 if (Size != sizeof(ULONG_PTR)) return STATUS_INFO_LENGTH_MISMATCH;
2297
2298 *(PULONG_PTR)Buffer = (ULONG_PTR)MmSystemRangeStart;
2299
2300 if (ReqSize) *ReqSize = sizeof(ULONG_PTR);
2301
2302 return STATUS_SUCCESS;
2303 }
2304
2305 /* Class 51 - Driver verifier information */
2306 QSI_DEF(SystemVerifierInformation)
2307 {
2308 /* FIXME */
2309 DPRINT1("NtQuerySystemInformation - SystemVerifierInformation not implemented\n");
2310 return STATUS_NOT_IMPLEMENTED;
2311 }
2312
2313
2314 SSI_DEF(SystemVerifierInformation)
2315 {
2316 /* FIXME */
2317 DPRINT1("NtSetSystemInformation - SystemVerifierInformation not implemented\n");
2318 return STATUS_NOT_IMPLEMENTED;
2319 }
2320
2321
2322 /* Class 52 */
2323 SSI_DEF(SystemVerifierThunkExtend)
2324 {
2325 /* FIXME */
2326 DPRINT1("NtSetSystemInformation - SystemVerifierThunkExtend not implemented\n");
2327 return STATUS_NOT_IMPLEMENTED;
2328 }
2329
2330
2331 /* Class 53 - A session's processes */
2332 QSI_DEF(SystemSessionProcessesInformation)
2333 {
2334 /* FIXME */
2335 DPRINT1("NtQuerySystemInformation - SystemSessionProcessInformation not implemented\n");
2336 return STATUS_NOT_IMPLEMENTED;
2337 }
2338
2339
2340 /* Class 54 - Load & map in system space */
2341 SSI_DEF(SystemLoadGdiDriverInSystemSpaceInformation)
2342 {
2343 /* FIXME */
2344 DPRINT1("NtSetSystemInformation - SystemLoadGdiDriverInSystemSpaceInformation not implemented\n");
2345 return STATUS_NOT_IMPLEMENTED;
2346 }
2347
2348
2349 /* Class 55 - NUMA processor information */
2350 QSI_DEF(SystemNumaProcessorMap)
2351 {
2352 ULONG MaxEntries, Node;
2353 PSYSTEM_NUMA_INFORMATION NumaInformation = (PSYSTEM_NUMA_INFORMATION)Buffer;
2354
2355 /* Validate input size */
2356 if (Size < sizeof(ULONG))
2357 {
2358 return STATUS_INFO_LENGTH_MISMATCH;
2359 }
2360
2361 /* Return highest node */
2362 NumaInformation->HighestNodeNumber = KeNumberNodes - 1;
2363
2364 /* Compute how much entries we will be able to put in output structure */
2365 MaxEntries = (Size - FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, ActiveProcessorsAffinityMask)) / sizeof(ULONGLONG);
2366 /* Make sure we don't overflow KeNodeBlock */
2367 if (MaxEntries > KeNumberNodes)
2368 {
2369 MaxEntries = KeNumberNodes;
2370 }
2371
2372 /* If we have entries to write, and room for it */
2373 if (Size >= FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, ActiveProcessorsAffinityMask) &&
2374 MaxEntries != 0)
2375 {
2376 /* Already set size we return */
2377 *ReqSize = FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, ActiveProcessorsAffinityMask) +
2378 MaxEntries * sizeof(ULONGLONG);
2379
2380 /* For each node, return processor mask */
2381 for (Node = 0; Node < MaxEntries; ++Node)
2382 {
2383 NumaInformation->ActiveProcessorsAffinityMask[Node] = KeNodeBlock[Node]->ProcessorMask;
2384 }
2385 }
2386 else
2387 {
2388 /* We only returned highest node number */
2389 *ReqSize = sizeof(ULONG);
2390 }
2391
2392 return STATUS_SUCCESS;
2393 }
2394
2395
2396 /* Class 56 - Prefetcher information */
2397 QSI_DEF(SystemPrefetcherInformation)
2398 {
2399 /* FIXME */
2400 DPRINT1("NtQuerySystemInformation - SystemPrefetcherInformation not implemented\n");
2401 return STATUS_NOT_IMPLEMENTED;
2402 }
2403
2404
2405 /* Class 57 - Extended process information */
2406 QSI_DEF(SystemExtendedProcessInformation)
2407 {
2408 /* FIXME */
2409 DPRINT1("NtQuerySystemInformation - SystemExtendedProcessInformation not implemented\n");
2410 return STATUS_NOT_IMPLEMENTED;
2411 }
2412
2413
2414 /* Class 58 - Recommended shared ata alignment */
2415 QSI_DEF(SystemRecommendedSharedDataAlignment)
2416 {
2417 /* FIXME */
2418 DPRINT1("NtQuerySystemInformation - SystemRecommendedSharedDataAlignment not implemented\n");
2419 return STATUS_NOT_IMPLEMENTED;
2420 }
2421
2422
2423 /* Class 60 - NUMA memory information */
2424 QSI_DEF(SystemNumaAvailableMemory)
2425 {
2426 ULONG MaxEntries, Node;
2427 PSYSTEM_NUMA_INFORMATION NumaInformation = (PSYSTEM_NUMA_INFORMATION)Buffer;
2428
2429 /* Validate input size */
2430 if (Size < sizeof(ULONG))
2431 {
2432 return STATUS_INFO_LENGTH_MISMATCH;
2433 }
2434
2435 /* Return highest node */
2436 NumaInformation->HighestNodeNumber = KeNumberNodes - 1;
2437
2438 /* Compute how much entries we will be able to put in output structure */
2439 MaxEntries = (Size - FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, AvailableMemory)) / sizeof(ULONGLONG);
2440 /* Make sure we don't overflow KeNodeBlock */
2441 if (MaxEntries > KeNumberNodes)
2442 {
2443 MaxEntries = KeNumberNodes;
2444 }
2445
2446 /* If we have entries to write, and room for it */
2447 if (Size >= FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, AvailableMemory) &&
2448 MaxEntries != 0)
2449 {
2450 /* Already set size we return */
2451 *ReqSize = FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, AvailableMemory) +
2452 MaxEntries * sizeof(ULONGLONG);
2453
2454 /* If we have a single entry (us), directly return MM information */
2455 if (MaxEntries == 1)
2456 {
2457 NumaInformation->AvailableMemory[0] = MmAvailablePages << PAGE_SHIFT;
2458 }
2459 else
2460 {
2461 /* Otherwise, for each node, return available bytes */
2462 for (Node = 0; Node < MaxEntries; ++Node)
2463 {
2464 NumaInformation->AvailableMemory[Node] = (KeNodeBlock[Node]->FreeCount[0] + KeNodeBlock[Node]->FreeCount[1]) << PAGE_SHIFT;
2465 }
2466 }
2467 }
2468 else
2469 {
2470 /* We only returned highest node number */
2471 *ReqSize = sizeof(ULONG);
2472 }
2473
2474 return STATUS_SUCCESS;
2475 }
2476
2477 /* Class 64 - Extended handle information */
2478 QSI_DEF(SystemExtendedHandleInformation)
2479 {
2480 PSYSTEM_HANDLE_INFORMATION_EX HandleInformation;
2481 PLIST_ENTRY NextTableEntry;
2482 PHANDLE_TABLE HandleTable;
2483 PHANDLE_TABLE_ENTRY HandleTableEntry;
2484 EXHANDLE Handle;
2485 ULONG Index = 0;
2486 NTSTATUS Status;
2487 PMDL Mdl;
2488 PAGED_CODE();
2489
2490 DPRINT("NtQuerySystemInformation - SystemExtendedHandleInformation\n");
2491
2492 /* Set initial required buffer size */
2493 *ReqSize = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handle);
2494
2495 /* Check user's buffer size */
2496 if (Size < *ReqSize)
2497 {
2498 return STATUS_INFO_LENGTH_MISMATCH;
2499 }
2500
2501 /* We need to lock down the memory */
2502 Status = ExLockUserBuffer(Buffer,
2503 Size,
2504 ExGetPreviousMode(),
2505 IoWriteAccess,
2506 (PVOID*)&HandleInformation,
2507 &Mdl);
2508 if (!NT_SUCCESS(Status))
2509 {
2510 DPRINT1("Failed to lock the user buffer: 0x%lx\n", Status);
2511 return Status;
2512 }
2513
2514 /* Reset of count of handles */
2515 HandleInformation->Count = 0;
2516
2517 /* Enter a critical region */
2518 KeEnterCriticalRegion();
2519
2520 /* Acquire the handle table lock */
2521 ExAcquirePushLockShared(&HandleTableListLock);
2522
2523 /* Enumerate all system handles */
2524 for (NextTableEntry = HandleTableListHead.Flink;
2525 NextTableEntry != &HandleTableListHead;
2526 NextTableEntry = NextTableEntry->Flink)
2527 {
2528 /* Get current handle table */
2529 HandleTable = CONTAINING_RECORD(NextTableEntry, HANDLE_TABLE, HandleTableList);
2530
2531 /* Set the initial value and loop the entries */
2532 Handle.Value = 0;
2533 while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle)))
2534 {
2535 /* Validate the entry */
2536 if ((HandleTableEntry->Object) &&
2537 (HandleTableEntry->NextFreeTableEntry != -2))
2538 {
2539 /* Increase of count of handles */
2540 ++HandleInformation->Count;
2541
2542 /* Lock the entry */
2543 if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
2544 {
2545 /* Increase required buffer size */
2546 *ReqSize += sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX);
2547
2548 /* Check user's buffer size */
2549 if (*ReqSize > Size)
2550 {
2551 Status = STATUS_INFO_LENGTH_MISMATCH;
2552 }
2553 else
2554 {
2555 POBJECT_HEADER ObjectHeader = ObpGetHandleObject(HandleTableEntry);
2556
2557 /* Filling handle information */
2558 HandleInformation->Handle[Index].UniqueProcessId =
2559 (USHORT)(ULONG_PTR) HandleTable->UniqueProcessId;
2560
2561 HandleInformation->Handle[Index].CreatorBackTraceIndex = 0;
2562
2563 #if 0 /* FIXME!!! Type field currupted */
2564 HandleInformation->Handles[Index].ObjectTypeIndex =
2565 (UCHAR) ObjectHeader->Type->Index;
2566 #else
2567 HandleInformation->Handle[Index].ObjectTypeIndex = 0;
2568 #endif
2569
2570 HandleInformation->Handle[Index].HandleAttributes =
2571 HandleTableEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
2572
2573 HandleInformation->Handle[Index].HandleValue =
2574 (USHORT)(ULONG_PTR) Handle.GenericHandleOverlay;
2575
2576 HandleInformation->Handle[Index].Object = &ObjectHeader->Body;
2577
2578 HandleInformation->Handle[Index].GrantedAccess =
2579 HandleTableEntry->GrantedAccess;
2580
2581 HandleInformation->Handle[Index].Reserved = 0;
2582
2583 ++Index;
2584 }
2585
2586 /* Unlock it */
2587 ExUnlockHandleTableEntry(HandleTable, HandleTableEntry);
2588 }
2589 }
2590
2591 /* Go to the next entry */
2592 Handle.Value += sizeof(HANDLE);
2593 }
2594 }
2595
2596 /* Release the lock */
2597 ExReleasePushLockShared(&HandleTableListLock);
2598
2599 /* Leave the critical region */
2600 KeLeaveCriticalRegion();
2601
2602 /* Release the locked user buffer */
2603 ExUnlockUserBuffer(Mdl);
2604
2605 return Status;
2606 }
2607
2608 /* Class 76 - System firmware table information */
2609 QSI_DEF(SystemFirmwareTableInformation)
2610 {
2611 PSYSTEM_FIRMWARE_TABLE_INFORMATION SysFirmwareInfo = (PSYSTEM_FIRMWARE_TABLE_INFORMATION)Buffer;
2612 NTSTATUS Status = STATUS_SUCCESS;
2613 ULONG InputBufSize;
2614 ULONG DataSize = 0;
2615 ULONG TableCount = 0;
2616
2617 DPRINT("NtQuerySystemInformation - SystemFirmwareTableInformation\n");
2618
2619 /* Set initial required buffer size */
2620 *ReqSize = FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
2621
2622 /* Check user's buffer size */
2623 if (Size < *ReqSize)
2624 {
2625 return STATUS_INFO_LENGTH_MISMATCH;
2626 }
2627
2628 InputBufSize = SysFirmwareInfo->TableBufferLength;
2629 switch (SysFirmwareInfo->ProviderSignature)
2630 {
2631 /*
2632 * ExpFirmwareTableResource and ExpFirmwareTableProviderListHead
2633 * variables should be used there somehow...
2634 */
2635 case SIG_ACPI:
2636 {
2637 /* FIXME: Not implemented yet */
2638 DPRINT1("ACPI provider not implemented\n");
2639 Status = STATUS_NOT_IMPLEMENTED;
2640 break;
2641 }
2642 case SIG_FIRM:
2643 {
2644 /* FIXME: Not implemented yet */
2645 DPRINT1("FIRM provider not implemented\n");
2646 Status = STATUS_NOT_IMPLEMENTED;
2647 break;
2648 }
2649 case SIG_RSMB:
2650 {
2651 Status = ExpGetRawSMBiosTable(NULL, &DataSize, 0);
2652 if (DataSize > 0)
2653 {
2654 TableCount = 1;
2655 if (SysFirmwareInfo->Action == SystemFirmwareTable_Enumerate)
2656 {
2657 DataSize = TableCount * sizeof(ULONG);
2658 if (DataSize <= InputBufSize)
2659 {
2660 *(ULONG *)SysFirmwareInfo->TableBuffer = 0;
2661 }
2662 }
2663 else if (SysFirmwareInfo->Action == SystemFirmwareTable_Get
2664 && DataSize <= InputBufSize)
2665 {
2666 Status = ExpGetRawSMBiosTable(SysFirmwareInfo->TableBuffer, &DataSize, InputBufSize);
2667 }
2668 SysFirmwareInfo->TableBufferLength = DataSize;
2669 }
2670 break;
2671 }
2672 default:
2673 {
2674 DPRINT1("SystemFirmwareTableInformation: Unsupported provider (0x%x)\n",
2675 SysFirmwareInfo->ProviderSignature);
2676 Status = STATUS_ILLEGAL_FUNCTION;
2677 }
2678 }
2679
2680 if (NT_SUCCESS(Status))
2681 {
2682 switch (SysFirmwareInfo->Action)
2683 {
2684 case SystemFirmwareTable_Enumerate:
2685 case SystemFirmwareTable_Get:
2686 {
2687 if (SysFirmwareInfo->TableBufferLength > InputBufSize)
2688 {
2689 Status = STATUS_BUFFER_TOO_SMALL;
2690 }
2691 break;
2692 }
2693 default:
2694 {
2695 DPRINT1("SystemFirmwareTableInformation: Unsupported action (0x%x)\n",
2696 SysFirmwareInfo->Action);
2697 Status = STATUS_ILLEGAL_FUNCTION;
2698 }
2699 }
2700 }
2701 else
2702 {
2703 SysFirmwareInfo->TableBufferLength = 0;
2704 }
2705 return Status;
2706 }
2707
2708 /* Query/Set Calls Table */
2709 typedef
2710 struct _QSSI_CALLS
2711 {
2712 NTSTATUS (* Query) (PVOID,ULONG,PULONG);
2713 NTSTATUS (* Set) (PVOID,ULONG);
2714 } QSSI_CALLS;
2715
2716 // QS Query & Set
2717 // QX Query
2718 // XS Set
2719 // XX unknown behaviour
2720 //
2721 #define SI_QS(n) {QSI_USE(n),SSI_USE(n)}
2722 #define SI_QX(n) {QSI_USE(n),NULL}
2723 #define SI_XS(n) {NULL,SSI_USE(n)}
2724 #define SI_XX(n) {NULL,NULL}
2725
2726 static
2727 QSSI_CALLS
2728 CallQS [] =
2729 {
2730 SI_QX(SystemBasicInformation),
2731 SI_QX(SystemProcessorInformation),
2732 SI_QX(SystemPerformanceInformation),
2733 SI_QX(SystemTimeOfDayInformation),
2734 SI_QX(SystemPathInformation), /* should be SI_XX */
2735 SI_QX(SystemProcessInformation),
2736 SI_QX(SystemCallCountInformation),
2737 SI_QX(SystemDeviceInformation),
2738 SI_QX(SystemProcessorPerformanceInformation),
2739 SI_QS(SystemFlagsInformation),
2740 SI_QX(SystemCallTimeInformation), /* should be SI_XX */
2741 SI_QX(SystemModuleInformation),
2742 SI_QX(SystemLocksInformation),
2743 SI_QX(SystemStackTraceInformation), /* should be SI_XX */
2744 SI_QX(SystemPagedPoolInformation), /* should be SI_XX */
2745 SI_QX(SystemNonPagedPoolInformation), /* should be SI_XX */
2746 SI_QX(SystemHandleInformation),
2747 SI_QX(SystemObjectInformation),
2748 SI_QX(SystemPageFileInformation),
2749 SI_QX(SystemVdmInstemulInformation),
2750 SI_QX(SystemVdmBopInformation), /* it should be SI_XX */
2751 SI_QS(SystemFileCacheInformation),
2752 SI_QX(SystemPoolTagInformation),
2753 SI_QX(SystemInterruptInformation),
2754 SI_QS(SystemDpcBehaviourInformation),
2755 SI_QX(SystemFullMemoryInformation), /* it should be SI_XX */
2756 SI_XS(SystemLoadGdiDriverInformation),
2757 SI_XS(SystemUnloadGdiDriverInformation),
2758 SI_QS(SystemTimeAdjustmentInformation),
2759 SI_QX(SystemSummaryMemoryInformation), /* it should be SI_XX */
2760 SI_QX(SystemNextEventIdInformation), /* it should be SI_XX */
2761 SI_QX(SystemPerformanceTraceInformation), /* it should be SI_XX */
2762 SI_QX(SystemCrashDumpInformation),
2763 SI_QX(SystemExceptionInformation),
2764 SI_QX(SystemCrashDumpStateInformation),
2765 SI_QX(SystemKernelDebuggerInformation),
2766 SI_QX(SystemContextSwitchInformation),
2767 SI_QS(SystemRegistryQuotaInformation),
2768 SI_XS(SystemExtendServiceTableInformation),
2769 SI_XS(SystemPrioritySeperation),
2770 SI_QX(SystemVerifierAddDriverInformation), /* it should be SI_XX */
2771 SI_QX(SystemVerifierRemoveDriverInformation), /* it should be SI_XX */
2772 SI_QX(SystemProcessorIdleInformation), /* it should be SI_XX */
2773 SI_QX(SystemLegacyDriverInformation), /* it should be SI_XX */
2774 SI_QS(SystemCurrentTimeZoneInformation), /* it should be SI_QX */
2775 SI_QX(SystemLookasideInformation),
2776 SI_XS(SystemTimeSlipNotification),
2777 SI_XS(SystemSessionCreate),
2778 SI_XS(SystemSessionDetach),
2779 SI_QX(SystemSessionInformation), /* it should be SI_XX */
2780 SI_QX(SystemRangeStartInformation),
2781 SI_QS(SystemVerifierInformation),
2782 SI_XS(SystemVerifierThunkExtend),
2783 SI_QX(SystemSessionProcessesInformation),
2784 SI_XS(SystemLoadGdiDriverInSystemSpaceInformation),
2785 SI_QX(SystemNumaProcessorMap),
2786 SI_QX(SystemPrefetcherInformation),
2787 SI_QX(SystemExtendedProcessInformation),
2788 SI_QX(SystemRecommendedSharedDataAlignment),
2789 SI_XX(SystemComPlusPackage),
2790 SI_QX(SystemNumaAvailableMemory),
2791 SI_XX(SystemProcessorPowerInformation), /* FIXME: not implemented */
2792 SI_XX(SystemEmulationBasicInformation), /* FIXME: not implemented */
2793 SI_XX(SystemEmulationProcessorInformation), /* FIXME: not implemented */
2794 SI_QX(SystemExtendedHandleInformation),
2795 SI_XX(SystemLostDelayedWriteInformation), /* FIXME: not implemented */
2796 SI_XX(SystemBigPoolInformation), /* FIXME: not implemented */
2797 SI_XX(SystemSessionPoolTagInformation), /* FIXME: not implemented */
2798 SI_XX(SystemSessionMappedViewInformation), /* FIXME: not implemented */
2799 SI_XX(SystemHotpatchInformation), /* FIXME: not implemented */
2800 SI_XX(SystemObjectSecurityMode), /* FIXME: not implemented */
2801 SI_XX(SystemWatchdogTimerHandler), /* FIXME: not implemented */
2802 SI_XX(SystemWatchdogTimerInformation), /* FIXME: not implemented */
2803 SI_XX(SystemLogicalProcessorInformation), /* FIXME: not implemented */
2804 SI_XX(SystemWow64SharedInformation), /* FIXME: not implemented */
2805 SI_XX(SystemRegisterFirmwareTableInformationHandler), /* FIXME: not implemented */
2806 SI_QX(SystemFirmwareTableInformation),
2807 };
2808
2809 C_ASSERT(SystemBasicInformation == 0);
2810 #define MIN_SYSTEM_INFO_CLASS (SystemBasicInformation)
2811 #define MAX_SYSTEM_INFO_CLASS (sizeof(CallQS) / sizeof(CallQS[0]))
2812
2813 /*
2814 * @implemented
2815 */
2816 __kernel_entry
2817 NTSTATUS
2818 NTAPI
2819 NtQuerySystemInformation(
2820 _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
2821 _Out_writes_bytes_to_opt_(SystemInformationLength, *ReturnLength) PVOID SystemInformation,
2822 _In_ ULONG Length,
2823 _Out_opt_ PULONG UnsafeResultLength)
2824 {
2825 KPROCESSOR_MODE PreviousMode;
2826 ULONG ResultLength = 0;
2827 ULONG Alignment = TYPE_ALIGNMENT(ULONG);
2828 NTSTATUS FStatus = STATUS_NOT_IMPLEMENTED;
2829
2830 PAGED_CODE();
2831
2832 PreviousMode = ExGetPreviousMode();
2833
2834 _SEH2_TRY
2835 {
2836 #if (NTDDI_VERSION >= NTDDI_VISTA)
2837 /*
2838 * Check if the request is valid.
2839 */
2840 if (SystemInformationClass >= MAX_SYSTEM_INFO_CLASS)
2841 {
2842 _SEH2_YIELD(return STATUS_INVALID_INFO_CLASS);
2843 }
2844 #endif
2845
2846 if (PreviousMode != KernelMode)
2847 {
2848 /* SystemKernelDebuggerInformation needs only BOOLEAN alignment */
2849 if (SystemInformationClass == SystemKernelDebuggerInformation)
2850 Alignment = TYPE_ALIGNMENT(BOOLEAN);
2851
2852 ProbeForWrite(SystemInformation, Length, Alignment);
2853 if (UnsafeResultLength != NULL)
2854 ProbeForWriteUlong(UnsafeResultLength);
2855 }
2856
2857 if (UnsafeResultLength)
2858 *UnsafeResultLength = 0;
2859
2860 #if (NTDDI_VERSION < NTDDI_VISTA)
2861 /*
2862 * Check if the request is valid.
2863 */
2864 if (SystemInformationClass >= MAX_SYSTEM_INFO_CLASS)
2865 {
2866 _SEH2_YIELD(return STATUS_INVALID_INFO_CLASS);
2867 }
2868 #endif
2869
2870 if (NULL != CallQS [SystemInformationClass].Query)
2871 {
2872 /*
2873 * Hand the request to a subhandler.
2874 */
2875 FStatus = CallQS [SystemInformationClass].Query(SystemInformation,
2876 Length,
2877 &ResultLength);
2878
2879 /* Save the result length to the caller */
2880 if (UnsafeResultLength)
2881 *UnsafeResultLength = ResultLength;
2882 }
2883 }
2884 _SEH2_EXCEPT(ExSystemExceptionFilter())
2885 {
2886 FStatus = _SEH2_GetExceptionCode();
2887 }
2888 _SEH2_END;
2889
2890 return FStatus;
2891 }
2892
2893
2894 NTSTATUS
2895 NTAPI
2896 NtSetSystemInformation (IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
2897 IN PVOID SystemInformation,
2898 IN ULONG SystemInformationLength)
2899 {
2900 NTSTATUS Status = STATUS_INVALID_INFO_CLASS;
2901 KPROCESSOR_MODE PreviousMode;
2902
2903 PAGED_CODE();
2904
2905 PreviousMode = ExGetPreviousMode();
2906
2907 _SEH2_TRY
2908 {
2909 /*
2910 * If called from user mode, check
2911 * possible unsafe arguments.
2912 */
2913 if (PreviousMode != KernelMode)
2914 {
2915 ProbeForRead(SystemInformation, SystemInformationLength, sizeof(ULONG));
2916 }
2917
2918 /*
2919 * Check the request is valid.
2920 */
2921 if ((SystemInformationClass >= MIN_SYSTEM_INFO_CLASS) &&
2922 (SystemInformationClass < MAX_SYSTEM_INFO_CLASS))
2923 {
2924 if (NULL != CallQS [SystemInformationClass].Set)
2925 {
2926 /*
2927 * Hand the request to a subhandler.
2928 */
2929 Status = CallQS [SystemInformationClass].Set(SystemInformation,
2930 SystemInformationLength);
2931 }
2932 }
2933 }
2934 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2935 {
2936 Status = _SEH2_GetExceptionCode();
2937 }
2938 _SEH2_END;
2939
2940 return Status;
2941 }
2942
2943 ULONG
2944 NTAPI
2945 NtGetCurrentProcessorNumber(VOID)
2946 {
2947 /* Just use Ke */
2948 return KeGetCurrentProcessorNumber();
2949 }
2950
2951 #undef ExGetPreviousMode
2952 KPROCESSOR_MODE
2953 NTAPI
2954 ExGetPreviousMode(VOID)
2955 {
2956 /* Just use Ke */
2957 return KeGetPreviousMode();
2958 }