Sync with trunk r63192.
[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 /* FIXME */
1792 DPRINT1("NtSetSystemInformation - SystemPrioritySeperation not implemented\n");
1793 return STATUS_NOT_IMPLEMENTED;
1794 }
1795
1796 /* Class 40 - Plug Play Bus Information */
1797 QSI_DEF(SystemPlugPlayBusInformation)
1798 {
1799 /* FIXME */
1800 DPRINT1("NtQuerySystemInformation - SystemPlugPlayBusInformation not implemented\n");
1801 return STATUS_NOT_IMPLEMENTED;
1802 }
1803
1804 /* Class 41 - Dock Information */
1805 QSI_DEF(SystemDockInformation)
1806 {
1807 /* FIXME */
1808 DPRINT1("NtQuerySystemInformation - SystemDockInformation not implemented\n");
1809 return STATUS_NOT_IMPLEMENTED;
1810 }
1811
1812 /* Class 42 - Power Information */
1813 QSI_DEF(SystemPowerInformation)
1814 {
1815 /* FIXME */
1816 DPRINT1("NtQuerySystemInformation - SystemPowerInformation not implemented\n");
1817 return STATUS_NOT_IMPLEMENTED;
1818 }
1819
1820 /* Class 43 - Processor Speed Information */
1821 QSI_DEF(SystemProcessorSpeedInformation)
1822 {
1823 /* FIXME */
1824 DPRINT1("NtQuerySystemInformation - SystemProcessorSpeedInformation not implemented\n");
1825 return STATUS_NOT_IMPLEMENTED;
1826 }
1827
1828 /* Class 44 - Current Time Zone Information */
1829 QSI_DEF(SystemCurrentTimeZoneInformation)
1830 {
1831 *ReqSize = sizeof(TIME_ZONE_INFORMATION);
1832
1833 if (sizeof(TIME_ZONE_INFORMATION) != Size)
1834 {
1835 return STATUS_INFO_LENGTH_MISMATCH;
1836 }
1837
1838 /* Copy the time zone information struct */
1839 memcpy(Buffer,
1840 &ExpTimeZoneInfo,
1841 sizeof(TIME_ZONE_INFORMATION));
1842
1843 return STATUS_SUCCESS;
1844 }
1845
1846
1847 SSI_DEF(SystemCurrentTimeZoneInformation)
1848 {
1849 /* Check user buffer's size */
1850 if (Size < sizeof(TIME_ZONE_INFORMATION))
1851 {
1852 return STATUS_INFO_LENGTH_MISMATCH;
1853 }
1854
1855 return ExpSetTimeZoneInformation((PTIME_ZONE_INFORMATION)Buffer);
1856 }
1857
1858 static
1859 VOID
1860 ExpCopyLookasideInformation(
1861 PSYSTEM_LOOKASIDE_INFORMATION *InfoPointer,
1862 PULONG RemainingPointer,
1863 PLIST_ENTRY ListHead,
1864 BOOLEAN ListUsesMisses)
1865
1866 {
1867 PSYSTEM_LOOKASIDE_INFORMATION Info;
1868 PGENERAL_LOOKASIDE LookasideList;
1869 PLIST_ENTRY ListEntry;
1870 ULONG Remaining;
1871
1872 /* Get info pointer and remaining count of free array element */
1873 Info = *InfoPointer;
1874 Remaining = *RemainingPointer;
1875
1876 /* Loop as long as we have lookaside lists and free array elements */
1877 for (ListEntry = ListHead->Flink;
1878 (ListEntry != ListHead) && (Remaining > 0);
1879 ListEntry = ListEntry->Flink, Remaining--)
1880 {
1881 LookasideList = CONTAINING_RECORD(ListEntry, GENERAL_LOOKASIDE, ListEntry);
1882
1883 /* Fill the next array element */
1884 Info->CurrentDepth = LookasideList->Depth;
1885 Info->MaximumDepth = LookasideList->MaximumDepth;
1886 Info->TotalAllocates = LookasideList->TotalAllocates;
1887 Info->TotalFrees = LookasideList->TotalFrees;
1888 Info->Type = LookasideList->Type;
1889 Info->Tag = LookasideList->Tag;
1890 Info->Size = LookasideList->Size;
1891
1892 /* Check how the lists track misses/hits */
1893 if (ListUsesMisses)
1894 {
1895 /* Copy misses */
1896 Info->AllocateMisses = LookasideList->AllocateMisses;
1897 Info->FreeMisses = LookasideList->FreeMisses;
1898 }
1899 else
1900 {
1901 /* Calculate misses */
1902 Info->AllocateMisses = LookasideList->TotalAllocates
1903 - LookasideList->AllocateHits;
1904 Info->FreeMisses = LookasideList->TotalFrees
1905 - LookasideList->FreeHits;
1906 }
1907 }
1908
1909 /* Return the updated pointer and remaining count */
1910 *InfoPointer = Info;
1911 *RemainingPointer = Remaining;
1912 }
1913
1914 /* Class 45 - Lookaside Information */
1915 QSI_DEF(SystemLookasideInformation)
1916 {
1917 KPROCESSOR_MODE PreviousMode;
1918 PSYSTEM_LOOKASIDE_INFORMATION Info;
1919 PMDL Mdl;
1920 ULONG MaxCount, Remaining;
1921 KIRQL OldIrql;
1922 NTSTATUS Status;
1923
1924 /* First we need to lock down the memory, since we are going to access it
1925 at high IRQL */
1926 PreviousMode = ExGetPreviousMode();
1927 Status = ExLockUserBuffer(Buffer,
1928 Size,
1929 PreviousMode,
1930 IoWriteAccess,
1931 (PVOID*)&Info,
1932 &Mdl);
1933 if (!NT_SUCCESS(Status))
1934 {
1935 DPRINT1("Failed to lock the user buffer: 0x%lx\n", Status);
1936 return Status;
1937 }
1938
1939 /* Calculate how many items we can store */
1940 Remaining = MaxCount = Size / sizeof(SYSTEM_LOOKASIDE_INFORMATION);
1941 if (Remaining == 0)
1942 {
1943 goto Leave;
1944 }
1945
1946 /* Copy info from pool lookaside lists */
1947 ExpCopyLookasideInformation(&Info,
1948 &Remaining,
1949 &ExPoolLookasideListHead,
1950 FALSE);
1951 if (Remaining == 0)
1952 {
1953 goto Leave;
1954 }
1955
1956 /* Copy info from system lookaside lists */
1957 ExpCopyLookasideInformation(&Info,
1958 &Remaining,
1959 &ExSystemLookasideListHead,
1960 TRUE);
1961 if (Remaining == 0)
1962 {
1963 goto Leave;
1964 }
1965
1966 /* Acquire spinlock for ExpNonPagedLookasideListHead */
1967 OldIrql = KfAcquireSpinLock(&ExpNonPagedLookasideListLock);
1968
1969 /* Copy info from non-paged lookaside lists */
1970 ExpCopyLookasideInformation(&Info,
1971 &Remaining,
1972 &ExpNonPagedLookasideListHead,
1973 TRUE);
1974
1975 /* Release spinlock for ExpNonPagedLookasideListHead */
1976 KfReleaseSpinLock(&ExpNonPagedLookasideListLock, OldIrql);
1977
1978 if (Remaining == 0)
1979 {
1980 goto Leave;
1981 }
1982
1983 /* Acquire spinlock for ExpPagedLookasideListHead */
1984 OldIrql = KfAcquireSpinLock(&ExpPagedLookasideListLock);
1985
1986 /* Copy info from paged lookaside lists */
1987 ExpCopyLookasideInformation(&Info,
1988 &Remaining,
1989 &ExpPagedLookasideListHead,
1990 TRUE);
1991
1992 /* Release spinlock for ExpPagedLookasideListHead */
1993 KfReleaseSpinLock(&ExpPagedLookasideListLock, OldIrql);
1994
1995 Leave:
1996
1997 /* Release the locked user buffer */
1998 ExUnlockUserBuffer(Mdl);
1999
2000 /* Return the size of the actually written data */
2001 *ReqSize = (MaxCount - Remaining) * sizeof(SYSTEM_LOOKASIDE_INFORMATION);
2002 return STATUS_SUCCESS;
2003 }
2004
2005
2006 /* Class 46 - Set time slip event */
2007 SSI_DEF(SystemSetTimeSlipEvent)
2008 {
2009 /* FIXME */
2010 DPRINT1("NtSetSystemInformation - SystemSetTimSlipEvent not implemented\n");
2011 return STATUS_NOT_IMPLEMENTED;
2012 }
2013
2014 NTSTATUS
2015 NTAPI
2016 MmSessionCreate(OUT PULONG SessionId);
2017
2018 NTSTATUS
2019 NTAPI
2020 MmSessionDelete(IN ULONG SessionId);
2021
2022 /* Class 47 - Create a new session (TSE) */
2023 SSI_DEF(SystemCreateSession)
2024 {
2025 ULONG SessionId;
2026 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2027 NTSTATUS Status;
2028
2029 if (Size != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2030
2031 if (PreviousMode != KernelMode)
2032 {
2033 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2034 {
2035 return STATUS_PRIVILEGE_NOT_HELD;
2036 }
2037 }
2038
2039 Status = MmSessionCreate(&SessionId);
2040 if (NT_SUCCESS(Status)) *(PULONG)Buffer = SessionId;
2041
2042 return Status;
2043 }
2044
2045
2046 /* Class 48 - Delete an existing session (TSE) */
2047 SSI_DEF(SystemDeleteSession)
2048 {
2049 ULONG SessionId;
2050 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2051
2052 if (Size != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2053
2054 if (PreviousMode != KernelMode)
2055 {
2056 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2057 {
2058 return STATUS_PRIVILEGE_NOT_HELD;
2059 }
2060 }
2061
2062 SessionId = *(PULONG)Buffer;
2063
2064 return MmSessionDelete(SessionId);
2065 }
2066
2067
2068 /* Class 49 - UNKNOWN */
2069 QSI_DEF(SystemInvalidInfoClass4)
2070 {
2071 /* FIXME */
2072 DPRINT1("NtQuerySystemInformation - SystemInvalidInfoClass4 not implemented\n");
2073 return STATUS_NOT_IMPLEMENTED;
2074 }
2075
2076
2077 /* Class 50 - System range start address */
2078 QSI_DEF(SystemRangeStartInformation)
2079 {
2080 /* Check user buffer's size */
2081 if (Size != sizeof(ULONG_PTR)) return STATUS_INFO_LENGTH_MISMATCH;
2082
2083 *(PULONG_PTR)Buffer = (ULONG_PTR)MmSystemRangeStart;
2084
2085 if (ReqSize) *ReqSize = sizeof(ULONG_PTR);
2086
2087 return STATUS_SUCCESS;
2088 }
2089
2090 /* Class 51 - Driver verifier information */
2091 QSI_DEF(SystemVerifierInformation)
2092 {
2093 /* FIXME */
2094 DPRINT1("NtQuerySystemInformation - SystemVerifierInformation not implemented\n");
2095 return STATUS_NOT_IMPLEMENTED;
2096 }
2097
2098
2099 SSI_DEF(SystemVerifierInformation)
2100 {
2101 /* FIXME */
2102 DPRINT1("NtSetSystemInformation - SystemVerifierInformation not implemented\n");
2103 return STATUS_NOT_IMPLEMENTED;
2104 }
2105
2106
2107 /* Class 52 - Add a driver verifier */
2108 SSI_DEF(SystemAddVerifier)
2109 {
2110 /* FIXME */
2111 DPRINT1("NtSetSystemInformation - SystemAddVerifier not implemented\n");
2112 return STATUS_NOT_IMPLEMENTED;
2113 }
2114
2115
2116 /* Class 53 - A session's processes */
2117 QSI_DEF(SystemSessionProcessesInformation)
2118 {
2119 /* FIXME */
2120 DPRINT1("NtQuerySystemInformation - SystemSessionProcessInformation not implemented\n");
2121 return STATUS_NOT_IMPLEMENTED;
2122 }
2123
2124
2125 /* Query/Set Calls Table */
2126 typedef
2127 struct _QSSI_CALLS
2128 {
2129 NTSTATUS (* Query) (PVOID,ULONG,PULONG);
2130 NTSTATUS (* Set) (PVOID,ULONG);
2131
2132 } QSSI_CALLS;
2133
2134 // QS Query & Set
2135 // QX Query
2136 // XS Set
2137 // XX unknown behaviour
2138 //
2139 #define SI_QS(n) {QSI_USE(n),SSI_USE(n)}
2140 #define SI_QX(n) {QSI_USE(n),NULL}
2141 #define SI_XS(n) {NULL,SSI_USE(n)}
2142 #define SI_XX(n) {NULL,NULL}
2143
2144 static
2145 QSSI_CALLS
2146 CallQS [] =
2147 {
2148 SI_QX(SystemBasicInformation),
2149 SI_QX(SystemProcessorInformation),
2150 SI_QX(SystemPerformanceInformation),
2151 SI_QX(SystemTimeOfDayInformation),
2152 SI_QX(SystemPathInformation), /* should be SI_XX */
2153 SI_QX(SystemProcessInformation), // aka SystemProcessesAndThreadsInformation
2154 SI_QX(SystemCallCountInformation), // aka SystemCallCounts
2155 SI_QX(SystemDeviceInformation), // aka SystemConfigurationInformation
2156 SI_QX(SystemProcessorPerformanceInformation), // aka SystemProcessorTimes
2157 SI_QS(SystemFlagsInformation), // aka SystemGlobalFlag
2158 SI_QX(SystemCallTimeInformation), /* should be SI_XX */
2159 SI_QX(SystemModuleInformation),
2160 SI_QX(SystemLocksInformation), // aka SystemLockInformation
2161 SI_QX(SystemStackTraceInformation), /* should be SI_XX */
2162 SI_QX(SystemPagedPoolInformation), /* should be SI_XX */
2163 SI_QX(SystemNonPagedPoolInformation), /* should be SI_XX */
2164 SI_QX(SystemHandleInformation),
2165 SI_QX(SystemObjectInformation),
2166 SI_QX(SystemPageFileInformation), // aka SystemPagefileInformation
2167 SI_QX(SystemVdmInstemulInformation), // aka SystemInstructionEmulationCounts
2168 SI_QX(SystemVdmBopInformation), /* it should be SI_XX */
2169 SI_QS(SystemFileCacheInformation), // aka SystemCacheInformation
2170 SI_QX(SystemPoolTagInformation),
2171 SI_QX(SystemInterruptInformation), // aka SystemProcessorStatistics
2172 SI_QS(SystemDpcBehaviourInformation), // aka SystemDpcInformation
2173 SI_QX(SystemFullMemoryInformation), /* it should be SI_XX */
2174 SI_XS(SystemLoadGdiDriverInformation), // correct: SystemLoadImage
2175 SI_XS(SystemUnloadGdiDriverInformation), // correct: SystemUnloadImage
2176 SI_QS(SystemTimeAdjustmentInformation), // aka SystemTimeAdjustment
2177 SI_QX(SystemSummaryMemoryInformation), /* it should be SI_XX */
2178 SI_QX(SystemNextEventIdInformation), /* it should be SI_XX */
2179 SI_QX(SystemEventIdsInformation), /* it should be SI_XX */ // SystemPerformanceTraceInformation
2180 SI_QX(SystemCrashDumpInformation),
2181 SI_QX(SystemExceptionInformation),
2182 SI_QX(SystemCrashDumpStateInformation),
2183 SI_QX(SystemKernelDebuggerInformation),
2184 SI_QX(SystemContextSwitchInformation),
2185 SI_QS(SystemRegistryQuotaInformation),
2186 SI_XS(SystemExtendServiceTableInformation), // correct: SystemLoadAndCallImage
2187 SI_XS(SystemPrioritySeperation),
2188 SI_QX(SystemPlugPlayBusInformation), /* it should be SI_XX */
2189 SI_QX(SystemDockInformation), /* it should be SI_XX */
2190 SI_QX(SystemPowerInformation), /* it should be SI_XX */ // SystemPowerInformationNative? SystemInvalidInfoClass2
2191 SI_QX(SystemProcessorSpeedInformation), /* it should be SI_XX */
2192 SI_QS(SystemCurrentTimeZoneInformation), /* it should be SI_QX */ // aka SystemTimeZoneInformation
2193 SI_QX(SystemLookasideInformation),
2194 SI_XS(SystemSetTimeSlipEvent),
2195 SI_XS(SystemCreateSession),
2196 SI_XS(SystemDeleteSession),
2197 SI_QX(SystemInvalidInfoClass4), /* it should be SI_XX */ // SystemSessionInformation?
2198 SI_QX(SystemRangeStartInformation),
2199 SI_QS(SystemVerifierInformation),
2200 SI_XS(SystemAddVerifier),
2201 SI_QX(SystemSessionProcessesInformation)
2202 };
2203
2204 C_ASSERT(SystemBasicInformation == 0);
2205 #define MIN_SYSTEM_INFO_CLASS (SystemBasicInformation)
2206 #define MAX_SYSTEM_INFO_CLASS (sizeof(CallQS) / sizeof(CallQS[0]))
2207
2208 /*
2209 * @implemented
2210 */
2211 NTSTATUS NTAPI
2212 NtQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
2213 OUT PVOID SystemInformation,
2214 IN ULONG Length,
2215 OUT PULONG UnsafeResultLength)
2216 {
2217 KPROCESSOR_MODE PreviousMode;
2218 ULONG ResultLength = 0;
2219 NTSTATUS FStatus = STATUS_NOT_IMPLEMENTED;
2220
2221 PAGED_CODE();
2222
2223 PreviousMode = ExGetPreviousMode();
2224
2225 _SEH2_TRY
2226 {
2227 if (PreviousMode != KernelMode)
2228 {
2229 /* SystemKernelDebuggerInformation needs only BOOLEAN alignment */
2230 ProbeForWrite(SystemInformation, Length, 1);
2231 if (UnsafeResultLength != NULL)
2232 ProbeForWriteUlong(UnsafeResultLength);
2233 }
2234
2235 if (UnsafeResultLength)
2236 *UnsafeResultLength = 0;
2237
2238 /*
2239 * Check if the request is valid.
2240 */
2241 if (SystemInformationClass >= MAX_SYSTEM_INFO_CLASS)
2242 {
2243 _SEH2_YIELD(return STATUS_INVALID_INFO_CLASS);
2244 }
2245
2246 if (NULL != CallQS [SystemInformationClass].Query)
2247 {
2248 /*
2249 * Hand the request to a subhandler.
2250 */
2251 FStatus = CallQS [SystemInformationClass].Query(SystemInformation,
2252 Length,
2253 &ResultLength);
2254
2255 /* Save the result length to the caller */
2256 if (UnsafeResultLength)
2257 *UnsafeResultLength = ResultLength;
2258 }
2259 }
2260 _SEH2_EXCEPT(ExSystemExceptionFilter())
2261 {
2262 FStatus = _SEH2_GetExceptionCode();
2263 }
2264 _SEH2_END;
2265
2266 return FStatus;
2267 }
2268
2269
2270 NTSTATUS
2271 NTAPI
2272 NtSetSystemInformation (IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
2273 IN PVOID SystemInformation,
2274 IN ULONG SystemInformationLength)
2275 {
2276 PAGED_CODE();
2277
2278 /*
2279 * If called from user mode, check
2280 * possible unsafe arguments.
2281 */
2282 #if 0
2283 if (KernelMode != KeGetPreviousMode())
2284 {
2285 // Check arguments
2286 //ProbeForWrite(
2287 // SystemInformation,
2288 // Length
2289 // );
2290 //ProbeForWrite(
2291 // ResultLength,
2292 // sizeof (ULONG)
2293 // );
2294 }
2295 #endif
2296 /*
2297 * Check the request is valid.
2298 */
2299 if ((SystemInformationClass >= MIN_SYSTEM_INFO_CLASS) &&
2300 (SystemInformationClass < MAX_SYSTEM_INFO_CLASS))
2301 {
2302 if (NULL != CallQS [SystemInformationClass].Set)
2303 {
2304 /*
2305 * Hand the request to a subhandler.
2306 */
2307 return CallQS [SystemInformationClass].Set(SystemInformation,
2308 SystemInformationLength);
2309 }
2310 }
2311
2312 return STATUS_INVALID_INFO_CLASS;
2313 }
2314
2315 NTSTATUS
2316 NTAPI
2317 NtFlushInstructionCache(IN HANDLE ProcessHandle,
2318 IN PVOID BaseAddress,
2319 IN ULONG NumberOfBytesToFlush)
2320 {
2321 PAGED_CODE();
2322
2323 #if defined(_M_IX86) || defined(_M_AMD64)
2324 __wbinvd();
2325 #elif defined(_M_PPC)
2326 __asm__ __volatile__("tlbsync");
2327 #elif defined(_M_MIPS)
2328 DPRINT1("NtFlushInstructionCache() is not implemented\n");
2329 for (;;);
2330 #elif defined(_M_ARM)
2331 __asm__ __volatile__("mov r1, #0; mcr p15, 0, r1, c7, c5, 0");
2332 #else
2333 #error Unknown architecture
2334 #endif
2335 return STATUS_SUCCESS;
2336 }
2337
2338 ULONG
2339 NTAPI
2340 NtGetCurrentProcessorNumber(VOID)
2341 {
2342 /* Just return the CPU */
2343 return KeGetCurrentProcessorNumber();
2344 }
2345
2346 /*
2347 * @implemented
2348 */
2349 #undef ExGetPreviousMode
2350 KPROCESSOR_MODE
2351 NTAPI
2352 ExGetPreviousMode (VOID)
2353 {
2354 return KeGetPreviousMode();
2355 }