[NTOS:EX] Implement SystemFirmwareTableInformation class
[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 ULONG IdleUser, IdleKernel;
673 PSYSTEM_PERFORMANCE_INFORMATION Spi
674 = (PSYSTEM_PERFORMANCE_INFORMATION) Buffer;
675
676 PEPROCESS TheIdleProcess;
677
678 *ReqSize = sizeof(SYSTEM_PERFORMANCE_INFORMATION);
679
680 /* Check user buffer's size */
681 if (Size < sizeof(SYSTEM_PERFORMANCE_INFORMATION))
682 {
683 return STATUS_INFO_LENGTH_MISMATCH;
684 }
685
686 TheIdleProcess = PsIdleProcess;
687
688 IdleKernel = KeQueryRuntimeProcess(&TheIdleProcess->Pcb, &IdleUser);
689 Spi->IdleProcessTime.QuadPart = UInt32x32To64(IdleKernel, KeMaximumIncrement);
690 Spi->IoReadTransferCount = IoReadTransferCount;
691 Spi->IoWriteTransferCount = IoWriteTransferCount;
692 Spi->IoOtherTransferCount = IoOtherTransferCount;
693 Spi->IoReadOperationCount = IoReadOperationCount;
694 Spi->IoWriteOperationCount = IoWriteOperationCount;
695 Spi->IoOtherOperationCount = IoOtherOperationCount;
696
697 Spi->AvailablePages = (ULONG)MmAvailablePages;
698 /*
699 * Add up all the used "Committed" memory + pagefile.
700 * Not sure this is right. 8^\
701 */
702 Spi->CommittedPages = MiMemoryConsumers[MC_SYSTEM].PagesUsed +
703 MiMemoryConsumers[MC_CACHE].PagesUsed +
704 MiMemoryConsumers[MC_USER].PagesUsed +
705 MiUsedSwapPages;
706 /*
707 * Add up the full system total + pagefile.
708 * All this make Taskmgr happy but not sure it is the right numbers.
709 * This too, fixes some of GlobalMemoryStatusEx numbers.
710 */
711 Spi->CommitLimit = MmNumberOfPhysicalPages + MiFreeSwapPages + MiUsedSwapPages;
712
713 Spi->PeakCommitment = 0; /* FIXME */
714 Spi->PageFaultCount = 0; /* FIXME */
715 Spi->CopyOnWriteCount = 0; /* FIXME */
716 Spi->TransitionCount = 0; /* FIXME */
717 Spi->CacheTransitionCount = 0; /* FIXME */
718 Spi->DemandZeroCount = 0; /* FIXME */
719 Spi->PageReadCount = 0; /* FIXME */
720 Spi->PageReadIoCount = 0; /* FIXME */
721 Spi->CacheReadCount = 0; /* FIXME */
722 Spi->CacheIoCount = 0; /* FIXME */
723 Spi->DirtyPagesWriteCount = 0; /* FIXME */
724 Spi->DirtyWriteIoCount = 0; /* FIXME */
725 Spi->MappedPagesWriteCount = 0; /* FIXME */
726 Spi->MappedWriteIoCount = 0; /* FIXME */
727
728 Spi->PagedPoolPages = 0;
729 Spi->NonPagedPoolPages = 0;
730 Spi->PagedPoolAllocs = 0;
731 Spi->PagedPoolFrees = 0;
732 Spi->PagedPoolLookasideHits = 0;
733 Spi->NonPagedPoolAllocs = 0;
734 Spi->NonPagedPoolFrees = 0;
735 Spi->NonPagedPoolLookasideHits = 0;
736 ExQueryPoolUsage(&Spi->PagedPoolPages,
737 &Spi->NonPagedPoolPages,
738 &Spi->PagedPoolAllocs,
739 &Spi->PagedPoolFrees,
740 &Spi->PagedPoolLookasideHits,
741 &Spi->NonPagedPoolAllocs,
742 &Spi->NonPagedPoolFrees,
743 &Spi->NonPagedPoolLookasideHits);
744 Spi->FreeSystemPtes = 0; /* FIXME */
745
746 Spi->ResidentSystemCodePage = 0; /* FIXME */
747
748 Spi->TotalSystemDriverPages = 0; /* FIXME */
749 Spi->Spare3Count = 0; /* FIXME */
750
751 Spi->ResidentSystemCachePage = MiMemoryConsumers[MC_CACHE].PagesUsed;
752 Spi->ResidentPagedPoolPage = 0; /* FIXME */
753
754 Spi->ResidentSystemDriverPage = 0; /* FIXME */
755 Spi->CcFastReadNoWait = 0; /* FIXME */
756 Spi->CcFastReadWait = 0; /* FIXME */
757 Spi->CcFastReadResourceMiss = 0; /* FIXME */
758 Spi->CcFastReadNotPossible = 0; /* FIXME */
759
760 Spi->CcFastMdlReadNoWait = 0; /* FIXME */
761 Spi->CcFastMdlReadWait = 0; /* FIXME */
762 Spi->CcFastMdlReadResourceMiss = 0; /* FIXME */
763 Spi->CcFastMdlReadNotPossible = 0; /* FIXME */
764
765 Spi->CcMapDataNoWait = CcMapDataNoWait;
766 Spi->CcMapDataWait = CcMapDataWait;
767 Spi->CcMapDataNoWaitMiss = 0; /* FIXME */
768 Spi->CcMapDataWaitMiss = 0; /* FIXME */
769
770 Spi->CcPinMappedDataCount = 0; /* FIXME */
771 Spi->CcPinReadNoWait = CcPinReadNoWait;
772 Spi->CcPinReadWait = CcPinReadWait;
773 Spi->CcPinReadNoWaitMiss = 0; /* FIXME */
774 Spi->CcPinReadWaitMiss = 0; /* FIXME */
775 Spi->CcCopyReadNoWait = 0; /* FIXME */
776 Spi->CcCopyReadWait = 0; /* FIXME */
777 Spi->CcCopyReadNoWaitMiss = 0; /* FIXME */
778 Spi->CcCopyReadWaitMiss = 0; /* FIXME */
779
780 Spi->CcMdlReadNoWait = 0; /* FIXME */
781 Spi->CcMdlReadWait = 0; /* FIXME */
782 Spi->CcMdlReadNoWaitMiss = 0; /* FIXME */
783 Spi->CcMdlReadWaitMiss = 0; /* FIXME */
784 Spi->CcReadAheadIos = 0; /* FIXME */
785 Spi->CcLazyWriteIos = CcLazyWriteIos;
786 Spi->CcLazyWritePages = CcLazyWritePages;
787 Spi->CcDataFlushes = CcDataFlushes;
788 Spi->CcDataPages = CcDataPages;
789 Spi->ContextSwitches = 0; /* FIXME */
790 Spi->FirstLevelTbFills = 0; /* FIXME */
791 Spi->SecondLevelTbFills = 0; /* FIXME */
792 Spi->SystemCalls = 0; /* FIXME */
793
794 return STATUS_SUCCESS;
795 }
796
797 /* Class 3 - Time Of Day Information */
798 QSI_DEF(SystemTimeOfDayInformation)
799 {
800 SYSTEM_TIMEOFDAY_INFORMATION Sti;
801 LARGE_INTEGER CurrentTime;
802
803 /* Set amount of written information to 0 */
804 *ReqSize = 0;
805
806 /* Check user buffer's size */
807 if (Size > sizeof(SYSTEM_TIMEOFDAY_INFORMATION))
808 {
809 return STATUS_INFO_LENGTH_MISMATCH;
810 }
811
812 /* Get current time */
813 KeQuerySystemTime(&CurrentTime);
814
815 /* Zero local buffer */
816 RtlZeroMemory(&Sti, sizeof(SYSTEM_TIMEOFDAY_INFORMATION));
817
818 /* Fill local time structure */
819 Sti.BootTime= KeBootTime;
820 Sti.CurrentTime = CurrentTime;
821 Sti.TimeZoneBias.QuadPart = ExpTimeZoneBias.QuadPart;
822 Sti.TimeZoneId = ExpTimeZoneId;
823 Sti.Reserved = 0;
824
825 /* Copy as much as requested by caller */
826 RtlCopyMemory(Buffer, &Sti, Size);
827
828 /* Set amount of information we copied */
829 *ReqSize = Size;
830
831 return STATUS_SUCCESS;
832 }
833
834 /* Class 4 - Path Information */
835 QSI_DEF(SystemPathInformation)
836 {
837 /* FIXME: QSI returns STATUS_BREAKPOINT. Why? */
838 DPRINT1("NtQuerySystemInformation - SystemPathInformation not implemented\n");
839
840 return STATUS_BREAKPOINT;
841 }
842
843 /* Class 5 - Process Information */
844 QSI_DEF(SystemProcessInformation)
845 {
846 PSYSTEM_PROCESS_INFORMATION SpiCurrent;
847 PSYSTEM_THREAD_INFORMATION ThreadInfo;
848 PEPROCESS Process = NULL, SystemProcess;
849 PETHREAD CurrentThread;
850 ANSI_STRING ImageName;
851 ULONG CurrentSize;
852 USHORT ImageNameMaximumLength; // image name length in bytes
853 USHORT ImageNameLength;
854 PLIST_ENTRY CurrentEntry;
855 ULONG TotalSize = 0, ThreadsCount;
856 ULONG TotalUser, TotalKernel;
857 PUCHAR Current;
858 NTSTATUS Status = STATUS_SUCCESS;
859 PUNICODE_STRING TempProcessImageName;
860 _SEH2_VOLATILE PUNICODE_STRING ProcessImageName = NULL;
861 PWCHAR szSrc;
862 BOOLEAN Overflow = FALSE;
863
864 _SEH2_TRY
865 {
866 /* scan the process list */
867
868 PSYSTEM_PROCESS_INFORMATION Spi
869 = (PSYSTEM_PROCESS_INFORMATION) Buffer;
870
871 *ReqSize = sizeof(SYSTEM_PROCESS_INFORMATION);
872
873 /* Check for overflow */
874 if (Size < sizeof(SYSTEM_PROCESS_INFORMATION))
875 {
876 Overflow = TRUE;
877 }
878
879 /* Zero user's buffer */
880 if (!Overflow) RtlZeroMemory(Spi, Size);
881
882 SystemProcess = PsIdleProcess;
883 Process = SystemProcess;
884 Current = (PUCHAR) Spi;
885
886 do
887 {
888 SpiCurrent = (PSYSTEM_PROCESS_INFORMATION) Current;
889
890 /* Lock the Process */
891 KeEnterCriticalRegion();
892 ExAcquirePushLockShared(&Process->ProcessLock);
893
894 if ((Process->ProcessExiting) &&
895 (Process->Pcb.Header.SignalState) &&
896 !(Process->ActiveThreads) &&
897 (IsListEmpty(&Process->Pcb.ThreadListHead)))
898 {
899 DPRINT1("Process %p (%s:%p) is a zombie\n",
900 Process, Process->ImageFileName, Process->UniqueProcessId);
901 CurrentSize = 0;
902 ImageNameMaximumLength = 0;
903
904 /* Unlock the Process */
905 ExReleasePushLockShared(&Process->ProcessLock);
906 KeLeaveCriticalRegion();
907 goto Skip;
908 }
909
910 ThreadsCount = 0;
911 CurrentEntry = Process->Pcb.ThreadListHead.Flink;
912 while (CurrentEntry != &Process->Pcb.ThreadListHead)
913 {
914 ThreadsCount++;
915 CurrentEntry = CurrentEntry->Flink;
916 }
917
918 // size of the structure for every process
919 CurrentSize = sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_THREAD_INFORMATION) * ThreadsCount;
920 ImageNameLength = 0;
921 Status = SeLocateProcessImageName(Process, &TempProcessImageName);
922 ProcessImageName = TempProcessImageName;
923 szSrc = NULL;
924 if (NT_SUCCESS(Status) && (ProcessImageName->Length > 0))
925 {
926 szSrc = (PWCHAR)((PCHAR)ProcessImageName->Buffer + ProcessImageName->Length);
927 /* Loop the file name*/
928 while (szSrc > ProcessImageName->Buffer)
929 {
930 /* Make sure this isn't a backslash */
931 if (*--szSrc == OBJ_NAME_PATH_SEPARATOR)
932 {
933 szSrc++;
934 break;
935 }
936 else
937 {
938 ImageNameLength += sizeof(WCHAR);
939 }
940 }
941 }
942 if (!ImageNameLength && Process != PsIdleProcess)
943 {
944 ImageNameLength = (USHORT)strlen(Process->ImageFileName) * sizeof(WCHAR);
945 }
946
947 /* Round up the image name length as NT does */
948 if (ImageNameLength > 0)
949 ImageNameMaximumLength = ROUND_UP(ImageNameLength + sizeof(WCHAR), 8);
950 else
951 ImageNameMaximumLength = 0;
952
953 TotalSize += CurrentSize + ImageNameMaximumLength;
954
955 /* Check for overflow */
956 if (TotalSize > Size)
957 {
958 Overflow = TRUE;
959 }
960
961 /* Fill system information */
962 if (!Overflow)
963 {
964 SpiCurrent->NextEntryOffset = CurrentSize + ImageNameMaximumLength; // relative offset to the beginning of the next structure
965 SpiCurrent->NumberOfThreads = ThreadsCount;
966 SpiCurrent->CreateTime = Process->CreateTime;
967 SpiCurrent->ImageName.Length = ImageNameLength;
968 SpiCurrent->ImageName.MaximumLength = ImageNameMaximumLength;
969 SpiCurrent->ImageName.Buffer = (void*)(Current + CurrentSize);
970
971 /* Copy name to the end of the struct */
972 if(Process != PsIdleProcess)
973 {
974 if (szSrc)
975 {
976 RtlCopyMemory(SpiCurrent->ImageName.Buffer, szSrc, SpiCurrent->ImageName.Length);
977 }
978 else
979 {
980 RtlInitAnsiString(&ImageName, Process->ImageFileName);
981 RtlAnsiStringToUnicodeString(&SpiCurrent->ImageName, &ImageName, FALSE);
982 }
983 }
984 else
985 {
986 RtlInitUnicodeString(&SpiCurrent->ImageName, NULL);
987 }
988
989 SpiCurrent->BasePriority = Process->Pcb.BasePriority;
990 SpiCurrent->UniqueProcessId = Process->UniqueProcessId;
991 SpiCurrent->InheritedFromUniqueProcessId = Process->InheritedFromUniqueProcessId;
992 SpiCurrent->HandleCount = ObGetProcessHandleCount(Process);
993 SpiCurrent->PeakVirtualSize = Process->PeakVirtualSize;
994 SpiCurrent->VirtualSize = Process->VirtualSize;
995 SpiCurrent->PageFaultCount = Process->Vm.PageFaultCount;
996 SpiCurrent->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
997 SpiCurrent->WorkingSetSize = Process->Vm.WorkingSetSize;
998 SpiCurrent->QuotaPeakPagedPoolUsage = Process->QuotaPeak[0];
999 SpiCurrent->QuotaPagedPoolUsage = Process->QuotaUsage[0];
1000 SpiCurrent->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[1];
1001 SpiCurrent->QuotaNonPagedPoolUsage = Process->QuotaUsage[1];
1002 SpiCurrent->PagefileUsage = Process->QuotaUsage[2];
1003 SpiCurrent->PeakPagefileUsage = Process->QuotaPeak[2];
1004 SpiCurrent->PrivatePageCount = Process->CommitCharge;
1005 ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(SpiCurrent + 1);
1006
1007 CurrentEntry = Process->Pcb.ThreadListHead.Flink;
1008 while (CurrentEntry != &Process->Pcb.ThreadListHead)
1009 {
1010 CurrentThread = CONTAINING_RECORD(CurrentEntry, ETHREAD, Tcb.ThreadListEntry);
1011
1012 ThreadInfo->KernelTime.QuadPart = UInt32x32To64(CurrentThread->Tcb.KernelTime, KeMaximumIncrement);
1013 ThreadInfo->UserTime.QuadPart = UInt32x32To64(CurrentThread->Tcb.UserTime, KeMaximumIncrement);
1014 ThreadInfo->CreateTime.QuadPart = CurrentThread->CreateTime.QuadPart;
1015 ThreadInfo->WaitTime = CurrentThread->Tcb.WaitTime;
1016 ThreadInfo->StartAddress = (PVOID) CurrentThread->StartAddress;
1017 ThreadInfo->ClientId = CurrentThread->Cid;
1018 ThreadInfo->Priority = CurrentThread->Tcb.Priority;
1019 ThreadInfo->BasePriority = CurrentThread->Tcb.BasePriority;
1020 ThreadInfo->ContextSwitches = CurrentThread->Tcb.ContextSwitches;
1021 ThreadInfo->ThreadState = CurrentThread->Tcb.State;
1022 ThreadInfo->WaitReason = CurrentThread->Tcb.WaitReason;
1023
1024 ThreadInfo++;
1025 CurrentEntry = CurrentEntry->Flink;
1026 }
1027
1028 /* Query total user/kernel times of a process */
1029 TotalKernel = KeQueryRuntimeProcess(&Process->Pcb, &TotalUser);
1030 SpiCurrent->UserTime.QuadPart = UInt32x32To64(TotalUser, KeMaximumIncrement);
1031 SpiCurrent->KernelTime.QuadPart = UInt32x32To64(TotalKernel, KeMaximumIncrement);
1032 }
1033
1034 if (ProcessImageName)
1035 {
1036 /* Release the memory allocated by SeLocateProcessImageName */
1037 ExFreePoolWithTag(ProcessImageName, TAG_SEPA);
1038 ProcessImageName = NULL;
1039 }
1040
1041 /* Unlock the Process */
1042 ExReleasePushLockShared(&Process->ProcessLock);
1043 KeLeaveCriticalRegion();
1044
1045 /* Handle idle process entry */
1046 Skip:
1047 if (Process == PsIdleProcess) Process = NULL;
1048
1049 Process = PsGetNextProcess(Process);
1050 ThreadsCount = 0;
1051 if ((Process == SystemProcess) || (Process == NULL))
1052 {
1053 if (!Overflow)
1054 SpiCurrent->NextEntryOffset = 0;
1055 break;
1056 }
1057 else
1058 Current += CurrentSize + ImageNameMaximumLength;
1059 } while ((Process != SystemProcess) && (Process != NULL));
1060
1061 if(Process != NULL)
1062 ObDereferenceObject(Process);
1063 Status = STATUS_SUCCESS;
1064 }
1065 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1066 {
1067 if(Process != NULL)
1068 ObDereferenceObject(Process);
1069 if (ProcessImageName)
1070 {
1071 /* Release the memory allocated by SeLocateProcessImageName */
1072 ExFreePoolWithTag(ProcessImageName, TAG_SEPA);
1073 }
1074
1075 Status = _SEH2_GetExceptionCode();
1076 }
1077 _SEH2_END
1078
1079 if (Overflow)
1080 Status = STATUS_INFO_LENGTH_MISMATCH;
1081
1082 *ReqSize = TotalSize;
1083 return Status;
1084 }
1085
1086 /* Class 6 - Call Count Information */
1087 QSI_DEF(SystemCallCountInformation)
1088 {
1089 /* FIXME */
1090 DPRINT1("NtQuerySystemInformation - SystemCallCountInformation not implemented\n");
1091 return STATUS_NOT_IMPLEMENTED;
1092 }
1093
1094 /* Class 7 - Device Information */
1095 QSI_DEF(SystemDeviceInformation)
1096 {
1097 PSYSTEM_DEVICE_INFORMATION Sdi
1098 = (PSYSTEM_DEVICE_INFORMATION) Buffer;
1099 PCONFIGURATION_INFORMATION ConfigInfo;
1100
1101 *ReqSize = sizeof(SYSTEM_DEVICE_INFORMATION);
1102
1103 /* Check user buffer's size */
1104 if (Size < sizeof(SYSTEM_DEVICE_INFORMATION))
1105 {
1106 return STATUS_INFO_LENGTH_MISMATCH;
1107 }
1108
1109 ConfigInfo = IoGetConfigurationInformation();
1110
1111 Sdi->NumberOfDisks = ConfigInfo->DiskCount;
1112 Sdi->NumberOfFloppies = ConfigInfo->FloppyCount;
1113 Sdi->NumberOfCdRoms = ConfigInfo->CdRomCount;
1114 Sdi->NumberOfTapes = ConfigInfo->TapeCount;
1115 Sdi->NumberOfSerialPorts = ConfigInfo->SerialCount;
1116 Sdi->NumberOfParallelPorts = ConfigInfo->ParallelCount;
1117
1118 return STATUS_SUCCESS;
1119 }
1120
1121 /* Class 8 - Processor Performance Information */
1122 QSI_DEF(SystemProcessorPerformanceInformation)
1123 {
1124 PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION Spi
1125 = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) Buffer;
1126
1127 LONG i;
1128 ULONG TotalTime;
1129 PKPRCB Prcb;
1130
1131 *ReqSize = KeNumberProcessors * sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
1132
1133 /* Check user buffer's size */
1134 if (Size < *ReqSize)
1135 {
1136 return STATUS_INFO_LENGTH_MISMATCH;
1137 }
1138
1139 for (i = 0; i < KeNumberProcessors; i++)
1140 {
1141 /* Get the PRCB on this processor */
1142 Prcb = KiProcessorBlock[i];
1143
1144 /* Calculate total user and kernel times */
1145 TotalTime = Prcb->IdleThread->KernelTime + Prcb->IdleThread->UserTime;
1146 Spi->IdleTime.QuadPart = UInt32x32To64(TotalTime, KeMaximumIncrement);
1147 Spi->KernelTime.QuadPart = UInt32x32To64(Prcb->KernelTime, KeMaximumIncrement);
1148 Spi->UserTime.QuadPart = UInt32x32To64(Prcb->UserTime, KeMaximumIncrement);
1149 Spi->DpcTime.QuadPart = UInt32x32To64(Prcb->DpcTime, KeMaximumIncrement);
1150 Spi->InterruptTime.QuadPart = UInt32x32To64(Prcb->InterruptTime, KeMaximumIncrement);
1151 Spi->InterruptCount = Prcb->InterruptCount;
1152 Spi++;
1153 }
1154
1155 return STATUS_SUCCESS;
1156 }
1157
1158 /* Class 9 - Flags Information */
1159 QSI_DEF(SystemFlagsInformation)
1160 {
1161 #if (NTDDI_VERSION >= NTDDI_VISTA)
1162 *ReqSize = sizeof(SYSTEM_FLAGS_INFORMATION);
1163 #endif
1164
1165 if (sizeof(SYSTEM_FLAGS_INFORMATION) != Size)
1166 {
1167 return STATUS_INFO_LENGTH_MISMATCH;
1168 }
1169
1170 ((PSYSTEM_FLAGS_INFORMATION) Buffer)->Flags = NtGlobalFlag;
1171 #if (NTDDI_VERSION < NTDDI_VISTA)
1172 *ReqSize = sizeof(SYSTEM_FLAGS_INFORMATION);
1173 #endif
1174
1175 return STATUS_SUCCESS;
1176 }
1177
1178 SSI_DEF(SystemFlagsInformation)
1179 {
1180 if (sizeof(SYSTEM_FLAGS_INFORMATION) != Size)
1181 {
1182 return STATUS_INFO_LENGTH_MISMATCH;
1183 }
1184
1185 if (!SeSinglePrivilegeCheck(SeDebugPrivilege, ExGetPreviousMode()))
1186 {
1187 return STATUS_ACCESS_DENIED;
1188 }
1189
1190 NtGlobalFlag = ((PSYSTEM_FLAGS_INFORMATION) Buffer)->Flags;
1191 return STATUS_SUCCESS;
1192 }
1193
1194 /* Class 10 - Call Time Information */
1195 QSI_DEF(SystemCallTimeInformation)
1196 {
1197 /* FIXME */
1198 DPRINT1("NtQuerySystemInformation - SystemCallTimeInformation not implemented\n");
1199 return STATUS_NOT_IMPLEMENTED;
1200 }
1201
1202 /* Class 11 - Module Information */
1203 QSI_DEF(SystemModuleInformation)
1204 {
1205 NTSTATUS Status;
1206
1207 /* Acquire system module list lock */
1208 KeEnterCriticalRegion();
1209 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource, TRUE);
1210
1211 /* Call the generic handler with the system module list */
1212 Status = ExpQueryModuleInformation(&PsLoadedModuleList,
1213 &MmLoadedUserImageList,
1214 (PRTL_PROCESS_MODULES)Buffer,
1215 Size,
1216 ReqSize);
1217
1218 /* Release list lock and return status */
1219 ExReleaseResourceLite(&PsLoadedModuleResource);
1220 KeLeaveCriticalRegion();
1221 return Status;
1222 }
1223
1224 /* Class 12 - Locks Information */
1225 QSI_DEF(SystemLocksInformation)
1226 {
1227 /* FIXME */
1228 DPRINT1("NtQuerySystemInformation - SystemLocksInformation not implemented\n");
1229 return STATUS_NOT_IMPLEMENTED;
1230 }
1231
1232 /* Class 13 - Stack Trace Information */
1233 QSI_DEF(SystemStackTraceInformation)
1234 {
1235 /* FIXME */
1236 DPRINT1("NtQuerySystemInformation - SystemStackTraceInformation not implemented\n");
1237 return STATUS_NOT_IMPLEMENTED;
1238 }
1239
1240 /* Class 14 - Paged Pool Information */
1241 QSI_DEF(SystemPagedPoolInformation)
1242 {
1243 /* FIXME */
1244 DPRINT1("NtQuerySystemInformation - SystemPagedPoolInformation not implemented\n");
1245 return STATUS_NOT_IMPLEMENTED;
1246 }
1247
1248 /* Class 15 - Non Paged Pool Information */
1249 QSI_DEF(SystemNonPagedPoolInformation)
1250 {
1251 /* FIXME */
1252 DPRINT1("NtQuerySystemInformation - SystemNonPagedPoolInformation not implemented\n");
1253 return STATUS_NOT_IMPLEMENTED;
1254 }
1255
1256
1257 /* Class 16 - Handle Information */
1258 QSI_DEF(SystemHandleInformation)
1259 {
1260 PSYSTEM_HANDLE_INFORMATION HandleInformation;
1261 PLIST_ENTRY NextTableEntry;
1262 PHANDLE_TABLE HandleTable;
1263 PHANDLE_TABLE_ENTRY HandleTableEntry;
1264 EXHANDLE Handle;
1265 ULONG Index = 0;
1266 NTSTATUS Status;
1267 PMDL Mdl;
1268 PAGED_CODE();
1269
1270 DPRINT("NtQuerySystemInformation - SystemHandleInformation\n");
1271
1272 /* Set initial required buffer size */
1273 *ReqSize = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION, Handles);
1274
1275 /* Check user's buffer size */
1276 if (Size < *ReqSize)
1277 {
1278 return STATUS_INFO_LENGTH_MISMATCH;
1279 }
1280
1281 /* We need to lock down the memory */
1282 Status = ExLockUserBuffer(Buffer,
1283 Size,
1284 ExGetPreviousMode(),
1285 IoWriteAccess,
1286 (PVOID*)&HandleInformation,
1287 &Mdl);
1288 if (!NT_SUCCESS(Status))
1289 {
1290 DPRINT1("Failed to lock the user buffer: 0x%lx\n", Status);
1291 return Status;
1292 }
1293
1294 /* Reset of count of handles */
1295 HandleInformation->NumberOfHandles = 0;
1296
1297 /* Enter a critical region */
1298 KeEnterCriticalRegion();
1299
1300 /* Acquire the handle table lock */
1301 ExAcquirePushLockShared(&HandleTableListLock);
1302
1303 /* Enumerate all system handles */
1304 for (NextTableEntry = HandleTableListHead.Flink;
1305 NextTableEntry != &HandleTableListHead;
1306 NextTableEntry = NextTableEntry->Flink)
1307 {
1308 /* Get current handle table */
1309 HandleTable = CONTAINING_RECORD(NextTableEntry, HANDLE_TABLE, HandleTableList);
1310
1311 /* Set the initial value and loop the entries */
1312 Handle.Value = 0;
1313 while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle)))
1314 {
1315 /* Validate the entry */
1316 if ((HandleTableEntry->Object) &&
1317 (HandleTableEntry->NextFreeTableEntry != -2))
1318 {
1319 /* Increase of count of handles */
1320 ++HandleInformation->NumberOfHandles;
1321
1322 /* Lock the entry */
1323 if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
1324 {
1325 /* Increase required buffer size */
1326 *ReqSize += sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO);
1327
1328 /* Check user's buffer size */
1329 if (*ReqSize > Size)
1330 {
1331 Status = STATUS_INFO_LENGTH_MISMATCH;
1332 }
1333 else
1334 {
1335 POBJECT_HEADER ObjectHeader = ObpGetHandleObject(HandleTableEntry);
1336
1337 /* Filling handle information */
1338 HandleInformation->Handles[Index].UniqueProcessId =
1339 (USHORT)(ULONG_PTR) HandleTable->UniqueProcessId;
1340
1341 HandleInformation->Handles[Index].CreatorBackTraceIndex = 0;
1342
1343 #if 0 /* FIXME!!! Type field currupted */
1344 HandleInformation->Handles[Index].ObjectTypeIndex =
1345 (UCHAR) ObjectHeader->Type->Index;
1346 #else
1347 HandleInformation->Handles[Index].ObjectTypeIndex = 0;
1348 #endif
1349
1350 HandleInformation->Handles[Index].HandleAttributes =
1351 HandleTableEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
1352
1353 HandleInformation->Handles[Index].HandleValue =
1354 (USHORT)(ULONG_PTR) Handle.GenericHandleOverlay;
1355
1356 HandleInformation->Handles[Index].Object = &ObjectHeader->Body;
1357
1358 HandleInformation->Handles[Index].GrantedAccess =
1359 HandleTableEntry->GrantedAccess;
1360
1361 ++Index;
1362 }
1363
1364 /* Unlock it */
1365 ExUnlockHandleTableEntry(HandleTable, HandleTableEntry);
1366 }
1367 }
1368
1369 /* Go to the next entry */
1370 Handle.Value += sizeof(HANDLE);
1371 }
1372 }
1373
1374 /* Release the lock */
1375 ExReleasePushLockShared(&HandleTableListLock);
1376
1377 /* Leave the critical region */
1378 KeLeaveCriticalRegion();
1379
1380 /* Release the locked user buffer */
1381 ExUnlockUserBuffer(Mdl);
1382
1383 return Status;
1384 }
1385
1386 /* Class 17 - Information */
1387 QSI_DEF(SystemObjectInformation)
1388 {
1389 /* FIXME */
1390 DPRINT1("NtQuerySystemInformation - SystemObjectInformation not implemented\n");
1391 return STATUS_NOT_IMPLEMENTED;
1392 }
1393
1394 /* Class 18 - Information */
1395 QSI_DEF(SystemPageFileInformation)
1396 {
1397 UNICODE_STRING FileName; /* FIXME */
1398 SYSTEM_PAGEFILE_INFORMATION *Spfi = (SYSTEM_PAGEFILE_INFORMATION *) Buffer;
1399
1400 if (Size < sizeof(SYSTEM_PAGEFILE_INFORMATION))
1401 {
1402 * ReqSize = sizeof(SYSTEM_PAGEFILE_INFORMATION);
1403 return STATUS_INFO_LENGTH_MISMATCH;
1404 }
1405
1406 RtlInitUnicodeString(&FileName, NULL); /* FIXME */
1407
1408 /* FIXME */
1409 Spfi->NextEntryOffset = 0;
1410
1411 Spfi->TotalSize = MiFreeSwapPages + MiUsedSwapPages;
1412 Spfi->TotalInUse = MiUsedSwapPages;
1413 Spfi->PeakUsage = MiUsedSwapPages; /* FIXME */
1414 Spfi->PageFileName = FileName;
1415 return STATUS_SUCCESS;
1416 }
1417
1418 /* Class 19 - Vdm Instemul Information */
1419 QSI_DEF(SystemVdmInstemulInformation)
1420 {
1421 /* FIXME */
1422 DPRINT1("NtQuerySystemInformation - SystemVdmInstemulInformation not implemented\n");
1423 return STATUS_NOT_IMPLEMENTED;
1424 }
1425
1426 /* Class 20 - Vdm Bop Information */
1427 QSI_DEF(SystemVdmBopInformation)
1428 {
1429 /* FIXME */
1430 DPRINT1("NtQuerySystemInformation - SystemVdmBopInformation not implemented\n");
1431 return STATUS_NOT_IMPLEMENTED;
1432 }
1433
1434 /* Class 21 - File Cache Information */
1435 QSI_DEF(SystemFileCacheInformation)
1436 {
1437 SYSTEM_FILECACHE_INFORMATION *Sci = (SYSTEM_FILECACHE_INFORMATION *) Buffer;
1438
1439 *ReqSize = sizeof(SYSTEM_FILECACHE_INFORMATION);
1440
1441 if (Size < *ReqSize)
1442 {
1443 return STATUS_INFO_LENGTH_MISMATCH;
1444 }
1445
1446 RtlZeroMemory(Sci, sizeof(SYSTEM_FILECACHE_INFORMATION));
1447
1448 /* Return the Byte size not the page size. */
1449 Sci->CurrentSize =
1450 MiMemoryConsumers[MC_CACHE].PagesUsed * PAGE_SIZE;
1451 Sci->PeakSize =
1452 MiMemoryConsumers[MC_CACHE].PagesUsed * PAGE_SIZE; /* FIXME */
1453 /* Taskmgr multiplies this one by page size right away */
1454 Sci->CurrentSizeIncludingTransitionInPages =
1455 MiMemoryConsumers[MC_CACHE].PagesUsed; /* FIXME: Should be */
1456 /* system working set and standby pages. */
1457 Sci->PageFaultCount = 0; /* FIXME */
1458 Sci->MinimumWorkingSet = 0; /* FIXME */
1459 Sci->MaximumWorkingSet = 0; /* FIXME */
1460
1461 return STATUS_SUCCESS;
1462 }
1463
1464 SSI_DEF(SystemFileCacheInformation)
1465 {
1466 if (Size < sizeof(SYSTEM_FILECACHE_INFORMATION))
1467 {
1468 return STATUS_INFO_LENGTH_MISMATCH;
1469 }
1470 /* FIXME */
1471 DPRINT1("NtSetSystemInformation - SystemFileCacheInformation not implemented\n");
1472 return STATUS_NOT_IMPLEMENTED;
1473 }
1474
1475 /* Class 22 - Pool Tag Information */
1476 QSI_DEF(SystemPoolTagInformation)
1477 {
1478 if (Size < sizeof(SYSTEM_POOLTAG_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
1479 return ExGetPoolTagInfo(Buffer, Size, ReqSize);
1480 }
1481
1482 /* Class 23 - Interrupt Information for all processors */
1483 QSI_DEF(SystemInterruptInformation)
1484 {
1485 PKPRCB Prcb;
1486 LONG i;
1487 ULONG ti;
1488 PSYSTEM_INTERRUPT_INFORMATION sii = (PSYSTEM_INTERRUPT_INFORMATION)Buffer;
1489
1490 if(Size < KeNumberProcessors * sizeof(SYSTEM_INTERRUPT_INFORMATION))
1491 {
1492 return STATUS_INFO_LENGTH_MISMATCH;
1493 }
1494
1495 ti = KeQueryTimeIncrement();
1496
1497 for (i = 0; i < KeNumberProcessors; i++)
1498 {
1499 Prcb = KiProcessorBlock[i];
1500 sii->ContextSwitches = KeGetContextSwitches(Prcb);
1501 sii->DpcCount = Prcb->DpcData[0].DpcCount;
1502 sii->DpcRate = Prcb->DpcRequestRate;
1503 sii->TimeIncrement = ti;
1504 sii->DpcBypassCount = 0;
1505 sii->ApcBypassCount = 0;
1506 sii++;
1507 }
1508
1509 return STATUS_SUCCESS;
1510 }
1511
1512 /* Class 24 - DPC Behaviour Information */
1513 QSI_DEF(SystemDpcBehaviourInformation)
1514 {
1515 /* FIXME */
1516 DPRINT1("NtQuerySystemInformation - SystemDpcBehaviourInformation not implemented\n");
1517 return STATUS_NOT_IMPLEMENTED;
1518 }
1519
1520 SSI_DEF(SystemDpcBehaviourInformation)
1521 {
1522 /* FIXME */
1523 DPRINT1("NtSetSystemInformation - SystemDpcBehaviourInformation not implemented\n");
1524 return STATUS_NOT_IMPLEMENTED;
1525 }
1526
1527 /* Class 25 - Full Memory Information */
1528 QSI_DEF(SystemFullMemoryInformation)
1529 {
1530 PULONG Spi = (PULONG) Buffer;
1531
1532 PEPROCESS TheIdleProcess;
1533
1534 *ReqSize = sizeof(ULONG);
1535
1536 if (sizeof(ULONG) != Size)
1537 {
1538 return STATUS_INFO_LENGTH_MISMATCH;
1539 }
1540
1541 DPRINT("SystemFullMemoryInformation\n");
1542
1543 TheIdleProcess = PsIdleProcess;
1544
1545 DPRINT("PID: %p, KernelTime: %u PFFree: %lu PFUsed: %lu\n",
1546 TheIdleProcess->UniqueProcessId,
1547 TheIdleProcess->Pcb.KernelTime,
1548 MiFreeSwapPages,
1549 MiUsedSwapPages);
1550
1551 *Spi = MiMemoryConsumers[MC_USER].PagesUsed;
1552
1553 return STATUS_SUCCESS;
1554 }
1555
1556 /* Class 26 - Load Image */
1557 SSI_DEF(SystemLoadGdiDriverInformation)
1558 {
1559 PSYSTEM_GDI_DRIVER_INFORMATION DriverInfo = (PVOID)Buffer;
1560 UNICODE_STRING ImageName;
1561 PVOID ImageBase;
1562 PVOID SectionPointer;
1563 ULONG_PTR EntryPoint;
1564 NTSTATUS Status;
1565 ULONG DirSize;
1566 PIMAGE_NT_HEADERS NtHeader;
1567
1568 /* Validate size */
1569 if (Size != sizeof(SYSTEM_GDI_DRIVER_INFORMATION))
1570 {
1571 /* Incorrect buffer length, fail */
1572 return STATUS_INFO_LENGTH_MISMATCH;
1573 }
1574
1575 /* Only kernel mode can call this function */
1576 if (ExGetPreviousMode() != KernelMode) return STATUS_PRIVILEGE_NOT_HELD;
1577
1578 /* Load the driver */
1579 ImageName = DriverInfo->DriverName;
1580 Status = MmLoadSystemImage(&ImageName,
1581 NULL,
1582 NULL,
1583 0,
1584 &SectionPointer,
1585 &ImageBase);
1586 if (!NT_SUCCESS(Status)) return Status;
1587
1588 /* Return the export pointer */
1589 DriverInfo->ExportSectionPointer =
1590 RtlImageDirectoryEntryToData(ImageBase,
1591 TRUE,
1592 IMAGE_DIRECTORY_ENTRY_EXPORT,
1593 &DirSize);
1594
1595 /* Get the entrypoint */
1596 NtHeader = RtlImageNtHeader(ImageBase);
1597 EntryPoint = NtHeader->OptionalHeader.AddressOfEntryPoint;
1598 EntryPoint += (ULONG_PTR)ImageBase;
1599
1600 /* Save other data */
1601 DriverInfo->ImageAddress = ImageBase;
1602 DriverInfo->SectionPointer = SectionPointer;
1603 DriverInfo->EntryPoint = (PVOID)EntryPoint;
1604 DriverInfo->ImageLength = NtHeader->OptionalHeader.SizeOfImage;
1605
1606 /* All is good */
1607 return STATUS_SUCCESS;
1608 }
1609
1610 /* Class 27 - Unload Image */
1611 SSI_DEF(SystemUnloadGdiDriverInformation)
1612 {
1613 PVOID *SectionPointer = Buffer;
1614
1615 /* Validate size */
1616 if (Size != sizeof(PVOID))
1617 {
1618 /* Incorrect length, fail */
1619 return STATUS_INFO_LENGTH_MISMATCH;
1620 }
1621
1622 /* Only kernel mode can call this function */
1623 if (ExGetPreviousMode() != KernelMode) return STATUS_PRIVILEGE_NOT_HELD;
1624
1625 /* Unload the image */
1626 MmUnloadSystemImage(*SectionPointer);
1627 return STATUS_SUCCESS;
1628 }
1629
1630 /* Class 28 - Time Adjustment Information */
1631 QSI_DEF(SystemTimeAdjustmentInformation)
1632 {
1633 PSYSTEM_QUERY_TIME_ADJUST_INFORMATION TimeInfo =
1634 (PSYSTEM_QUERY_TIME_ADJUST_INFORMATION)Buffer;
1635
1636 /* Check if enough storage was provided */
1637 if (sizeof(SYSTEM_QUERY_TIME_ADJUST_INFORMATION) > Size)
1638 {
1639 * ReqSize = sizeof(SYSTEM_QUERY_TIME_ADJUST_INFORMATION);
1640 return STATUS_INFO_LENGTH_MISMATCH;
1641 }
1642
1643 /* Give time values to our caller */
1644 TimeInfo->TimeIncrement = KeMaximumIncrement;
1645 TimeInfo->TimeAdjustment = KeTimeAdjustment;
1646 TimeInfo->Enable = !KiTimeAdjustmentEnabled;
1647
1648 return STATUS_SUCCESS;
1649 }
1650
1651 SSI_DEF(SystemTimeAdjustmentInformation)
1652 {
1653 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1654 PSYSTEM_SET_TIME_ADJUST_INFORMATION TimeInfo =
1655 (PSYSTEM_SET_TIME_ADJUST_INFORMATION)Buffer;
1656
1657 /* Check size of a buffer, it must match our expectations */
1658 if (sizeof(SYSTEM_SET_TIME_ADJUST_INFORMATION) != Size)
1659 return STATUS_INFO_LENGTH_MISMATCH;
1660
1661 /* Check who is calling */
1662 if (PreviousMode != KernelMode)
1663 {
1664 /* Check access rights */
1665 if (!SeSinglePrivilegeCheck(SeSystemtimePrivilege, PreviousMode))
1666 {
1667 return STATUS_PRIVILEGE_NOT_HELD;
1668 }
1669 }
1670
1671 /* FIXME: behaviour suggests the member be named 'Disable' */
1672 if (TimeInfo->Enable)
1673 {
1674 /* Disable time adjustment and set default value */
1675 KiTimeAdjustmentEnabled = FALSE;
1676 KeTimeAdjustment = KeMaximumIncrement;
1677 }
1678 else
1679 {
1680 /* Check if a valid time adjustment value is given */
1681 if (TimeInfo->TimeAdjustment == 0) return STATUS_INVALID_PARAMETER_2;
1682
1683 /* Enable time adjustment and set the adjustment value */
1684 KiTimeAdjustmentEnabled = TRUE;
1685 KeTimeAdjustment = TimeInfo->TimeAdjustment;
1686 }
1687
1688 return STATUS_SUCCESS;
1689 }
1690
1691 /* Class 29 - Summary Memory Information */
1692 QSI_DEF(SystemSummaryMemoryInformation)
1693 {
1694 /* FIXME */
1695 DPRINT1("NtQuerySystemInformation - SystemSummaryMemoryInformation not implemented\n");
1696 return STATUS_NOT_IMPLEMENTED;
1697 }
1698
1699 /* Class 30 - Next Event Id Information */
1700 QSI_DEF(SystemNextEventIdInformation)
1701 {
1702 /* FIXME */
1703 DPRINT1("NtQuerySystemInformation - SystemNextEventIdInformation not implemented\n");
1704 return STATUS_NOT_IMPLEMENTED;
1705 }
1706
1707 /* Class 31 */
1708 QSI_DEF(SystemPerformanceTraceInformation)
1709 {
1710 /* FIXME */
1711 DPRINT1("NtQuerySystemInformation - SystemPerformanceTraceInformation not implemented\n");
1712 return STATUS_NOT_IMPLEMENTED;
1713 }
1714
1715 /* Class 32 - Crash Dump Information */
1716 QSI_DEF(SystemCrashDumpInformation)
1717 {
1718 /* FIXME */
1719 DPRINT1("NtQuerySystemInformation - SystemCrashDumpInformation not implemented\n");
1720 return STATUS_NOT_IMPLEMENTED;
1721 }
1722
1723 /* Class 33 - Exception Information */
1724 QSI_DEF(SystemExceptionInformation)
1725 {
1726 PSYSTEM_EXCEPTION_INFORMATION ExceptionInformation =
1727 (PSYSTEM_EXCEPTION_INFORMATION)Buffer;
1728 PKPRCB Prcb;
1729 ULONG AlignmentFixupCount = 0, ExceptionDispatchCount = 0;
1730 ULONG FloatingEmulationCount = 0, ByteWordEmulationCount = 0;
1731 CHAR i;
1732
1733 /* Check size of a buffer, it must match our expectations */
1734 if (sizeof(SYSTEM_EXCEPTION_INFORMATION) != Size)
1735 return STATUS_INFO_LENGTH_MISMATCH;
1736
1737 /* Sum up exception count information from all processors */
1738 for (i = 0; i < KeNumberProcessors; i++)
1739 {
1740 Prcb = KiProcessorBlock[i];
1741 if (Prcb)
1742 {
1743 AlignmentFixupCount += Prcb->KeAlignmentFixupCount;
1744 ExceptionDispatchCount += Prcb->KeExceptionDispatchCount;
1745 #ifndef _M_ARM
1746 FloatingEmulationCount += Prcb->KeFloatingEmulationCount;
1747 #endif // _M_ARM
1748 }
1749 }
1750
1751 /* Save information in user's buffer */
1752 ExceptionInformation->AlignmentFixupCount = AlignmentFixupCount;
1753 ExceptionInformation->ExceptionDispatchCount = ExceptionDispatchCount;
1754 ExceptionInformation->FloatingEmulationCount = FloatingEmulationCount;
1755 ExceptionInformation->ByteWordEmulationCount = ByteWordEmulationCount;
1756
1757 return STATUS_SUCCESS;
1758 }
1759
1760 /* Class 34 - Crash Dump State Information */
1761 QSI_DEF(SystemCrashDumpStateInformation)
1762 {
1763 /* FIXME */
1764 DPRINT1("NtQuerySystemInformation - SystemCrashDumpStateInformation not implemented\n");
1765 return STATUS_NOT_IMPLEMENTED;
1766 }
1767
1768 /* Class 35 - Kernel Debugger Information */
1769 QSI_DEF(SystemKernelDebuggerInformation)
1770 {
1771 PSYSTEM_KERNEL_DEBUGGER_INFORMATION skdi = (PSYSTEM_KERNEL_DEBUGGER_INFORMATION) Buffer;
1772
1773 #if (NTDDI_VERSION >= NTDDI_VISTA)
1774 *ReqSize = sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION);
1775 #endif
1776
1777 if (Size < sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION))
1778 {
1779 return STATUS_INFO_LENGTH_MISMATCH;
1780 }
1781
1782 skdi->KernelDebuggerEnabled = KD_DEBUGGER_ENABLED;
1783 skdi->KernelDebuggerNotPresent = KD_DEBUGGER_NOT_PRESENT;
1784
1785 #if (NTDDI_VERSION < NTDDI_VISTA)
1786 *ReqSize = sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION);
1787 #endif
1788
1789 return STATUS_SUCCESS;
1790 }
1791
1792 /* Class 36 - Context Switch Information */
1793 QSI_DEF(SystemContextSwitchInformation)
1794 {
1795 PSYSTEM_CONTEXT_SWITCH_INFORMATION ContextSwitchInformation =
1796 (PSYSTEM_CONTEXT_SWITCH_INFORMATION)Buffer;
1797 ULONG ContextSwitches;
1798 PKPRCB Prcb;
1799 CHAR i;
1800
1801 /* Check size of a buffer, it must match our expectations */
1802 if (sizeof(SYSTEM_CONTEXT_SWITCH_INFORMATION) != Size)
1803 return STATUS_INFO_LENGTH_MISMATCH;
1804
1805 /* Calculate total value of context switches across all processors */
1806 ContextSwitches = 0;
1807 for (i = 0; i < KeNumberProcessors; i ++)
1808 {
1809 Prcb = KiProcessorBlock[i];
1810 if (Prcb)
1811 {
1812 ContextSwitches += KeGetContextSwitches(Prcb);
1813 }
1814 }
1815
1816 ContextSwitchInformation->ContextSwitches = ContextSwitches;
1817
1818 /* FIXME */
1819 ContextSwitchInformation->FindAny = 0;
1820 ContextSwitchInformation->FindLast = 0;
1821 ContextSwitchInformation->FindIdeal = 0;
1822 ContextSwitchInformation->IdleAny = 0;
1823 ContextSwitchInformation->IdleCurrent = 0;
1824 ContextSwitchInformation->IdleLast = 0;
1825 ContextSwitchInformation->IdleIdeal = 0;
1826 ContextSwitchInformation->PreemptAny = 0;
1827 ContextSwitchInformation->PreemptCurrent = 0;
1828 ContextSwitchInformation->PreemptLast = 0;
1829 ContextSwitchInformation->SwitchToIdle = 0;
1830
1831 return STATUS_SUCCESS;
1832 }
1833
1834 /* Class 37 - Registry Quota Information */
1835 QSI_DEF(SystemRegistryQuotaInformation)
1836 {
1837 PSYSTEM_REGISTRY_QUOTA_INFORMATION srqi = (PSYSTEM_REGISTRY_QUOTA_INFORMATION) Buffer;
1838
1839 *ReqSize = sizeof(SYSTEM_REGISTRY_QUOTA_INFORMATION);
1840 if (Size < sizeof(SYSTEM_REGISTRY_QUOTA_INFORMATION))
1841 {
1842 return STATUS_INFO_LENGTH_MISMATCH;
1843 }
1844
1845 DPRINT1("Faking max registry size of 32 MB\n");
1846 srqi->RegistryQuotaAllowed = 0x2000000;
1847 srqi->RegistryQuotaUsed = 0x200000;
1848 srqi->PagedPoolSize = 0x200000;
1849
1850 return STATUS_SUCCESS;
1851 }
1852
1853 SSI_DEF(SystemRegistryQuotaInformation)
1854 {
1855 /* FIXME */
1856 DPRINT1("NtSetSystemInformation - SystemRegistryQuotaInformation not implemented\n");
1857 return STATUS_NOT_IMPLEMENTED;
1858 }
1859
1860 /* Class 38 - Load And Call Image */
1861 SSI_DEF(SystemExtendServiceTableInformation)
1862 {
1863 UNICODE_STRING ImageName;
1864 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1865 PLDR_DATA_TABLE_ENTRY ModuleObject;
1866 NTSTATUS Status;
1867 PIMAGE_NT_HEADERS NtHeader;
1868 DRIVER_OBJECT Win32k;
1869 PDRIVER_INITIALIZE DriverInit;
1870 PVOID ImageBase;
1871 ULONG_PTR EntryPoint;
1872
1873 /* Validate the size */
1874 if (Size != sizeof(UNICODE_STRING)) return STATUS_INFO_LENGTH_MISMATCH;
1875
1876 /* Check who is calling */
1877 if (PreviousMode != KernelMode)
1878 {
1879 static const UNICODE_STRING Win32kName =
1880 RTL_CONSTANT_STRING(L"\\SystemRoot\\System32\\win32k.sys");
1881
1882 /* Make sure we can load drivers */
1883 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, UserMode))
1884 {
1885 /* FIXME: We can't, fail */
1886 return STATUS_PRIVILEGE_NOT_HELD;
1887 }
1888
1889 _SEH2_TRY
1890 {
1891 /* Probe and copy the unicode string */
1892 ProbeForRead(Buffer, sizeof(ImageName), 1);
1893 ImageName = *(PUNICODE_STRING)Buffer;
1894
1895 /* Probe the string buffer */
1896 ProbeForRead(ImageName.Buffer, ImageName.Length, sizeof(WCHAR));
1897
1898 /* Check if we have the correct name (nothing else is allowed!) */
1899 if (!RtlEqualUnicodeString(&ImageName, &Win32kName, FALSE))
1900 {
1901 _SEH2_YIELD(return STATUS_PRIVILEGE_NOT_HELD);
1902 }
1903 }
1904 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1905 {
1906 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1907 }
1908 _SEH2_END;
1909
1910 /* Recursively call the function, so that we are from kernel mode */
1911 return ZwSetSystemInformation(SystemExtendServiceTableInformation,
1912 (PVOID)&Win32kName,
1913 sizeof(Win32kName));
1914 }
1915
1916 /* Load the image */
1917 Status = MmLoadSystemImage((PUNICODE_STRING)Buffer,
1918 NULL,
1919 NULL,
1920 0,
1921 (PVOID)&ModuleObject,
1922 &ImageBase);
1923
1924 if (!NT_SUCCESS(Status)) return Status;
1925
1926 /* Get the headers */
1927 NtHeader = RtlImageNtHeader(ImageBase);
1928 if (!NtHeader)
1929 {
1930 /* Fail */
1931 MmUnloadSystemImage(ModuleObject);
1932 return STATUS_INVALID_IMAGE_FORMAT;
1933 }
1934
1935 /* Get the entrypoint */
1936 EntryPoint = NtHeader->OptionalHeader.AddressOfEntryPoint;
1937 EntryPoint += (ULONG_PTR)ImageBase;
1938 DriverInit = (PDRIVER_INITIALIZE)EntryPoint;
1939
1940 /* Create a dummy device */
1941 RtlZeroMemory(&Win32k, sizeof(Win32k));
1942 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
1943 Win32k.DriverStart = ImageBase;
1944
1945 /* Call it */
1946 Status = (DriverInit)(&Win32k, NULL);
1947 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
1948
1949 /* Unload if we failed */
1950 if (!NT_SUCCESS(Status)) MmUnloadSystemImage(ModuleObject);
1951 return Status;
1952 }
1953
1954 /* Class 39 - Priority Separation */
1955 SSI_DEF(SystemPrioritySeperation)
1956 {
1957 /* Check if the size is correct */
1958 if (Size != sizeof(ULONG))
1959 {
1960 return STATUS_INFO_LENGTH_MISMATCH;
1961 }
1962
1963 /* We need the TCB privilege */
1964 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, ExGetPreviousMode()))
1965 {
1966 return STATUS_PRIVILEGE_NOT_HELD;
1967 }
1968
1969 /* Modify the quantum table */
1970 PsChangeQuantumTable(TRUE, *(PULONG)Buffer);
1971
1972 return STATUS_SUCCESS;
1973 }
1974
1975 /* Class 40 */
1976 QSI_DEF(SystemVerifierAddDriverInformation)
1977 {
1978 /* FIXME */
1979 DPRINT1("NtQuerySystemInformation - SystemVerifierAddDriverInformation not implemented\n");
1980 return STATUS_NOT_IMPLEMENTED;
1981 }
1982
1983 /* Class 41 */
1984 QSI_DEF(SystemVerifierRemoveDriverInformation)
1985 {
1986 /* FIXME */
1987 DPRINT1("NtQuerySystemInformation - SystemVerifierRemoveDriverInformation not implemented\n");
1988 return STATUS_NOT_IMPLEMENTED;
1989 }
1990
1991 /* Class 42 - Power Information */
1992 QSI_DEF(SystemProcessorIdleInformation)
1993 {
1994 *ReqSize = sizeof(PROCESSOR_POWER_INFORMATION) * KeNumberProcessors;
1995
1996 if (sizeof(PROCESSOR_POWER_INFORMATION) * KeNumberProcessors > Size)
1997 {
1998 return STATUS_INFO_LENGTH_MISMATCH;
1999 }
2000
2001 /* FIXME */
2002 DPRINT1("NtQuerySystemInformation - SystemPowerInformation not implemented\n");
2003 return STATUS_NOT_IMPLEMENTED;
2004 }
2005
2006 /* Class 43 */
2007 QSI_DEF(SystemLegacyDriverInformation)
2008 {
2009 /* FIXME */
2010 DPRINT1("NtQuerySystemInformation - SystemLegacyDriverInformation not implemented\n");
2011 return STATUS_NOT_IMPLEMENTED;
2012 }
2013
2014 /* Class 44 - Current Time Zone Information */
2015 QSI_DEF(SystemCurrentTimeZoneInformation)
2016 {
2017 *ReqSize = sizeof(RTL_TIME_ZONE_INFORMATION);
2018
2019 if (sizeof(RTL_TIME_ZONE_INFORMATION) != Size)
2020 {
2021 return STATUS_INFO_LENGTH_MISMATCH;
2022 }
2023
2024 /* Copy the time zone information struct */
2025 memcpy(Buffer,
2026 &ExpTimeZoneInfo,
2027 sizeof(RTL_TIME_ZONE_INFORMATION));
2028
2029 return STATUS_SUCCESS;
2030 }
2031
2032
2033 SSI_DEF(SystemCurrentTimeZoneInformation)
2034 {
2035 /* Check user buffer's size */
2036 if (Size < sizeof(RTL_TIME_ZONE_INFORMATION))
2037 {
2038 return STATUS_INFO_LENGTH_MISMATCH;
2039 }
2040
2041 return ExpSetTimeZoneInformation((PRTL_TIME_ZONE_INFORMATION)Buffer);
2042 }
2043
2044 static
2045 VOID
2046 ExpCopyLookasideInformation(
2047 PSYSTEM_LOOKASIDE_INFORMATION *InfoPointer,
2048 PULONG RemainingPointer,
2049 PLIST_ENTRY ListHead,
2050 BOOLEAN ListUsesMisses)
2051
2052 {
2053 PSYSTEM_LOOKASIDE_INFORMATION Info;
2054 PGENERAL_LOOKASIDE LookasideList;
2055 PLIST_ENTRY ListEntry;
2056 ULONG Remaining;
2057
2058 /* Get info pointer and remaining count of free array element */
2059 Info = *InfoPointer;
2060 Remaining = *RemainingPointer;
2061
2062 /* Loop as long as we have lookaside lists and free array elements */
2063 for (ListEntry = ListHead->Flink;
2064 (ListEntry != ListHead) && (Remaining > 0);
2065 ListEntry = ListEntry->Flink, Remaining--)
2066 {
2067 LookasideList = CONTAINING_RECORD(ListEntry, GENERAL_LOOKASIDE, ListEntry);
2068
2069 /* Fill the next array element */
2070 Info->CurrentDepth = LookasideList->Depth;
2071 Info->MaximumDepth = LookasideList->MaximumDepth;
2072 Info->TotalAllocates = LookasideList->TotalAllocates;
2073 Info->TotalFrees = LookasideList->TotalFrees;
2074 Info->Type = LookasideList->Type;
2075 Info->Tag = LookasideList->Tag;
2076 Info->Size = LookasideList->Size;
2077
2078 /* Check how the lists track misses/hits */
2079 if (ListUsesMisses)
2080 {
2081 /* Copy misses */
2082 Info->AllocateMisses = LookasideList->AllocateMisses;
2083 Info->FreeMisses = LookasideList->FreeMisses;
2084 }
2085 else
2086 {
2087 /* Calculate misses */
2088 Info->AllocateMisses = LookasideList->TotalAllocates
2089 - LookasideList->AllocateHits;
2090 Info->FreeMisses = LookasideList->TotalFrees
2091 - LookasideList->FreeHits;
2092 }
2093 }
2094
2095 /* Return the updated pointer and remaining count */
2096 *InfoPointer = Info;
2097 *RemainingPointer = Remaining;
2098 }
2099
2100 /* Class 45 - Lookaside Information */
2101 QSI_DEF(SystemLookasideInformation)
2102 {
2103 KPROCESSOR_MODE PreviousMode;
2104 PSYSTEM_LOOKASIDE_INFORMATION Info;
2105 PMDL Mdl;
2106 ULONG MaxCount, Remaining;
2107 KIRQL OldIrql;
2108 NTSTATUS Status;
2109
2110 /* First we need to lock down the memory, since we are going to access it
2111 at high IRQL */
2112 PreviousMode = ExGetPreviousMode();
2113 Status = ExLockUserBuffer(Buffer,
2114 Size,
2115 PreviousMode,
2116 IoWriteAccess,
2117 (PVOID*)&Info,
2118 &Mdl);
2119 if (!NT_SUCCESS(Status))
2120 {
2121 DPRINT1("Failed to lock the user buffer: 0x%lx\n", Status);
2122 return Status;
2123 }
2124
2125 /* Calculate how many items we can store */
2126 Remaining = MaxCount = Size / sizeof(SYSTEM_LOOKASIDE_INFORMATION);
2127 if (Remaining == 0)
2128 {
2129 goto Leave;
2130 }
2131
2132 /* Copy info from pool lookaside lists */
2133 ExpCopyLookasideInformation(&Info,
2134 &Remaining,
2135 &ExPoolLookasideListHead,
2136 FALSE);
2137 if (Remaining == 0)
2138 {
2139 goto Leave;
2140 }
2141
2142 /* Copy info from system lookaside lists */
2143 ExpCopyLookasideInformation(&Info,
2144 &Remaining,
2145 &ExSystemLookasideListHead,
2146 TRUE);
2147 if (Remaining == 0)
2148 {
2149 goto Leave;
2150 }
2151
2152 /* Acquire spinlock for ExpNonPagedLookasideListHead */
2153 KeAcquireSpinLock(&ExpNonPagedLookasideListLock, &OldIrql);
2154
2155 /* Copy info from non-paged lookaside lists */
2156 ExpCopyLookasideInformation(&Info,
2157 &Remaining,
2158 &ExpNonPagedLookasideListHead,
2159 TRUE);
2160
2161 /* Release spinlock for ExpNonPagedLookasideListHead */
2162 KeReleaseSpinLock(&ExpNonPagedLookasideListLock, OldIrql);
2163
2164 if (Remaining == 0)
2165 {
2166 goto Leave;
2167 }
2168
2169 /* Acquire spinlock for ExpPagedLookasideListHead */
2170 KeAcquireSpinLock(&ExpPagedLookasideListLock, &OldIrql);
2171
2172 /* Copy info from paged lookaside lists */
2173 ExpCopyLookasideInformation(&Info,
2174 &Remaining,
2175 &ExpPagedLookasideListHead,
2176 TRUE);
2177
2178 /* Release spinlock for ExpPagedLookasideListHead */
2179 KeReleaseSpinLock(&ExpPagedLookasideListLock, OldIrql);
2180
2181 Leave:
2182
2183 /* Release the locked user buffer */
2184 ExUnlockUserBuffer(Mdl);
2185
2186 /* Return the size of the actually written data */
2187 *ReqSize = (MaxCount - Remaining) * sizeof(SYSTEM_LOOKASIDE_INFORMATION);
2188 return STATUS_SUCCESS;
2189 }
2190
2191
2192 /* Class 46 - Set time slip event */
2193 SSI_DEF(SystemTimeSlipNotification)
2194 {
2195 /* FIXME */
2196 DPRINT1("NtSetSystemInformation - SystemTimeSlipNotification not implemented\n");
2197 return STATUS_NOT_IMPLEMENTED;
2198 }
2199
2200 NTSTATUS
2201 NTAPI
2202 MmSessionCreate(OUT PULONG SessionId);
2203
2204 NTSTATUS
2205 NTAPI
2206 MmSessionDelete(IN ULONG SessionId);
2207
2208 /* Class 47 - Create a new session (TSE) */
2209 SSI_DEF(SystemSessionCreate)
2210 {
2211 ULONG SessionId;
2212 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2213 NTSTATUS Status;
2214
2215 if (Size != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2216
2217 if (PreviousMode != KernelMode)
2218 {
2219 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2220 {
2221 return STATUS_PRIVILEGE_NOT_HELD;
2222 }
2223
2224 ProbeForWriteUlong(Buffer);
2225 }
2226
2227 Status = MmSessionCreate(&SessionId);
2228 if (NT_SUCCESS(Status)) *(PULONG)Buffer = SessionId;
2229
2230 return Status;
2231 }
2232
2233
2234 /* Class 48 - Delete an existing session (TSE) */
2235 SSI_DEF(SystemSessionDetach)
2236 {
2237 ULONG SessionId;
2238 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2239
2240 if (Size != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2241
2242 if (PreviousMode != KernelMode)
2243 {
2244 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2245 {
2246 return STATUS_PRIVILEGE_NOT_HELD;
2247 }
2248 }
2249
2250 SessionId = *(PULONG)Buffer;
2251
2252 return MmSessionDelete(SessionId);
2253 }
2254
2255
2256 /* Class 49 - UNKNOWN */
2257 QSI_DEF(SystemSessionInformation)
2258 {
2259 /* FIXME */
2260 DPRINT1("NtQuerySystemInformation - SystemSessionInformation not implemented\n");
2261 return STATUS_NOT_IMPLEMENTED;
2262 }
2263
2264
2265 /* Class 50 - System range start address */
2266 QSI_DEF(SystemRangeStartInformation)
2267 {
2268 /* Check user buffer's size */
2269 if (Size != sizeof(ULONG_PTR)) return STATUS_INFO_LENGTH_MISMATCH;
2270
2271 *(PULONG_PTR)Buffer = (ULONG_PTR)MmSystemRangeStart;
2272
2273 if (ReqSize) *ReqSize = sizeof(ULONG_PTR);
2274
2275 return STATUS_SUCCESS;
2276 }
2277
2278 /* Class 51 - Driver verifier information */
2279 QSI_DEF(SystemVerifierInformation)
2280 {
2281 /* FIXME */
2282 DPRINT1("NtQuerySystemInformation - SystemVerifierInformation not implemented\n");
2283 return STATUS_NOT_IMPLEMENTED;
2284 }
2285
2286
2287 SSI_DEF(SystemVerifierInformation)
2288 {
2289 /* FIXME */
2290 DPRINT1("NtSetSystemInformation - SystemVerifierInformation not implemented\n");
2291 return STATUS_NOT_IMPLEMENTED;
2292 }
2293
2294
2295 /* Class 52 */
2296 SSI_DEF(SystemVerifierThunkExtend)
2297 {
2298 /* FIXME */
2299 DPRINT1("NtSetSystemInformation - SystemVerifierThunkExtend not implemented\n");
2300 return STATUS_NOT_IMPLEMENTED;
2301 }
2302
2303
2304 /* Class 53 - A session's processes */
2305 QSI_DEF(SystemSessionProcessesInformation)
2306 {
2307 /* FIXME */
2308 DPRINT1("NtQuerySystemInformation - SystemSessionProcessInformation not implemented\n");
2309 return STATUS_NOT_IMPLEMENTED;
2310 }
2311
2312
2313 /* Class 54 - Load & map in system space */
2314 SSI_DEF(SystemLoadGdiDriverInSystemSpaceInformation)
2315 {
2316 /* FIXME */
2317 DPRINT1("NtSetSystemInformation - SystemLoadGdiDriverInSystemSpaceInformation not implemented\n");
2318 return STATUS_NOT_IMPLEMENTED;
2319 }
2320
2321
2322 /* Class 55 - NUMA processor information */
2323 QSI_DEF(SystemNumaProcessorMap)
2324 {
2325 ULONG MaxEntries, Node;
2326 PSYSTEM_NUMA_INFORMATION NumaInformation = (PSYSTEM_NUMA_INFORMATION)Buffer;
2327
2328 /* Validate input size */
2329 if (Size < sizeof(ULONG))
2330 {
2331 return STATUS_INFO_LENGTH_MISMATCH;
2332 }
2333
2334 /* Return highest node */
2335 NumaInformation->HighestNodeNumber = KeNumberNodes - 1;
2336
2337 /* Compute how much entries we will be able to put in output structure */
2338 MaxEntries = (Size - FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, ActiveProcessorsAffinityMask)) / sizeof(ULONGLONG);
2339 /* Make sure we don't overflow KeNodeBlock */
2340 if (MaxEntries > KeNumberNodes)
2341 {
2342 MaxEntries = KeNumberNodes;
2343 }
2344
2345 /* If we have entries to write, and room for it */
2346 if (Size >= FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, ActiveProcessorsAffinityMask) &&
2347 MaxEntries != 0)
2348 {
2349 /* Already set size we return */
2350 *ReqSize = FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, ActiveProcessorsAffinityMask) +
2351 MaxEntries * sizeof(ULONGLONG);
2352
2353 /* For each node, return processor mask */
2354 for (Node = 0; Node < MaxEntries; ++Node)
2355 {
2356 NumaInformation->ActiveProcessorsAffinityMask[Node] = KeNodeBlock[Node]->ProcessorMask;
2357 }
2358 }
2359 else
2360 {
2361 /* We only returned highest node number */
2362 *ReqSize = sizeof(ULONG);
2363 }
2364
2365 return STATUS_SUCCESS;
2366 }
2367
2368
2369 /* Class 56 - Prefetcher information */
2370 QSI_DEF(SystemPrefetcherInformation)
2371 {
2372 /* FIXME */
2373 DPRINT1("NtQuerySystemInformation - SystemPrefetcherInformation not implemented\n");
2374 return STATUS_NOT_IMPLEMENTED;
2375 }
2376
2377
2378 /* Class 57 - Extended process information */
2379 QSI_DEF(SystemExtendedProcessInformation)
2380 {
2381 /* FIXME */
2382 DPRINT1("NtQuerySystemInformation - SystemExtendedProcessInformation not implemented\n");
2383 return STATUS_NOT_IMPLEMENTED;
2384 }
2385
2386
2387 /* Class 58 - Recommended shared ata alignment */
2388 QSI_DEF(SystemRecommendedSharedDataAlignment)
2389 {
2390 /* FIXME */
2391 DPRINT1("NtQuerySystemInformation - SystemRecommendedSharedDataAlignment not implemented\n");
2392 return STATUS_NOT_IMPLEMENTED;
2393 }
2394
2395
2396 /* Class 60 - NUMA memory information */
2397 QSI_DEF(SystemNumaAvailableMemory)
2398 {
2399 ULONG MaxEntries, Node;
2400 PSYSTEM_NUMA_INFORMATION NumaInformation = (PSYSTEM_NUMA_INFORMATION)Buffer;
2401
2402 /* Validate input size */
2403 if (Size < sizeof(ULONG))
2404 {
2405 return STATUS_INFO_LENGTH_MISMATCH;
2406 }
2407
2408 /* Return highest node */
2409 NumaInformation->HighestNodeNumber = KeNumberNodes - 1;
2410
2411 /* Compute how much entries we will be able to put in output structure */
2412 MaxEntries = (Size - FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, AvailableMemory)) / sizeof(ULONGLONG);
2413 /* Make sure we don't overflow KeNodeBlock */
2414 if (MaxEntries > KeNumberNodes)
2415 {
2416 MaxEntries = KeNumberNodes;
2417 }
2418
2419 /* If we have entries to write, and room for it */
2420 if (Size >= FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, AvailableMemory) &&
2421 MaxEntries != 0)
2422 {
2423 /* Already set size we return */
2424 *ReqSize = FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, AvailableMemory) +
2425 MaxEntries * sizeof(ULONGLONG);
2426
2427 /* If we have a single entry (us), directly return MM information */
2428 if (MaxEntries == 1)
2429 {
2430 NumaInformation->AvailableMemory[0] = MmAvailablePages << PAGE_SHIFT;
2431 }
2432 else
2433 {
2434 /* Otherwise, for each node, return available bytes */
2435 for (Node = 0; Node < MaxEntries; ++Node)
2436 {
2437 NumaInformation->AvailableMemory[Node] = (KeNodeBlock[Node]->FreeCount[0] + KeNodeBlock[Node]->FreeCount[1]) << PAGE_SHIFT;
2438 }
2439 }
2440 }
2441 else
2442 {
2443 /* We only returned highest node number */
2444 *ReqSize = sizeof(ULONG);
2445 }
2446
2447 return STATUS_SUCCESS;
2448 }
2449
2450 /* Class 64 - Extended handle information */
2451 QSI_DEF(SystemExtendedHandleInformation)
2452 {
2453 PSYSTEM_HANDLE_INFORMATION_EX HandleInformation;
2454 PLIST_ENTRY NextTableEntry;
2455 PHANDLE_TABLE HandleTable;
2456 PHANDLE_TABLE_ENTRY HandleTableEntry;
2457 EXHANDLE Handle;
2458 ULONG Index = 0;
2459 NTSTATUS Status;
2460 PMDL Mdl;
2461 PAGED_CODE();
2462
2463 DPRINT("NtQuerySystemInformation - SystemExtendedHandleInformation\n");
2464
2465 /* Set initial required buffer size */
2466 *ReqSize = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handle);
2467
2468 /* Check user's buffer size */
2469 if (Size < *ReqSize)
2470 {
2471 return STATUS_INFO_LENGTH_MISMATCH;
2472 }
2473
2474 /* We need to lock down the memory */
2475 Status = ExLockUserBuffer(Buffer,
2476 Size,
2477 ExGetPreviousMode(),
2478 IoWriteAccess,
2479 (PVOID*)&HandleInformation,
2480 &Mdl);
2481 if (!NT_SUCCESS(Status))
2482 {
2483 DPRINT1("Failed to lock the user buffer: 0x%lx\n", Status);
2484 return Status;
2485 }
2486
2487 /* Reset of count of handles */
2488 HandleInformation->Count = 0;
2489
2490 /* Enter a critical region */
2491 KeEnterCriticalRegion();
2492
2493 /* Acquire the handle table lock */
2494 ExAcquirePushLockShared(&HandleTableListLock);
2495
2496 /* Enumerate all system handles */
2497 for (NextTableEntry = HandleTableListHead.Flink;
2498 NextTableEntry != &HandleTableListHead;
2499 NextTableEntry = NextTableEntry->Flink)
2500 {
2501 /* Get current handle table */
2502 HandleTable = CONTAINING_RECORD(NextTableEntry, HANDLE_TABLE, HandleTableList);
2503
2504 /* Set the initial value and loop the entries */
2505 Handle.Value = 0;
2506 while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle)))
2507 {
2508 /* Validate the entry */
2509 if ((HandleTableEntry->Object) &&
2510 (HandleTableEntry->NextFreeTableEntry != -2))
2511 {
2512 /* Increase of count of handles */
2513 ++HandleInformation->Count;
2514
2515 /* Lock the entry */
2516 if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
2517 {
2518 /* Increase required buffer size */
2519 *ReqSize += sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX);
2520
2521 /* Check user's buffer size */
2522 if (*ReqSize > Size)
2523 {
2524 Status = STATUS_INFO_LENGTH_MISMATCH;
2525 }
2526 else
2527 {
2528 POBJECT_HEADER ObjectHeader = ObpGetHandleObject(HandleTableEntry);
2529
2530 /* Filling handle information */
2531 HandleInformation->Handle[Index].UniqueProcessId =
2532 (USHORT)(ULONG_PTR) HandleTable->UniqueProcessId;
2533
2534 HandleInformation->Handle[Index].CreatorBackTraceIndex = 0;
2535
2536 #if 0 /* FIXME!!! Type field currupted */
2537 HandleInformation->Handles[Index].ObjectTypeIndex =
2538 (UCHAR) ObjectHeader->Type->Index;
2539 #else
2540 HandleInformation->Handle[Index].ObjectTypeIndex = 0;
2541 #endif
2542
2543 HandleInformation->Handle[Index].HandleAttributes =
2544 HandleTableEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
2545
2546 HandleInformation->Handle[Index].HandleValue =
2547 (USHORT)(ULONG_PTR) Handle.GenericHandleOverlay;
2548
2549 HandleInformation->Handle[Index].Object = &ObjectHeader->Body;
2550
2551 HandleInformation->Handle[Index].GrantedAccess =
2552 HandleTableEntry->GrantedAccess;
2553
2554 HandleInformation->Handle[Index].Reserved = 0;
2555
2556 ++Index;
2557 }
2558
2559 /* Unlock it */
2560 ExUnlockHandleTableEntry(HandleTable, HandleTableEntry);
2561 }
2562 }
2563
2564 /* Go to the next entry */
2565 Handle.Value += sizeof(HANDLE);
2566 }
2567 }
2568
2569 /* Release the lock */
2570 ExReleasePushLockShared(&HandleTableListLock);
2571
2572 /* Leave the critical region */
2573 KeLeaveCriticalRegion();
2574
2575 /* Release the locked user buffer */
2576 ExUnlockUserBuffer(Mdl);
2577
2578 return Status;
2579 }
2580
2581 /* Class 76 - System firmware table information */
2582 QSI_DEF(SystemFirmwareTableInformation)
2583 {
2584 PSYSTEM_FIRMWARE_TABLE_INFORMATION SysFirmwareInfo = (PSYSTEM_FIRMWARE_TABLE_INFORMATION)Buffer;
2585 NTSTATUS Status = STATUS_SUCCESS;
2586 ULONG InputBufSize;
2587 ULONG DataSize = 0;
2588 ULONG TableCount = 0;
2589
2590 DPRINT("NtQuerySystemInformation - SystemFirmwareTableInformation\n");
2591
2592 /* Set initial required buffer size */
2593 *ReqSize = FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
2594
2595 /* Check user's buffer size */
2596 if (Size < *ReqSize)
2597 {
2598 return STATUS_INFO_LENGTH_MISMATCH;
2599 }
2600
2601 InputBufSize = SysFirmwareInfo->TableBufferLength;
2602 switch (SysFirmwareInfo->ProviderSignature)
2603 {
2604 /*
2605 * ExpFirmwareTableResource and ExpFirmwareTableProviderListHead
2606 * variables should be used there somehow...
2607 */
2608 case SIG_ACPI:
2609 {
2610 /* FIXME: Not implemented yet */
2611 DPRINT1("ACPI provider not implemented\n");
2612 Status = STATUS_NOT_IMPLEMENTED;
2613 break;
2614 }
2615 case SIG_FIRM:
2616 {
2617 /* FIXME: Not implemented yet */
2618 DPRINT1("FIRM provider not implemented\n");
2619 Status = STATUS_NOT_IMPLEMENTED;
2620 break;
2621 }
2622 case SIG_RSMB:
2623 {
2624 Status = ExpGetRawSMBiosTable(NULL, &DataSize, 0);
2625 if (DataSize > 0)
2626 {
2627 TableCount = 1;
2628 if (SysFirmwareInfo->Action == SystemFirmwareTable_Enumerate)
2629 {
2630 DataSize = TableCount * sizeof(ULONG);
2631 if (DataSize <= InputBufSize)
2632 {
2633 *(ULONG *)SysFirmwareInfo->TableBuffer = 0;
2634 }
2635 }
2636 else if (SysFirmwareInfo->Action == SystemFirmwareTable_Get
2637 && DataSize <= InputBufSize)
2638 {
2639 Status = ExpGetRawSMBiosTable(SysFirmwareInfo->TableBuffer, &DataSize, InputBufSize);
2640 }
2641 SysFirmwareInfo->TableBufferLength = DataSize;
2642 }
2643 break;
2644 }
2645 default:
2646 {
2647 DPRINT1("SystemFirmwareTableInformation: Unsupported provider (0x%x)\n",
2648 SysFirmwareInfo->ProviderSignature);
2649 Status = STATUS_ILLEGAL_FUNCTION;
2650 }
2651 }
2652
2653 if (NT_SUCCESS(Status))
2654 {
2655 switch (SysFirmwareInfo->Action)
2656 {
2657 case SystemFirmwareTable_Enumerate:
2658 case SystemFirmwareTable_Get:
2659 {
2660 if (SysFirmwareInfo->TableBufferLength > InputBufSize)
2661 {
2662 Status = STATUS_BUFFER_TOO_SMALL;
2663 }
2664 break;
2665 }
2666 default:
2667 {
2668 DPRINT1("SystemFirmwareTableInformation: Unsupported action (0x%x)\n",
2669 SysFirmwareInfo->Action);
2670 Status = STATUS_ILLEGAL_FUNCTION;
2671 }
2672 }
2673 }
2674 else
2675 {
2676 SysFirmwareInfo->TableBufferLength = 0;
2677 }
2678 return Status;
2679 }
2680
2681 /* Query/Set Calls Table */
2682 typedef
2683 struct _QSSI_CALLS
2684 {
2685 NTSTATUS (* Query) (PVOID,ULONG,PULONG);
2686 NTSTATUS (* Set) (PVOID,ULONG);
2687 } QSSI_CALLS;
2688
2689 // QS Query & Set
2690 // QX Query
2691 // XS Set
2692 // XX unknown behaviour
2693 //
2694 #define SI_QS(n) {QSI_USE(n),SSI_USE(n)}
2695 #define SI_QX(n) {QSI_USE(n),NULL}
2696 #define SI_XS(n) {NULL,SSI_USE(n)}
2697 #define SI_XX(n) {NULL,NULL}
2698
2699 static
2700 QSSI_CALLS
2701 CallQS [] =
2702 {
2703 SI_QX(SystemBasicInformation),
2704 SI_QX(SystemProcessorInformation),
2705 SI_QX(SystemPerformanceInformation),
2706 SI_QX(SystemTimeOfDayInformation),
2707 SI_QX(SystemPathInformation), /* should be SI_XX */
2708 SI_QX(SystemProcessInformation),
2709 SI_QX(SystemCallCountInformation),
2710 SI_QX(SystemDeviceInformation),
2711 SI_QX(SystemProcessorPerformanceInformation),
2712 SI_QS(SystemFlagsInformation),
2713 SI_QX(SystemCallTimeInformation), /* should be SI_XX */
2714 SI_QX(SystemModuleInformation),
2715 SI_QX(SystemLocksInformation),
2716 SI_QX(SystemStackTraceInformation), /* should be SI_XX */
2717 SI_QX(SystemPagedPoolInformation), /* should be SI_XX */
2718 SI_QX(SystemNonPagedPoolInformation), /* should be SI_XX */
2719 SI_QX(SystemHandleInformation),
2720 SI_QX(SystemObjectInformation),
2721 SI_QX(SystemPageFileInformation),
2722 SI_QX(SystemVdmInstemulInformation),
2723 SI_QX(SystemVdmBopInformation), /* it should be SI_XX */
2724 SI_QS(SystemFileCacheInformation),
2725 SI_QX(SystemPoolTagInformation),
2726 SI_QX(SystemInterruptInformation),
2727 SI_QS(SystemDpcBehaviourInformation),
2728 SI_QX(SystemFullMemoryInformation), /* it should be SI_XX */
2729 SI_XS(SystemLoadGdiDriverInformation),
2730 SI_XS(SystemUnloadGdiDriverInformation),
2731 SI_QS(SystemTimeAdjustmentInformation),
2732 SI_QX(SystemSummaryMemoryInformation), /* it should be SI_XX */
2733 SI_QX(SystemNextEventIdInformation), /* it should be SI_XX */
2734 SI_QX(SystemPerformanceTraceInformation), /* it should be SI_XX */
2735 SI_QX(SystemCrashDumpInformation),
2736 SI_QX(SystemExceptionInformation),
2737 SI_QX(SystemCrashDumpStateInformation),
2738 SI_QX(SystemKernelDebuggerInformation),
2739 SI_QX(SystemContextSwitchInformation),
2740 SI_QS(SystemRegistryQuotaInformation),
2741 SI_XS(SystemExtendServiceTableInformation),
2742 SI_XS(SystemPrioritySeperation),
2743 SI_QX(SystemVerifierAddDriverInformation), /* it should be SI_XX */
2744 SI_QX(SystemVerifierRemoveDriverInformation), /* it should be SI_XX */
2745 SI_QX(SystemProcessorIdleInformation), /* it should be SI_XX */
2746 SI_QX(SystemLegacyDriverInformation), /* it should be SI_XX */
2747 SI_QS(SystemCurrentTimeZoneInformation), /* it should be SI_QX */
2748 SI_QX(SystemLookasideInformation),
2749 SI_XS(SystemTimeSlipNotification),
2750 SI_XS(SystemSessionCreate),
2751 SI_XS(SystemSessionDetach),
2752 SI_QX(SystemSessionInformation), /* it should be SI_XX */
2753 SI_QX(SystemRangeStartInformation),
2754 SI_QS(SystemVerifierInformation),
2755 SI_XS(SystemVerifierThunkExtend),
2756 SI_QX(SystemSessionProcessesInformation),
2757 SI_XS(SystemLoadGdiDriverInSystemSpaceInformation),
2758 SI_QX(SystemNumaProcessorMap),
2759 SI_QX(SystemPrefetcherInformation),
2760 SI_QX(SystemExtendedProcessInformation),
2761 SI_QX(SystemRecommendedSharedDataAlignment),
2762 SI_XX(SystemComPlusPackage),
2763 SI_QX(SystemNumaAvailableMemory),
2764 SI_XX(SystemProcessorPowerInformation), /* FIXME: not implemented */
2765 SI_XX(SystemEmulationBasicInformation), /* FIXME: not implemented */
2766 SI_XX(SystemEmulationProcessorInformation), /* FIXME: not implemented */
2767 SI_QX(SystemExtendedHandleInformation),
2768 SI_XX(SystemLostDelayedWriteInformation), /* FIXME: not implemented */
2769 SI_XX(SystemBigPoolInformation), /* FIXME: not implemented */
2770 SI_XX(SystemSessionPoolTagInformation), /* FIXME: not implemented */
2771 SI_XX(SystemSessionMappedViewInformation), /* FIXME: not implemented */
2772 SI_XX(SystemHotpatchInformation), /* FIXME: not implemented */
2773 SI_XX(SystemObjectSecurityMode), /* FIXME: not implemented */
2774 SI_XX(SystemWatchdogTimerHandler), /* FIXME: not implemented */
2775 SI_XX(SystemWatchdogTimerInformation), /* FIXME: not implemented */
2776 SI_XX(SystemLogicalProcessorInformation), /* FIXME: not implemented */
2777 SI_XX(SystemWow64SharedInformation), /* FIXME: not implemented */
2778 SI_XX(SystemRegisterFirmwareTableInformationHandler), /* FIXME: not implemented */
2779 SI_QX(SystemFirmwareTableInformation),
2780 };
2781
2782 C_ASSERT(SystemBasicInformation == 0);
2783 #define MIN_SYSTEM_INFO_CLASS (SystemBasicInformation)
2784 #define MAX_SYSTEM_INFO_CLASS (sizeof(CallQS) / sizeof(CallQS[0]))
2785
2786 /*
2787 * @implemented
2788 */
2789 __kernel_entry
2790 NTSTATUS
2791 NTAPI
2792 NtQuerySystemInformation(
2793 _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
2794 _Out_writes_bytes_to_opt_(SystemInformationLength, *ReturnLength) PVOID SystemInformation,
2795 _In_ ULONG Length,
2796 _Out_opt_ PULONG UnsafeResultLength)
2797 {
2798 KPROCESSOR_MODE PreviousMode;
2799 ULONG ResultLength = 0;
2800 ULONG Alignment = TYPE_ALIGNMENT(ULONG);
2801 NTSTATUS FStatus = STATUS_NOT_IMPLEMENTED;
2802
2803 PAGED_CODE();
2804
2805 PreviousMode = ExGetPreviousMode();
2806
2807 _SEH2_TRY
2808 {
2809 #if (NTDDI_VERSION >= NTDDI_VISTA)
2810 /*
2811 * Check if the request is valid.
2812 */
2813 if (SystemInformationClass >= MAX_SYSTEM_INFO_CLASS)
2814 {
2815 _SEH2_YIELD(return STATUS_INVALID_INFO_CLASS);
2816 }
2817 #endif
2818
2819 if (PreviousMode != KernelMode)
2820 {
2821 /* SystemKernelDebuggerInformation needs only BOOLEAN alignment */
2822 if (SystemInformationClass == SystemKernelDebuggerInformation)
2823 Alignment = TYPE_ALIGNMENT(BOOLEAN);
2824
2825 ProbeForWrite(SystemInformation, Length, Alignment);
2826 if (UnsafeResultLength != NULL)
2827 ProbeForWriteUlong(UnsafeResultLength);
2828 }
2829
2830 if (UnsafeResultLength)
2831 *UnsafeResultLength = 0;
2832
2833 #if (NTDDI_VERSION < NTDDI_VISTA)
2834 /*
2835 * Check if the request is valid.
2836 */
2837 if (SystemInformationClass >= MAX_SYSTEM_INFO_CLASS)
2838 {
2839 _SEH2_YIELD(return STATUS_INVALID_INFO_CLASS);
2840 }
2841 #endif
2842
2843 if (NULL != CallQS [SystemInformationClass].Query)
2844 {
2845 /*
2846 * Hand the request to a subhandler.
2847 */
2848 FStatus = CallQS [SystemInformationClass].Query(SystemInformation,
2849 Length,
2850 &ResultLength);
2851
2852 /* Save the result length to the caller */
2853 if (UnsafeResultLength)
2854 *UnsafeResultLength = ResultLength;
2855 }
2856 }
2857 _SEH2_EXCEPT(ExSystemExceptionFilter())
2858 {
2859 FStatus = _SEH2_GetExceptionCode();
2860 }
2861 _SEH2_END;
2862
2863 return FStatus;
2864 }
2865
2866
2867 NTSTATUS
2868 NTAPI
2869 NtSetSystemInformation (IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
2870 IN PVOID SystemInformation,
2871 IN ULONG SystemInformationLength)
2872 {
2873 NTSTATUS Status = STATUS_INVALID_INFO_CLASS;
2874 KPROCESSOR_MODE PreviousMode;
2875
2876 PAGED_CODE();
2877
2878 PreviousMode = ExGetPreviousMode();
2879
2880 _SEH2_TRY
2881 {
2882 /*
2883 * If called from user mode, check
2884 * possible unsafe arguments.
2885 */
2886 if (PreviousMode != KernelMode)
2887 {
2888 ProbeForRead(SystemInformation, SystemInformationLength, sizeof(ULONG));
2889 }
2890
2891 /*
2892 * Check the request is valid.
2893 */
2894 if ((SystemInformationClass >= MIN_SYSTEM_INFO_CLASS) &&
2895 (SystemInformationClass < MAX_SYSTEM_INFO_CLASS))
2896 {
2897 if (NULL != CallQS [SystemInformationClass].Set)
2898 {
2899 /*
2900 * Hand the request to a subhandler.
2901 */
2902 Status = CallQS [SystemInformationClass].Set(SystemInformation,
2903 SystemInformationLength);
2904 }
2905 }
2906 }
2907 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2908 {
2909 Status = _SEH2_GetExceptionCode();
2910 }
2911 _SEH2_END;
2912
2913 return Status;
2914 }
2915
2916 ULONG
2917 NTAPI
2918 NtGetCurrentProcessorNumber(VOID)
2919 {
2920 /* Just use Ke */
2921 return KeGetCurrentProcessorNumber();
2922 }
2923
2924 #undef ExGetPreviousMode
2925 KPROCESSOR_MODE
2926 NTAPI
2927 ExGetPreviousMode(VOID)
2928 {
2929 /* Just use Ke */
2930 return KeGetPreviousMode();
2931 }