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