[RTL][NTOSKRNL]
[reactos.git] / reactos / 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 length 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 TempProcessImageName;
779 _SEH2_VOLATILE PUNICODE_STRING ProcessImageName = NULL;
780 PWCHAR szSrc;
781 BOOLEAN Overflow = FALSE;
782
783 _SEH2_TRY
784 {
785 /* scan the process list */
786
787 PSYSTEM_PROCESS_INFORMATION Spi
788 = (PSYSTEM_PROCESS_INFORMATION) Buffer;
789
790 *ReqSize = sizeof(SYSTEM_PROCESS_INFORMATION);
791
792 /* Check for overflow */
793 if (Size < sizeof(SYSTEM_PROCESS_INFORMATION))
794 {
795 Overflow = TRUE;
796 }
797
798 /* Zero user's buffer */
799 if (!Overflow) RtlZeroMemory(Spi, Size);
800
801 SystemProcess = PsIdleProcess;
802 Process = SystemProcess;
803 Current = (PUCHAR) Spi;
804
805 do
806 {
807 SpiCurrent = (PSYSTEM_PROCESS_INFORMATION) Current;
808
809 if ((Process->ProcessExiting) &&
810 (Process->Pcb.Header.SignalState) &&
811 !(Process->ActiveThreads) &&
812 (IsListEmpty(&Process->Pcb.ThreadListHead)))
813 {
814 DPRINT1("Process %p (%s:%p) is a zombie\n",
815 Process, Process->ImageFileName, Process->UniqueProcessId);
816 CurrentSize = 0;
817 ImageNameMaximumLength = 0;
818 goto Skip;
819 }
820
821 ThreadsCount = 0;
822 CurrentEntry = Process->Pcb.ThreadListHead.Flink;
823 while (CurrentEntry != &Process->Pcb.ThreadListHead)
824 {
825 ThreadsCount++;
826 CurrentEntry = CurrentEntry->Flink;
827 }
828
829 // size of the structure for every process
830 CurrentSize = sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_THREAD_INFORMATION) * ThreadsCount;
831 ImageNameLength = 0;
832 Status = SeLocateProcessImageName(Process, &TempProcessImageName);
833 ProcessImageName = TempProcessImageName;
834 szSrc = NULL;
835 if (NT_SUCCESS(Status) && (ProcessImageName->Length > 0))
836 {
837 szSrc = (PWCHAR)((PCHAR)ProcessImageName->Buffer + ProcessImageName->Length);
838 /* Loop the file name*/
839 while (szSrc > ProcessImageName->Buffer)
840 {
841 /* Make sure this isn't a backslash */
842 if (*--szSrc == OBJ_NAME_PATH_SEPARATOR)
843 {
844 szSrc++;
845 break;
846 }
847 else
848 {
849 ImageNameLength += sizeof(WCHAR);
850 }
851 }
852 }
853 if (!ImageNameLength && Process != PsIdleProcess)
854 {
855 ImageNameLength = (USHORT)strlen(Process->ImageFileName) * sizeof(WCHAR);
856 }
857
858 /* Round up the image name length as NT does */
859 if (ImageNameLength > 0)
860 ImageNameMaximumLength = ROUND_UP(ImageNameLength + sizeof(WCHAR), 8);
861 else
862 ImageNameMaximumLength = 0;
863
864 TotalSize += CurrentSize + ImageNameMaximumLength;
865
866 /* Check for overflow */
867 if (TotalSize > Size)
868 {
869 Overflow = TRUE;
870 }
871
872 /* Fill system information */
873 if (!Overflow)
874 {
875 SpiCurrent->NextEntryOffset = CurrentSize + ImageNameMaximumLength; // relative offset to the beginning of the next structure
876 SpiCurrent->NumberOfThreads = ThreadsCount;
877 SpiCurrent->CreateTime = Process->CreateTime;
878 SpiCurrent->ImageName.Length = ImageNameLength;
879 SpiCurrent->ImageName.MaximumLength = ImageNameMaximumLength;
880 SpiCurrent->ImageName.Buffer = (void*)(Current + CurrentSize);
881
882 /* Copy name to the end of the struct */
883 if(Process != PsIdleProcess)
884 {
885 if (szSrc)
886 {
887 RtlCopyMemory(SpiCurrent->ImageName.Buffer, szSrc, SpiCurrent->ImageName.Length);
888 }
889 else
890 {
891 RtlInitAnsiString(&ImageName, Process->ImageFileName);
892 RtlAnsiStringToUnicodeString(&SpiCurrent->ImageName, &ImageName, FALSE);
893 }
894 }
895 else
896 {
897 RtlInitUnicodeString(&SpiCurrent->ImageName, NULL);
898 }
899
900 SpiCurrent->BasePriority = Process->Pcb.BasePriority;
901 SpiCurrent->UniqueProcessId = Process->UniqueProcessId;
902 SpiCurrent->InheritedFromUniqueProcessId = Process->InheritedFromUniqueProcessId;
903 SpiCurrent->HandleCount = ObGetProcessHandleCount(Process);
904 SpiCurrent->PeakVirtualSize = Process->PeakVirtualSize;
905 SpiCurrent->VirtualSize = Process->VirtualSize;
906 SpiCurrent->PageFaultCount = Process->Vm.PageFaultCount;
907 SpiCurrent->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
908 SpiCurrent->WorkingSetSize = Process->Vm.WorkingSetSize;
909 SpiCurrent->QuotaPeakPagedPoolUsage = Process->QuotaPeak[0];
910 SpiCurrent->QuotaPagedPoolUsage = Process->QuotaUsage[0];
911 SpiCurrent->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[1];
912 SpiCurrent->QuotaNonPagedPoolUsage = Process->QuotaUsage[1];
913 SpiCurrent->PagefileUsage = Process->QuotaUsage[2];
914 SpiCurrent->PeakPagefileUsage = Process->QuotaPeak[2];
915 SpiCurrent->PrivatePageCount = Process->CommitCharge;
916 ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(SpiCurrent + 1);
917
918 CurrentEntry = Process->Pcb.ThreadListHead.Flink;
919 while (CurrentEntry != &Process->Pcb.ThreadListHead)
920 {
921 CurrentThread = CONTAINING_RECORD(CurrentEntry, ETHREAD, Tcb.ThreadListEntry);
922
923 ThreadInfo->KernelTime.QuadPart = UInt32x32To64(CurrentThread->Tcb.KernelTime, KeMaximumIncrement);
924 ThreadInfo->UserTime.QuadPart = UInt32x32To64(CurrentThread->Tcb.UserTime, KeMaximumIncrement);
925 ThreadInfo->CreateTime.QuadPart = CurrentThread->CreateTime.QuadPart;
926 ThreadInfo->WaitTime = CurrentThread->Tcb.WaitTime;
927 ThreadInfo->StartAddress = (PVOID) CurrentThread->StartAddress;
928 ThreadInfo->ClientId = CurrentThread->Cid;
929 ThreadInfo->Priority = CurrentThread->Tcb.Priority;
930 ThreadInfo->BasePriority = CurrentThread->Tcb.BasePriority;
931 ThreadInfo->ContextSwitches = CurrentThread->Tcb.ContextSwitches;
932 ThreadInfo->ThreadState = CurrentThread->Tcb.State;
933 ThreadInfo->WaitReason = CurrentThread->Tcb.WaitReason;
934
935 ThreadInfo++;
936 CurrentEntry = CurrentEntry->Flink;
937 }
938
939 /* Query total user/kernel times of a process */
940 TotalKernel = KeQueryRuntimeProcess(&Process->Pcb, &TotalUser);
941 SpiCurrent->UserTime.QuadPart = UInt32x32To64(TotalUser, KeMaximumIncrement);
942 SpiCurrent->KernelTime.QuadPart = UInt32x32To64(TotalKernel, KeMaximumIncrement);
943 }
944
945 if (ProcessImageName)
946 {
947 /* Release the memory allocated by SeLocateProcessImageName */
948 ExFreePoolWithTag(ProcessImageName, TAG_SEPA);
949 ProcessImageName = NULL;
950 }
951
952 /* Handle idle process entry */
953 Skip:
954 if (Process == PsIdleProcess) Process = NULL;
955
956 Process = PsGetNextProcess(Process);
957 ThreadsCount = 0;
958 if ((Process == SystemProcess) || (Process == NULL))
959 {
960 if (!Overflow)
961 SpiCurrent->NextEntryOffset = 0;
962 break;
963 }
964 else
965 Current += CurrentSize + ImageNameMaximumLength;
966 } while ((Process != SystemProcess) && (Process != NULL));
967
968 if(Process != NULL)
969 ObDereferenceObject(Process);
970 Status = STATUS_SUCCESS;
971 }
972 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
973 {
974 if(Process != NULL)
975 ObDereferenceObject(Process);
976 if (ProcessImageName)
977 {
978 /* Release the memory allocated by SeLocateProcessImageName */
979 ExFreePoolWithTag(ProcessImageName, TAG_SEPA);
980 }
981
982 Status = _SEH2_GetExceptionCode();
983 }
984 _SEH2_END
985
986 if (Overflow)
987 Status = STATUS_INFO_LENGTH_MISMATCH;
988
989 *ReqSize = TotalSize;
990 return Status;
991 }
992
993 /* Class 6 - Call Count Information */
994 QSI_DEF(SystemCallCountInformation)
995 {
996 /* FIXME */
997 DPRINT1("NtQuerySystemInformation - SystemCallCountInformation not implemented\n");
998 return STATUS_NOT_IMPLEMENTED;
999 }
1000
1001 /* Class 7 - Device Information */
1002 QSI_DEF(SystemDeviceInformation)
1003 {
1004 PSYSTEM_DEVICE_INFORMATION Sdi
1005 = (PSYSTEM_DEVICE_INFORMATION) Buffer;
1006 PCONFIGURATION_INFORMATION ConfigInfo;
1007
1008 *ReqSize = sizeof(SYSTEM_DEVICE_INFORMATION);
1009
1010 /* Check user buffer's size */
1011 if (Size < sizeof(SYSTEM_DEVICE_INFORMATION))
1012 {
1013 return STATUS_INFO_LENGTH_MISMATCH;
1014 }
1015
1016 ConfigInfo = IoGetConfigurationInformation();
1017
1018 Sdi->NumberOfDisks = ConfigInfo->DiskCount;
1019 Sdi->NumberOfFloppies = ConfigInfo->FloppyCount;
1020 Sdi->NumberOfCdRoms = ConfigInfo->CdRomCount;
1021 Sdi->NumberOfTapes = ConfigInfo->TapeCount;
1022 Sdi->NumberOfSerialPorts = ConfigInfo->SerialCount;
1023 Sdi->NumberOfParallelPorts = ConfigInfo->ParallelCount;
1024
1025 return STATUS_SUCCESS;
1026 }
1027
1028 /* Class 8 - Processor Performance Information */
1029 QSI_DEF(SystemProcessorPerformanceInformation)
1030 {
1031 PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION Spi
1032 = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) Buffer;
1033
1034 LONG i;
1035 ULONG TotalTime;
1036 PKPRCB Prcb;
1037
1038 *ReqSize = KeNumberProcessors * sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
1039
1040 /* Check user buffer's size */
1041 if (Size < *ReqSize)
1042 {
1043 return STATUS_INFO_LENGTH_MISMATCH;
1044 }
1045
1046 for (i = 0; i < KeNumberProcessors; i++)
1047 {
1048 /* Get the PRCB on this processor */
1049 Prcb = KiProcessorBlock[i];
1050
1051 /* Calculate total user and kernel times */
1052 TotalTime = Prcb->IdleThread->KernelTime + Prcb->IdleThread->UserTime;
1053 Spi->IdleTime.QuadPart = UInt32x32To64(TotalTime, KeMaximumIncrement);
1054 Spi->KernelTime.QuadPart = UInt32x32To64(Prcb->KernelTime, KeMaximumIncrement);
1055 Spi->UserTime.QuadPart = UInt32x32To64(Prcb->UserTime, KeMaximumIncrement);
1056 Spi->DpcTime.QuadPart = UInt32x32To64(Prcb->DpcTime, KeMaximumIncrement);
1057 Spi->InterruptTime.QuadPart = UInt32x32To64(Prcb->InterruptTime, KeMaximumIncrement);
1058 Spi->InterruptCount = Prcb->InterruptCount;
1059 Spi++;
1060 }
1061
1062 return STATUS_SUCCESS;
1063 }
1064
1065 /* Class 9 - Flags Information */
1066 QSI_DEF(SystemFlagsInformation)
1067 {
1068 if (sizeof(SYSTEM_FLAGS_INFORMATION) != Size)
1069 {
1070 *ReqSize = sizeof(SYSTEM_FLAGS_INFORMATION);
1071 return (STATUS_INFO_LENGTH_MISMATCH);
1072 }
1073 ((PSYSTEM_FLAGS_INFORMATION) Buffer)->Flags = NtGlobalFlag;
1074 return STATUS_SUCCESS;
1075 }
1076
1077 SSI_DEF(SystemFlagsInformation)
1078 {
1079 if (sizeof(SYSTEM_FLAGS_INFORMATION) != Size)
1080 {
1081 return STATUS_INFO_LENGTH_MISMATCH;
1082 }
1083 NtGlobalFlag = ((PSYSTEM_FLAGS_INFORMATION) Buffer)->Flags;
1084 return STATUS_SUCCESS;
1085 }
1086
1087 /* Class 10 - Call Time Information */
1088 QSI_DEF(SystemCallTimeInformation)
1089 {
1090 /* FIXME */
1091 DPRINT1("NtQuerySystemInformation - SystemCallTimeInformation not implemented\n");
1092 return STATUS_NOT_IMPLEMENTED;
1093 }
1094
1095 /* Class 11 - Module Information */
1096 QSI_DEF(SystemModuleInformation)
1097 {
1098 NTSTATUS Status;
1099
1100 /* Acquire system module list lock */
1101 KeEnterCriticalRegion();
1102 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource, TRUE);
1103
1104 /* Call the generic handler with the system module list */
1105 Status = ExpQueryModuleInformation(&PsLoadedModuleList,
1106 &MmLoadedUserImageList,
1107 (PRTL_PROCESS_MODULES)Buffer,
1108 Size,
1109 ReqSize);
1110
1111 /* Release list lock and return status */
1112 ExReleaseResourceLite(&PsLoadedModuleResource);
1113 KeLeaveCriticalRegion();
1114 return Status;
1115 }
1116
1117 /* Class 12 - Locks Information */
1118 QSI_DEF(SystemLocksInformation)
1119 {
1120 /* FIXME */
1121 DPRINT1("NtQuerySystemInformation - SystemLocksInformation not implemented\n");
1122 return STATUS_NOT_IMPLEMENTED;
1123 }
1124
1125 /* Class 13 - Stack Trace Information */
1126 QSI_DEF(SystemStackTraceInformation)
1127 {
1128 /* FIXME */
1129 DPRINT1("NtQuerySystemInformation - SystemStackTraceInformation not implemented\n");
1130 return STATUS_NOT_IMPLEMENTED;
1131 }
1132
1133 /* Class 14 - Paged Pool Information */
1134 QSI_DEF(SystemPagedPoolInformation)
1135 {
1136 /* FIXME */
1137 DPRINT1("NtQuerySystemInformation - SystemPagedPoolInformation not implemented\n");
1138 return STATUS_NOT_IMPLEMENTED;
1139 }
1140
1141 /* Class 15 - Non Paged Pool Information */
1142 QSI_DEF(SystemNonPagedPoolInformation)
1143 {
1144 /* FIXME */
1145 DPRINT1("NtQuerySystemInformation - SystemNonPagedPoolInformation not implemented\n");
1146 return STATUS_NOT_IMPLEMENTED;
1147 }
1148
1149
1150 /* Class 16 - Handle Information */
1151 QSI_DEF(SystemHandleInformation)
1152 {
1153 PEPROCESS pr, syspr;
1154 ULONG curSize, i = 0;
1155 ULONG hCount = 0;
1156
1157 PSYSTEM_HANDLE_INFORMATION Shi =
1158 (PSYSTEM_HANDLE_INFORMATION) Buffer;
1159
1160 DPRINT("NtQuerySystemInformation - SystemHandleInformation\n");
1161
1162 if (Size < sizeof(SYSTEM_HANDLE_INFORMATION))
1163 {
1164 *ReqSize = sizeof(SYSTEM_HANDLE_INFORMATION);
1165 return STATUS_INFO_LENGTH_MISMATCH;
1166 }
1167
1168 DPRINT("SystemHandleInformation 1\n");
1169
1170 /* First Calc Size from Count. */
1171 syspr = PsGetNextProcess(NULL);
1172 pr = syspr;
1173
1174 do
1175 {
1176 hCount = hCount + ObGetProcessHandleCount(pr);
1177 pr = PsGetNextProcess(pr);
1178
1179 if ((pr == syspr) || (pr == NULL)) break;
1180 }
1181 while ((pr != syspr) && (pr != NULL));
1182
1183 if(pr != NULL)
1184 {
1185 ObDereferenceObject(pr);
1186 }
1187
1188 DPRINT("SystemHandleInformation 2\n");
1189
1190 curSize = sizeof(SYSTEM_HANDLE_INFORMATION) +
1191 ((sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO) * hCount) -
1192 (sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO)));
1193
1194 Shi->NumberOfHandles = hCount;
1195
1196 if (curSize > Size)
1197 {
1198 *ReqSize = curSize;
1199 return (STATUS_INFO_LENGTH_MISMATCH);
1200 }
1201
1202 DPRINT("SystemHandleInformation 3\n");
1203
1204 /* Now get Handles from all processes. */
1205 syspr = PsGetNextProcess(NULL);
1206 pr = syspr;
1207
1208 do
1209 {
1210 int Count = 0, HandleCount;
1211
1212 HandleCount = ObGetProcessHandleCount(pr);
1213
1214 for (Count = 0; HandleCount > 0 ; HandleCount--)
1215 {
1216 Shi->Handles[i].UniqueProcessId = (USHORT)(ULONG_PTR)pr->UniqueProcessId;
1217 Count++;
1218 i++;
1219 }
1220
1221 pr = PsGetNextProcess(pr);
1222
1223 if ((pr == syspr) || (pr == NULL)) break;
1224 }
1225 while ((pr != syspr) && (pr != NULL));
1226
1227 if(pr != NULL) ObDereferenceObject(pr);
1228
1229 DPRINT("SystemHandleInformation 4\n");
1230 return STATUS_SUCCESS;
1231
1232 }
1233 /*
1234 SSI_DEF(SystemHandleInformation)
1235 {
1236
1237 return STATUS_SUCCESS;
1238 }
1239 */
1240
1241 /* Class 17 - Information */
1242 QSI_DEF(SystemObjectInformation)
1243 {
1244 /* FIXME */
1245 DPRINT1("NtQuerySystemInformation - SystemObjectInformation not implemented\n");
1246 return STATUS_NOT_IMPLEMENTED;
1247 }
1248
1249 /* Class 18 - Information */
1250 QSI_DEF(SystemPageFileInformation)
1251 {
1252 UNICODE_STRING FileName; /* FIXME */
1253 SYSTEM_PAGEFILE_INFORMATION *Spfi = (SYSTEM_PAGEFILE_INFORMATION *) Buffer;
1254
1255 if (Size < sizeof(SYSTEM_PAGEFILE_INFORMATION))
1256 {
1257 * ReqSize = sizeof(SYSTEM_PAGEFILE_INFORMATION);
1258 return STATUS_INFO_LENGTH_MISMATCH;
1259 }
1260
1261 RtlInitUnicodeString(&FileName, NULL); /* FIXME */
1262
1263 /* FIXME */
1264 Spfi->NextEntryOffset = 0;
1265
1266 Spfi->TotalSize = MiFreeSwapPages + MiUsedSwapPages;
1267 Spfi->TotalInUse = MiUsedSwapPages;
1268 Spfi->PeakUsage = MiUsedSwapPages; /* FIXME */
1269 Spfi->PageFileName = FileName;
1270 return STATUS_SUCCESS;
1271 }
1272
1273 /* Class 19 - Vdm Instemul Information */
1274 QSI_DEF(SystemVdmInstemulInformation)
1275 {
1276 /* FIXME */
1277 DPRINT1("NtQuerySystemInformation - SystemVdmInstemulInformation not implemented\n");
1278 return STATUS_NOT_IMPLEMENTED;
1279 }
1280
1281 /* Class 20 - Vdm Bop Information */
1282 QSI_DEF(SystemVdmBopInformation)
1283 {
1284 /* FIXME */
1285 DPRINT1("NtQuerySystemInformation - SystemVdmBopInformation not implemented\n");
1286 return STATUS_NOT_IMPLEMENTED;
1287 }
1288
1289 /* Class 21 - File Cache Information */
1290 QSI_DEF(SystemFileCacheInformation)
1291 {
1292 SYSTEM_FILECACHE_INFORMATION *Sci = (SYSTEM_FILECACHE_INFORMATION *) Buffer;
1293
1294 if (Size < sizeof(SYSTEM_FILECACHE_INFORMATION))
1295 {
1296 *ReqSize = sizeof(SYSTEM_FILECACHE_INFORMATION);
1297 return STATUS_INFO_LENGTH_MISMATCH;
1298 }
1299
1300 RtlZeroMemory(Sci, sizeof(SYSTEM_FILECACHE_INFORMATION));
1301
1302 /* Return the Byte size not the page size. */
1303 Sci->CurrentSize =
1304 MiMemoryConsumers[MC_CACHE].PagesUsed * PAGE_SIZE;
1305 Sci->PeakSize =
1306 MiMemoryConsumers[MC_CACHE].PagesUsed * PAGE_SIZE; /* FIXME */
1307 /* Taskmgr multiplies this one by page size right away */
1308 Sci->CurrentSizeIncludingTransitionInPages =
1309 MiMemoryConsumers[MC_CACHE].PagesUsed; /* FIXME: Should be */
1310 /* system working set and standby pages. */
1311 Sci->PageFaultCount = 0; /* FIXME */
1312 Sci->MinimumWorkingSet = 0; /* FIXME */
1313 Sci->MaximumWorkingSet = 0; /* FIXME */
1314
1315 return STATUS_SUCCESS;
1316 }
1317
1318 SSI_DEF(SystemFileCacheInformation)
1319 {
1320 if (Size < sizeof(SYSTEM_FILECACHE_INFORMATION))
1321 {
1322 return STATUS_INFO_LENGTH_MISMATCH;
1323 }
1324 /* FIXME */
1325 DPRINT1("NtSetSystemInformation - SystemFileCacheInformation not implemented\n");
1326 return STATUS_NOT_IMPLEMENTED;
1327 }
1328
1329 /* Class 22 - Pool Tag Information */
1330 QSI_DEF(SystemPoolTagInformation)
1331 {
1332 if (Size < sizeof(SYSTEM_POOLTAG_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
1333 return ExGetPoolTagInfo(Buffer, Size, ReqSize);
1334 }
1335
1336 /* Class 23 - Interrupt Information for all processors */
1337 QSI_DEF(SystemInterruptInformation)
1338 {
1339 PKPRCB Prcb;
1340 LONG i;
1341 ULONG ti;
1342 PSYSTEM_INTERRUPT_INFORMATION sii = (PSYSTEM_INTERRUPT_INFORMATION)Buffer;
1343
1344 if(Size < KeNumberProcessors * sizeof(SYSTEM_INTERRUPT_INFORMATION))
1345 {
1346 return STATUS_INFO_LENGTH_MISMATCH;
1347 }
1348
1349 ti = KeQueryTimeIncrement();
1350
1351 for (i = 0; i < KeNumberProcessors; i++)
1352 {
1353 Prcb = KiProcessorBlock[i];
1354 sii->ContextSwitches = KeGetContextSwitches(Prcb);
1355 sii->DpcCount = Prcb->DpcData[0].DpcCount;
1356 sii->DpcRate = Prcb->DpcRequestRate;
1357 sii->TimeIncrement = ti;
1358 sii->DpcBypassCount = 0;
1359 sii->ApcBypassCount = 0;
1360 sii++;
1361 }
1362
1363 return STATUS_SUCCESS;
1364 }
1365
1366 /* Class 24 - DPC Behaviour Information */
1367 QSI_DEF(SystemDpcBehaviourInformation)
1368 {
1369 /* FIXME */
1370 DPRINT1("NtQuerySystemInformation - SystemDpcBehaviourInformation not implemented\n");
1371 return STATUS_NOT_IMPLEMENTED;
1372 }
1373
1374 SSI_DEF(SystemDpcBehaviourInformation)
1375 {
1376 /* FIXME */
1377 DPRINT1("NtSetSystemInformation - SystemDpcBehaviourInformation not implemented\n");
1378 return STATUS_NOT_IMPLEMENTED;
1379 }
1380
1381 /* Class 25 - Full Memory Information */
1382 QSI_DEF(SystemFullMemoryInformation)
1383 {
1384 PULONG Spi = (PULONG) Buffer;
1385
1386 PEPROCESS TheIdleProcess;
1387
1388 *ReqSize = sizeof(ULONG);
1389
1390 if (sizeof(ULONG) != Size)
1391 {
1392 return STATUS_INFO_LENGTH_MISMATCH;
1393 }
1394
1395 DPRINT("SystemFullMemoryInformation\n");
1396
1397 TheIdleProcess = PsIdleProcess;
1398
1399 DPRINT("PID: %p, KernelTime: %u PFFree: %lu PFUsed: %lu\n",
1400 TheIdleProcess->UniqueProcessId,
1401 TheIdleProcess->Pcb.KernelTime,
1402 MiFreeSwapPages,
1403 MiUsedSwapPages);
1404
1405 *Spi = MiMemoryConsumers[MC_USER].PagesUsed;
1406
1407 return STATUS_SUCCESS;
1408 }
1409
1410 /* Class 26 - Load Image */
1411 SSI_DEF(SystemLoadGdiDriverInformation)
1412 {
1413 PSYSTEM_GDI_DRIVER_INFORMATION DriverInfo = (PVOID)Buffer;
1414 UNICODE_STRING ImageName;
1415 PVOID ImageBase;
1416 PVOID SectionPointer;
1417 ULONG_PTR EntryPoint;
1418 NTSTATUS Status;
1419 ULONG DirSize;
1420 PIMAGE_NT_HEADERS NtHeader;
1421
1422 /* Validate size */
1423 if (Size != sizeof(SYSTEM_GDI_DRIVER_INFORMATION))
1424 {
1425 /* Incorrect buffer length, fail */
1426 return STATUS_INFO_LENGTH_MISMATCH;
1427 }
1428
1429 /* Only kernel mode can call this function */
1430 if (ExGetPreviousMode() != KernelMode) return STATUS_PRIVILEGE_NOT_HELD;
1431
1432 /* Load the driver */
1433 ImageName = DriverInfo->DriverName;
1434 Status = MmLoadSystemImage(&ImageName,
1435 NULL,
1436 NULL,
1437 0,
1438 &SectionPointer,
1439 &ImageBase);
1440 if (!NT_SUCCESS(Status)) return Status;
1441
1442 /* Return the export pointer */
1443 DriverInfo->ExportSectionPointer =
1444 RtlImageDirectoryEntryToData(ImageBase,
1445 TRUE,
1446 IMAGE_DIRECTORY_ENTRY_EXPORT,
1447 &DirSize);
1448
1449 /* Get the entrypoint */
1450 NtHeader = RtlImageNtHeader(ImageBase);
1451 EntryPoint = NtHeader->OptionalHeader.AddressOfEntryPoint;
1452 EntryPoint += (ULONG_PTR)ImageBase;
1453
1454 /* Save other data */
1455 DriverInfo->ImageAddress = ImageBase;
1456 DriverInfo->SectionPointer = SectionPointer;
1457 DriverInfo->EntryPoint = (PVOID)EntryPoint;
1458 DriverInfo->ImageLength = NtHeader->OptionalHeader.SizeOfImage;
1459
1460 /* All is good */
1461 return STATUS_SUCCESS;
1462 }
1463
1464 /* Class 27 - Unload Image */
1465 SSI_DEF(SystemUnloadGdiDriverInformation)
1466 {
1467 PVOID *SectionPointer = Buffer;
1468
1469 /* Validate size */
1470 if (Size != sizeof(PVOID))
1471 {
1472 /* Incorrect length, fail */
1473 return STATUS_INFO_LENGTH_MISMATCH;
1474 }
1475
1476 /* Only kernel mode can call this function */
1477 if (ExGetPreviousMode() != KernelMode) return STATUS_PRIVILEGE_NOT_HELD;
1478
1479 /* Unload the image */
1480 MmUnloadSystemImage(*SectionPointer);
1481 return STATUS_SUCCESS;
1482 }
1483
1484 /* Class 28 - Time Adjustment Information */
1485 QSI_DEF(SystemTimeAdjustmentInformation)
1486 {
1487 PSYSTEM_QUERY_TIME_ADJUST_INFORMATION TimeInfo =
1488 (PSYSTEM_QUERY_TIME_ADJUST_INFORMATION)Buffer;
1489
1490 /* Check if enough storage was provided */
1491 if (sizeof(SYSTEM_QUERY_TIME_ADJUST_INFORMATION) > Size)
1492 {
1493 * ReqSize = sizeof(SYSTEM_QUERY_TIME_ADJUST_INFORMATION);
1494 return STATUS_INFO_LENGTH_MISMATCH;
1495 }
1496
1497 /* Give time values to our caller */
1498 TimeInfo->TimeIncrement = KeMaximumIncrement;
1499 TimeInfo->TimeAdjustment = KeTimeAdjustment;
1500 TimeInfo->Enable = !KiTimeAdjustmentEnabled;
1501
1502 return STATUS_SUCCESS;
1503 }
1504
1505 SSI_DEF(SystemTimeAdjustmentInformation)
1506 {
1507 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1508 PSYSTEM_SET_TIME_ADJUST_INFORMATION TimeInfo =
1509 (PSYSTEM_SET_TIME_ADJUST_INFORMATION)Buffer;
1510
1511 /* Check size of a buffer, it must match our expectations */
1512 if (sizeof(SYSTEM_SET_TIME_ADJUST_INFORMATION) != Size)
1513 return STATUS_INFO_LENGTH_MISMATCH;
1514
1515 /* Check who is calling */
1516 if (PreviousMode != KernelMode)
1517 {
1518 /* Check access rights */
1519 if (!SeSinglePrivilegeCheck(SeSystemtimePrivilege, PreviousMode))
1520 {
1521 return STATUS_PRIVILEGE_NOT_HELD;
1522 }
1523 }
1524
1525 /* FIXME: behaviour suggests the member be named 'Disable' */
1526 if (TimeInfo->Enable)
1527 {
1528 /* Disable time adjustment and set default value */
1529 KiTimeAdjustmentEnabled = FALSE;
1530 KeTimeAdjustment = KeMaximumIncrement;
1531 }
1532 else
1533 {
1534 /* Check if a valid time adjustment value is given */
1535 if (TimeInfo->TimeAdjustment == 0) return STATUS_INVALID_PARAMETER_2;
1536
1537 /* Enable time adjustment and set the adjustment value */
1538 KiTimeAdjustmentEnabled = TRUE;
1539 KeTimeAdjustment = TimeInfo->TimeAdjustment;
1540 }
1541
1542 return STATUS_SUCCESS;
1543 }
1544
1545 /* Class 29 - Summary Memory Information */
1546 QSI_DEF(SystemSummaryMemoryInformation)
1547 {
1548 /* FIXME */
1549 DPRINT1("NtQuerySystemInformation - SystemSummaryMemoryInformation not implemented\n");
1550 return STATUS_NOT_IMPLEMENTED;
1551 }
1552
1553 /* Class 30 - Next Event Id Information */
1554 QSI_DEF(SystemNextEventIdInformation)
1555 {
1556 /* FIXME */
1557 DPRINT1("NtQuerySystemInformation - SystemNextEventIdInformation not implemented\n");
1558 return STATUS_NOT_IMPLEMENTED;
1559 }
1560
1561 /* Class 31 - Event Ids Information */
1562 QSI_DEF(SystemEventIdsInformation)
1563 {
1564 /* FIXME */
1565 DPRINT1("NtQuerySystemInformation - SystemEventIdsInformation not implemented\n");
1566 return STATUS_NOT_IMPLEMENTED;
1567 }
1568
1569 /* Class 32 - Crash Dump Information */
1570 QSI_DEF(SystemCrashDumpInformation)
1571 {
1572 /* FIXME */
1573 DPRINT1("NtQuerySystemInformation - SystemCrashDumpInformation not implemented\n");
1574 return STATUS_NOT_IMPLEMENTED;
1575 }
1576
1577 /* Class 33 - Exception Information */
1578 QSI_DEF(SystemExceptionInformation)
1579 {
1580 PSYSTEM_EXCEPTION_INFORMATION ExceptionInformation =
1581 (PSYSTEM_EXCEPTION_INFORMATION)Buffer;
1582 PKPRCB Prcb;
1583 ULONG AlignmentFixupCount = 0, ExceptionDispatchCount = 0;
1584 ULONG FloatingEmulationCount = 0, ByteWordEmulationCount = 0;
1585 CHAR i;
1586
1587 /* Check size of a buffer, it must match our expectations */
1588 if (sizeof(SYSTEM_EXCEPTION_INFORMATION) != Size)
1589 return STATUS_INFO_LENGTH_MISMATCH;
1590
1591 /* Sum up exception count information from all processors */
1592 for (i = 0; i < KeNumberProcessors; i++)
1593 {
1594 Prcb = KiProcessorBlock[i];
1595 if (Prcb)
1596 {
1597 AlignmentFixupCount += Prcb->KeAlignmentFixupCount;
1598 ExceptionDispatchCount += Prcb->KeExceptionDispatchCount;
1599 #ifndef _M_ARM
1600 FloatingEmulationCount += Prcb->KeFloatingEmulationCount;
1601 #endif // _M_ARM
1602 }
1603 }
1604
1605 /* Save information in user's buffer */
1606 ExceptionInformation->AlignmentFixupCount = AlignmentFixupCount;
1607 ExceptionInformation->ExceptionDispatchCount = ExceptionDispatchCount;
1608 ExceptionInformation->FloatingEmulationCount = FloatingEmulationCount;
1609 ExceptionInformation->ByteWordEmulationCount = ByteWordEmulationCount;
1610
1611 return STATUS_SUCCESS;
1612 }
1613
1614 /* Class 34 - Crash Dump State Information */
1615 QSI_DEF(SystemCrashDumpStateInformation)
1616 {
1617 /* FIXME */
1618 DPRINT1("NtQuerySystemInformation - SystemCrashDumpStateInformation not implemented\n");
1619 return STATUS_NOT_IMPLEMENTED;
1620 }
1621
1622 /* Class 35 - Kernel Debugger Information */
1623 QSI_DEF(SystemKernelDebuggerInformation)
1624 {
1625 PSYSTEM_KERNEL_DEBUGGER_INFORMATION skdi = (PSYSTEM_KERNEL_DEBUGGER_INFORMATION) Buffer;
1626
1627 *ReqSize = sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION);
1628 if (Size < sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION))
1629 {
1630 return STATUS_INFO_LENGTH_MISMATCH;
1631 }
1632
1633 skdi->KernelDebuggerEnabled = KD_DEBUGGER_ENABLED;
1634 skdi->KernelDebuggerNotPresent = KD_DEBUGGER_NOT_PRESENT;
1635
1636 return STATUS_SUCCESS;
1637 }
1638
1639 /* Class 36 - Context Switch Information */
1640 QSI_DEF(SystemContextSwitchInformation)
1641 {
1642 PSYSTEM_CONTEXT_SWITCH_INFORMATION ContextSwitchInformation =
1643 (PSYSTEM_CONTEXT_SWITCH_INFORMATION)Buffer;
1644 ULONG ContextSwitches;
1645 PKPRCB Prcb;
1646 CHAR i;
1647
1648 /* Check size of a buffer, it must match our expectations */
1649 if (sizeof(SYSTEM_CONTEXT_SWITCH_INFORMATION) != Size)
1650 return STATUS_INFO_LENGTH_MISMATCH;
1651
1652 /* Calculate total value of context switches across all processors */
1653 ContextSwitches = 0;
1654 for (i = 0; i < KeNumberProcessors; i ++)
1655 {
1656 Prcb = KiProcessorBlock[i];
1657 if (Prcb)
1658 {
1659 ContextSwitches += KeGetContextSwitches(Prcb);
1660 }
1661 }
1662
1663 ContextSwitchInformation->ContextSwitches = ContextSwitches;
1664
1665 /* FIXME */
1666 ContextSwitchInformation->FindAny = 0;
1667 ContextSwitchInformation->FindLast = 0;
1668 ContextSwitchInformation->FindIdeal = 0;
1669 ContextSwitchInformation->IdleAny = 0;
1670 ContextSwitchInformation->IdleCurrent = 0;
1671 ContextSwitchInformation->IdleLast = 0;
1672 ContextSwitchInformation->IdleIdeal = 0;
1673 ContextSwitchInformation->PreemptAny = 0;
1674 ContextSwitchInformation->PreemptCurrent = 0;
1675 ContextSwitchInformation->PreemptLast = 0;
1676 ContextSwitchInformation->SwitchToIdle = 0;
1677
1678 return STATUS_SUCCESS;
1679 }
1680
1681 /* Class 37 - Registry Quota Information */
1682 QSI_DEF(SystemRegistryQuotaInformation)
1683 {
1684 PSYSTEM_REGISTRY_QUOTA_INFORMATION srqi = (PSYSTEM_REGISTRY_QUOTA_INFORMATION) Buffer;
1685
1686 *ReqSize = sizeof(SYSTEM_REGISTRY_QUOTA_INFORMATION);
1687 if (Size < sizeof(SYSTEM_REGISTRY_QUOTA_INFORMATION))
1688 {
1689 return STATUS_INFO_LENGTH_MISMATCH;
1690 }
1691
1692 DPRINT1("Faking max registry size of 32 MB\n");
1693 srqi->RegistryQuotaAllowed = 0x2000000;
1694 srqi->RegistryQuotaUsed = 0x200000;
1695 srqi->PagedPoolSize = 0x200000;
1696
1697 return STATUS_SUCCESS;
1698 }
1699
1700 SSI_DEF(SystemRegistryQuotaInformation)
1701 {
1702 /* FIXME */
1703 DPRINT1("NtSetSystemInformation - SystemRegistryQuotaInformation not implemented\n");
1704 return STATUS_NOT_IMPLEMENTED;
1705 }
1706
1707 /* Class 38 - Load And Call Image */
1708 SSI_DEF(SystemExtendServiceTableInformation)
1709 {
1710 UNICODE_STRING ImageName;
1711 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1712 PLDR_DATA_TABLE_ENTRY ModuleObject;
1713 NTSTATUS Status;
1714 PIMAGE_NT_HEADERS NtHeader;
1715 DRIVER_OBJECT Win32k;
1716 PDRIVER_INITIALIZE DriverInit;
1717 PVOID ImageBase;
1718 ULONG_PTR EntryPoint;
1719
1720 /* Validate the size */
1721 if (Size != sizeof(UNICODE_STRING)) return STATUS_INFO_LENGTH_MISMATCH;
1722
1723 /* Check who is calling */
1724 if (PreviousMode != KernelMode)
1725 {
1726 static const UNICODE_STRING Win32kName =
1727 RTL_CONSTANT_STRING(L"\\SystemRoot\\System32\\win32k.sys");
1728
1729 /* Make sure we can load drivers */
1730 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, UserMode))
1731 {
1732 /* FIXME: We can't, fail */
1733 return STATUS_PRIVILEGE_NOT_HELD;
1734 }
1735
1736 _SEH2_TRY
1737 {
1738 /* Probe and copy the unicode string */
1739 ProbeForRead(Buffer, sizeof(ImageName), 1);
1740 ImageName = *(PUNICODE_STRING)Buffer;
1741
1742 /* Probe the string buffer */
1743 ProbeForRead(ImageName.Buffer, ImageName.Length, sizeof(WCHAR));
1744
1745 /* Check if we have the correct name (nothing else is allowed!) */
1746 if (!RtlEqualUnicodeString(&ImageName, &Win32kName, FALSE))
1747 {
1748 _SEH2_YIELD(return STATUS_PRIVILEGE_NOT_HELD);
1749 }
1750 }
1751 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1752 {
1753 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1754 }
1755 _SEH2_END;
1756
1757 /* Recursively call the function, so that we are from kernel mode */
1758 return ZwSetSystemInformation(SystemExtendServiceTableInformation,
1759 (PVOID)&Win32kName,
1760 sizeof(Win32kName));
1761 }
1762
1763 /* Load the image */
1764 Status = MmLoadSystemImage((PUNICODE_STRING)Buffer,
1765 NULL,
1766 NULL,
1767 0,
1768 (PVOID)&ModuleObject,
1769 &ImageBase);
1770
1771 if (!NT_SUCCESS(Status)) return Status;
1772
1773 /* Get the headers */
1774 NtHeader = RtlImageNtHeader(ImageBase);
1775 if (!NtHeader)
1776 {
1777 /* Fail */
1778 MmUnloadSystemImage(ModuleObject);
1779 return STATUS_INVALID_IMAGE_FORMAT;
1780 }
1781
1782 /* Get the entrypoint */
1783 EntryPoint = NtHeader->OptionalHeader.AddressOfEntryPoint;
1784 EntryPoint += (ULONG_PTR)ImageBase;
1785 DriverInit = (PDRIVER_INITIALIZE)EntryPoint;
1786
1787 /* Create a dummy device */
1788 RtlZeroMemory(&Win32k, sizeof(Win32k));
1789 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
1790 Win32k.DriverStart = ImageBase;
1791
1792 /* Call it */
1793 Status = (DriverInit)(&Win32k, NULL);
1794 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
1795
1796 /* Unload if we failed */
1797 if (!NT_SUCCESS(Status)) MmUnloadSystemImage(ModuleObject);
1798 return Status;
1799 }
1800
1801 /* Class 39 - Priority Separation */
1802 SSI_DEF(SystemPrioritySeperation)
1803 {
1804 /* Check if the size is correct */
1805 if (Size != sizeof(ULONG))
1806 {
1807 return STATUS_INFO_LENGTH_MISMATCH;
1808 }
1809
1810 /* We need the TCB privilege */
1811 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, ExGetPreviousMode()))
1812 {
1813 return STATUS_PRIVILEGE_NOT_HELD;
1814 }
1815
1816 /* Modify the quantum table */
1817 PsChangeQuantumTable(TRUE, *(PULONG)Buffer);
1818
1819 return STATUS_SUCCESS;
1820 }
1821
1822 /* Class 40 - Plug Play Bus Information */
1823 QSI_DEF(SystemPlugPlayBusInformation)
1824 {
1825 /* FIXME */
1826 DPRINT1("NtQuerySystemInformation - SystemPlugPlayBusInformation not implemented\n");
1827 return STATUS_NOT_IMPLEMENTED;
1828 }
1829
1830 /* Class 41 - Dock Information */
1831 QSI_DEF(SystemDockInformation)
1832 {
1833 /* FIXME */
1834 DPRINT1("NtQuerySystemInformation - SystemDockInformation not implemented\n");
1835 return STATUS_NOT_IMPLEMENTED;
1836 }
1837
1838 /* Class 42 - Power Information */
1839 QSI_DEF(SystemPowerInformation)
1840 {
1841 /* FIXME */
1842 DPRINT1("NtQuerySystemInformation - SystemPowerInformation not implemented\n");
1843 return STATUS_NOT_IMPLEMENTED;
1844 }
1845
1846 /* Class 43 - Processor Speed Information */
1847 QSI_DEF(SystemProcessorSpeedInformation)
1848 {
1849 /* FIXME */
1850 DPRINT1("NtQuerySystemInformation - SystemProcessorSpeedInformation not implemented\n");
1851 return STATUS_NOT_IMPLEMENTED;
1852 }
1853
1854 /* Class 44 - Current Time Zone Information */
1855 QSI_DEF(SystemCurrentTimeZoneInformation)
1856 {
1857 *ReqSize = sizeof(TIME_ZONE_INFORMATION);
1858
1859 if (sizeof(TIME_ZONE_INFORMATION) != Size)
1860 {
1861 return STATUS_INFO_LENGTH_MISMATCH;
1862 }
1863
1864 /* Copy the time zone information struct */
1865 memcpy(Buffer,
1866 &ExpTimeZoneInfo,
1867 sizeof(TIME_ZONE_INFORMATION));
1868
1869 return STATUS_SUCCESS;
1870 }
1871
1872
1873 SSI_DEF(SystemCurrentTimeZoneInformation)
1874 {
1875 /* Check user buffer's size */
1876 if (Size < sizeof(TIME_ZONE_INFORMATION))
1877 {
1878 return STATUS_INFO_LENGTH_MISMATCH;
1879 }
1880
1881 return ExpSetTimeZoneInformation((PTIME_ZONE_INFORMATION)Buffer);
1882 }
1883
1884 static
1885 VOID
1886 ExpCopyLookasideInformation(
1887 PSYSTEM_LOOKASIDE_INFORMATION *InfoPointer,
1888 PULONG RemainingPointer,
1889 PLIST_ENTRY ListHead,
1890 BOOLEAN ListUsesMisses)
1891
1892 {
1893 PSYSTEM_LOOKASIDE_INFORMATION Info;
1894 PGENERAL_LOOKASIDE LookasideList;
1895 PLIST_ENTRY ListEntry;
1896 ULONG Remaining;
1897
1898 /* Get info pointer and remaining count of free array element */
1899 Info = *InfoPointer;
1900 Remaining = *RemainingPointer;
1901
1902 /* Loop as long as we have lookaside lists and free array elements */
1903 for (ListEntry = ListHead->Flink;
1904 (ListEntry != ListHead) && (Remaining > 0);
1905 ListEntry = ListEntry->Flink, Remaining--)
1906 {
1907 LookasideList = CONTAINING_RECORD(ListEntry, GENERAL_LOOKASIDE, ListEntry);
1908
1909 /* Fill the next array element */
1910 Info->CurrentDepth = LookasideList->Depth;
1911 Info->MaximumDepth = LookasideList->MaximumDepth;
1912 Info->TotalAllocates = LookasideList->TotalAllocates;
1913 Info->TotalFrees = LookasideList->TotalFrees;
1914 Info->Type = LookasideList->Type;
1915 Info->Tag = LookasideList->Tag;
1916 Info->Size = LookasideList->Size;
1917
1918 /* Check how the lists track misses/hits */
1919 if (ListUsesMisses)
1920 {
1921 /* Copy misses */
1922 Info->AllocateMisses = LookasideList->AllocateMisses;
1923 Info->FreeMisses = LookasideList->FreeMisses;
1924 }
1925 else
1926 {
1927 /* Calculate misses */
1928 Info->AllocateMisses = LookasideList->TotalAllocates
1929 - LookasideList->AllocateHits;
1930 Info->FreeMisses = LookasideList->TotalFrees
1931 - LookasideList->FreeHits;
1932 }
1933 }
1934
1935 /* Return the updated pointer and remaining count */
1936 *InfoPointer = Info;
1937 *RemainingPointer = Remaining;
1938 }
1939
1940 /* Class 45 - Lookaside Information */
1941 QSI_DEF(SystemLookasideInformation)
1942 {
1943 KPROCESSOR_MODE PreviousMode;
1944 PSYSTEM_LOOKASIDE_INFORMATION Info;
1945 PMDL Mdl;
1946 ULONG MaxCount, Remaining;
1947 KIRQL OldIrql;
1948 NTSTATUS Status;
1949
1950 /* First we need to lock down the memory, since we are going to access it
1951 at high IRQL */
1952 PreviousMode = ExGetPreviousMode();
1953 Status = ExLockUserBuffer(Buffer,
1954 Size,
1955 PreviousMode,
1956 IoWriteAccess,
1957 (PVOID*)&Info,
1958 &Mdl);
1959 if (!NT_SUCCESS(Status))
1960 {
1961 DPRINT1("Failed to lock the user buffer: 0x%lx\n", Status);
1962 return Status;
1963 }
1964
1965 /* Calculate how many items we can store */
1966 Remaining = MaxCount = Size / sizeof(SYSTEM_LOOKASIDE_INFORMATION);
1967 if (Remaining == 0)
1968 {
1969 goto Leave;
1970 }
1971
1972 /* Copy info from pool lookaside lists */
1973 ExpCopyLookasideInformation(&Info,
1974 &Remaining,
1975 &ExPoolLookasideListHead,
1976 FALSE);
1977 if (Remaining == 0)
1978 {
1979 goto Leave;
1980 }
1981
1982 /* Copy info from system lookaside lists */
1983 ExpCopyLookasideInformation(&Info,
1984 &Remaining,
1985 &ExSystemLookasideListHead,
1986 TRUE);
1987 if (Remaining == 0)
1988 {
1989 goto Leave;
1990 }
1991
1992 /* Acquire spinlock for ExpNonPagedLookasideListHead */
1993 KeAcquireSpinLock(&ExpNonPagedLookasideListLock, &OldIrql);
1994
1995 /* Copy info from non-paged lookaside lists */
1996 ExpCopyLookasideInformation(&Info,
1997 &Remaining,
1998 &ExpNonPagedLookasideListHead,
1999 TRUE);
2000
2001 /* Release spinlock for ExpNonPagedLookasideListHead */
2002 KeReleaseSpinLock(&ExpNonPagedLookasideListLock, OldIrql);
2003
2004 if (Remaining == 0)
2005 {
2006 goto Leave;
2007 }
2008
2009 /* Acquire spinlock for ExpPagedLookasideListHead */
2010 KeAcquireSpinLock(&ExpPagedLookasideListLock, &OldIrql);
2011
2012 /* Copy info from paged lookaside lists */
2013 ExpCopyLookasideInformation(&Info,
2014 &Remaining,
2015 &ExpPagedLookasideListHead,
2016 TRUE);
2017
2018 /* Release spinlock for ExpPagedLookasideListHead */
2019 KeReleaseSpinLock(&ExpPagedLookasideListLock, OldIrql);
2020
2021 Leave:
2022
2023 /* Release the locked user buffer */
2024 ExUnlockUserBuffer(Mdl);
2025
2026 /* Return the size of the actually written data */
2027 *ReqSize = (MaxCount - Remaining) * sizeof(SYSTEM_LOOKASIDE_INFORMATION);
2028 return STATUS_SUCCESS;
2029 }
2030
2031
2032 /* Class 46 - Set time slip event */
2033 SSI_DEF(SystemSetTimeSlipEvent)
2034 {
2035 /* FIXME */
2036 DPRINT1("NtSetSystemInformation - SystemSetTimSlipEvent not implemented\n");
2037 return STATUS_NOT_IMPLEMENTED;
2038 }
2039
2040 NTSTATUS
2041 NTAPI
2042 MmSessionCreate(OUT PULONG SessionId);
2043
2044 NTSTATUS
2045 NTAPI
2046 MmSessionDelete(IN ULONG SessionId);
2047
2048 /* Class 47 - Create a new session (TSE) */
2049 SSI_DEF(SystemCreateSession)
2050 {
2051 ULONG SessionId;
2052 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2053 NTSTATUS Status;
2054
2055 if (Size != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2056
2057 if (PreviousMode != KernelMode)
2058 {
2059 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2060 {
2061 return STATUS_PRIVILEGE_NOT_HELD;
2062 }
2063 }
2064
2065 Status = MmSessionCreate(&SessionId);
2066 if (NT_SUCCESS(Status)) *(PULONG)Buffer = SessionId;
2067
2068 return Status;
2069 }
2070
2071
2072 /* Class 48 - Delete an existing session (TSE) */
2073 SSI_DEF(SystemDeleteSession)
2074 {
2075 ULONG SessionId;
2076 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2077
2078 if (Size != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2079
2080 if (PreviousMode != KernelMode)
2081 {
2082 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2083 {
2084 return STATUS_PRIVILEGE_NOT_HELD;
2085 }
2086 }
2087
2088 SessionId = *(PULONG)Buffer;
2089
2090 return MmSessionDelete(SessionId);
2091 }
2092
2093
2094 /* Class 49 - UNKNOWN */
2095 QSI_DEF(SystemInvalidInfoClass4)
2096 {
2097 /* FIXME */
2098 DPRINT1("NtQuerySystemInformation - SystemInvalidInfoClass4 not implemented\n");
2099 return STATUS_NOT_IMPLEMENTED;
2100 }
2101
2102
2103 /* Class 50 - System range start address */
2104 QSI_DEF(SystemRangeStartInformation)
2105 {
2106 /* Check user buffer's size */
2107 if (Size != sizeof(ULONG_PTR)) return STATUS_INFO_LENGTH_MISMATCH;
2108
2109 *(PULONG_PTR)Buffer = (ULONG_PTR)MmSystemRangeStart;
2110
2111 if (ReqSize) *ReqSize = sizeof(ULONG_PTR);
2112
2113 return STATUS_SUCCESS;
2114 }
2115
2116 /* Class 51 - Driver verifier information */
2117 QSI_DEF(SystemVerifierInformation)
2118 {
2119 /* FIXME */
2120 DPRINT1("NtQuerySystemInformation - SystemVerifierInformation not implemented\n");
2121 return STATUS_NOT_IMPLEMENTED;
2122 }
2123
2124
2125 SSI_DEF(SystemVerifierInformation)
2126 {
2127 /* FIXME */
2128 DPRINT1("NtSetSystemInformation - SystemVerifierInformation not implemented\n");
2129 return STATUS_NOT_IMPLEMENTED;
2130 }
2131
2132
2133 /* Class 52 - Add a driver verifier */
2134 SSI_DEF(SystemAddVerifier)
2135 {
2136 /* FIXME */
2137 DPRINT1("NtSetSystemInformation - SystemAddVerifier not implemented\n");
2138 return STATUS_NOT_IMPLEMENTED;
2139 }
2140
2141
2142 /* Class 53 - A session's processes */
2143 QSI_DEF(SystemSessionProcessesInformation)
2144 {
2145 /* FIXME */
2146 DPRINT1("NtQuerySystemInformation - SystemSessionProcessInformation not implemented\n");
2147 return STATUS_NOT_IMPLEMENTED;
2148 }
2149
2150
2151 /* Query/Set Calls Table */
2152 typedef
2153 struct _QSSI_CALLS
2154 {
2155 NTSTATUS (* Query) (PVOID,ULONG,PULONG);
2156 NTSTATUS (* Set) (PVOID,ULONG);
2157
2158 } QSSI_CALLS;
2159
2160 // QS Query & Set
2161 // QX Query
2162 // XS Set
2163 // XX unknown behaviour
2164 //
2165 #define SI_QS(n) {QSI_USE(n),SSI_USE(n)}
2166 #define SI_QX(n) {QSI_USE(n),NULL}
2167 #define SI_XS(n) {NULL,SSI_USE(n)}
2168 #define SI_XX(n) {NULL,NULL}
2169
2170 static
2171 QSSI_CALLS
2172 CallQS [] =
2173 {
2174 SI_QX(SystemBasicInformation),
2175 SI_QX(SystemProcessorInformation),
2176 SI_QX(SystemPerformanceInformation),
2177 SI_QX(SystemTimeOfDayInformation),
2178 SI_QX(SystemPathInformation), /* should be SI_XX */
2179 SI_QX(SystemProcessInformation), // aka SystemProcessesAndThreadsInformation
2180 SI_QX(SystemCallCountInformation), // aka SystemCallCounts
2181 SI_QX(SystemDeviceInformation), // aka SystemConfigurationInformation
2182 SI_QX(SystemProcessorPerformanceInformation), // aka SystemProcessorTimes
2183 SI_QS(SystemFlagsInformation), // aka SystemGlobalFlag
2184 SI_QX(SystemCallTimeInformation), /* should be SI_XX */
2185 SI_QX(SystemModuleInformation),
2186 SI_QX(SystemLocksInformation), // aka SystemLockInformation
2187 SI_QX(SystemStackTraceInformation), /* should be SI_XX */
2188 SI_QX(SystemPagedPoolInformation), /* should be SI_XX */
2189 SI_QX(SystemNonPagedPoolInformation), /* should be SI_XX */
2190 SI_QX(SystemHandleInformation),
2191 SI_QX(SystemObjectInformation),
2192 SI_QX(SystemPageFileInformation), // aka SystemPagefileInformation
2193 SI_QX(SystemVdmInstemulInformation), // aka SystemInstructionEmulationCounts
2194 SI_QX(SystemVdmBopInformation), /* it should be SI_XX */
2195 SI_QS(SystemFileCacheInformation), // aka SystemCacheInformation
2196 SI_QX(SystemPoolTagInformation),
2197 SI_QX(SystemInterruptInformation), // aka SystemProcessorStatistics
2198 SI_QS(SystemDpcBehaviourInformation), // aka SystemDpcInformation
2199 SI_QX(SystemFullMemoryInformation), /* it should be SI_XX */
2200 SI_XS(SystemLoadGdiDriverInformation), // correct: SystemLoadImage
2201 SI_XS(SystemUnloadGdiDriverInformation), // correct: SystemUnloadImage
2202 SI_QS(SystemTimeAdjustmentInformation), // aka SystemTimeAdjustment
2203 SI_QX(SystemSummaryMemoryInformation), /* it should be SI_XX */
2204 SI_QX(SystemNextEventIdInformation), /* it should be SI_XX */
2205 SI_QX(SystemEventIdsInformation), /* it should be SI_XX */ // SystemPerformanceTraceInformation
2206 SI_QX(SystemCrashDumpInformation),
2207 SI_QX(SystemExceptionInformation),
2208 SI_QX(SystemCrashDumpStateInformation),
2209 SI_QX(SystemKernelDebuggerInformation),
2210 SI_QX(SystemContextSwitchInformation),
2211 SI_QS(SystemRegistryQuotaInformation),
2212 SI_XS(SystemExtendServiceTableInformation), // correct: SystemLoadAndCallImage
2213 SI_XS(SystemPrioritySeperation),
2214 SI_QX(SystemPlugPlayBusInformation), /* it should be SI_XX */
2215 SI_QX(SystemDockInformation), /* it should be SI_XX */
2216 SI_QX(SystemPowerInformation), /* it should be SI_XX */ // SystemPowerInformationNative? SystemInvalidInfoClass2
2217 SI_QX(SystemProcessorSpeedInformation), /* it should be SI_XX */
2218 SI_QS(SystemCurrentTimeZoneInformation), /* it should be SI_QX */ // aka SystemTimeZoneInformation
2219 SI_QX(SystemLookasideInformation),
2220 SI_XS(SystemSetTimeSlipEvent),
2221 SI_XS(SystemCreateSession),
2222 SI_XS(SystemDeleteSession),
2223 SI_QX(SystemInvalidInfoClass4), /* it should be SI_XX */ // SystemSessionInformation?
2224 SI_QX(SystemRangeStartInformation),
2225 SI_QS(SystemVerifierInformation),
2226 SI_XS(SystemAddVerifier),
2227 SI_QX(SystemSessionProcessesInformation)
2228 };
2229
2230 C_ASSERT(SystemBasicInformation == 0);
2231 #define MIN_SYSTEM_INFO_CLASS (SystemBasicInformation)
2232 #define MAX_SYSTEM_INFO_CLASS (sizeof(CallQS) / sizeof(CallQS[0]))
2233
2234 /*
2235 * @implemented
2236 */
2237 NTSTATUS NTAPI
2238 NtQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
2239 OUT PVOID SystemInformation,
2240 IN ULONG Length,
2241 OUT PULONG UnsafeResultLength)
2242 {
2243 KPROCESSOR_MODE PreviousMode;
2244 ULONG ResultLength = 0;
2245 NTSTATUS FStatus = STATUS_NOT_IMPLEMENTED;
2246
2247 PAGED_CODE();
2248
2249 PreviousMode = ExGetPreviousMode();
2250
2251 _SEH2_TRY
2252 {
2253 if (PreviousMode != KernelMode)
2254 {
2255 /* SystemKernelDebuggerInformation needs only BOOLEAN alignment */
2256 ProbeForWrite(SystemInformation, Length, 1);
2257 if (UnsafeResultLength != NULL)
2258 ProbeForWriteUlong(UnsafeResultLength);
2259 }
2260
2261 if (UnsafeResultLength)
2262 *UnsafeResultLength = 0;
2263
2264 /*
2265 * Check if the request is valid.
2266 */
2267 if (SystemInformationClass >= MAX_SYSTEM_INFO_CLASS)
2268 {
2269 _SEH2_YIELD(return STATUS_INVALID_INFO_CLASS);
2270 }
2271
2272 if (NULL != CallQS [SystemInformationClass].Query)
2273 {
2274 /*
2275 * Hand the request to a subhandler.
2276 */
2277 FStatus = CallQS [SystemInformationClass].Query(SystemInformation,
2278 Length,
2279 &ResultLength);
2280
2281 /* Save the result length to the caller */
2282 if (UnsafeResultLength)
2283 *UnsafeResultLength = ResultLength;
2284 }
2285 }
2286 _SEH2_EXCEPT(ExSystemExceptionFilter())
2287 {
2288 FStatus = _SEH2_GetExceptionCode();
2289 }
2290 _SEH2_END;
2291
2292 return FStatus;
2293 }
2294
2295
2296 NTSTATUS
2297 NTAPI
2298 NtSetSystemInformation (IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
2299 IN PVOID SystemInformation,
2300 IN ULONG SystemInformationLength)
2301 {
2302 PAGED_CODE();
2303
2304 /*
2305 * If called from user mode, check
2306 * possible unsafe arguments.
2307 */
2308 #if 0
2309 if (KernelMode != KeGetPreviousMode())
2310 {
2311 // Check arguments
2312 //ProbeForWrite(
2313 // SystemInformation,
2314 // Length
2315 // );
2316 //ProbeForWrite(
2317 // ResultLength,
2318 // sizeof (ULONG)
2319 // );
2320 }
2321 #endif
2322 /*
2323 * Check the request is valid.
2324 */
2325 if ((SystemInformationClass >= MIN_SYSTEM_INFO_CLASS) &&
2326 (SystemInformationClass < MAX_SYSTEM_INFO_CLASS))
2327 {
2328 if (NULL != CallQS [SystemInformationClass].Set)
2329 {
2330 /*
2331 * Hand the request to a subhandler.
2332 */
2333 return CallQS [SystemInformationClass].Set(SystemInformation,
2334 SystemInformationLength);
2335 }
2336 }
2337
2338 return STATUS_INVALID_INFO_CLASS;
2339 }
2340
2341 NTSTATUS
2342 NTAPI
2343 NtFlushInstructionCache(
2344 _In_ HANDLE ProcessHandle,
2345 _In_opt_ PVOID BaseAddress,
2346 _In_ ULONG FlushSize)
2347 {
2348 KAPC_STATE ApcState;
2349 PKPROCESS Process;
2350 NTSTATUS Status;
2351 PAGED_CODE();
2352
2353 /* Is a base address given? */
2354 if (BaseAddress != NULL)
2355 {
2356 /* If the requested size is 0, there is nothing to do */
2357 if (FlushSize == 0)
2358 {
2359 return STATUS_SUCCESS;
2360 }
2361
2362 /* Is this a user mode call? */
2363 if (KeGetPreviousMode() != KernelMode)
2364 {
2365 /* Make sure the base address is in user space */
2366 if (BaseAddress > MmHighestUserAddress)
2367 {
2368 DPRINT1("Invalid BaseAddress 0x%p\n", BaseAddress);
2369 return STATUS_ACCESS_VIOLATION;
2370 }
2371 }
2372 }
2373
2374 /* Is another process requested? */
2375 if (ProcessHandle != NtCurrentProcess())
2376 {
2377 /* Reference the process */
2378 Status = ObReferenceObjectByHandle(ProcessHandle,
2379 PROCESS_VM_WRITE,
2380 PsProcessType,
2381 KeGetPreviousMode(),
2382 (PVOID*)&Process,
2383 NULL);
2384 if (!NT_SUCCESS(Status))
2385 {
2386 DPRINT1("Failed to reference the process %p\n", ProcessHandle);
2387 return Status;
2388 }
2389
2390 /* Attach to the process */
2391 KeStackAttachProcess(Process, &ApcState);
2392 }
2393
2394 /* FIXME: don't flush everything if a range is requested */
2395 #if defined(_M_IX86) || defined(_M_AMD64)
2396 __wbinvd();
2397 #elif defined(_M_PPC)
2398 __asm__ __volatile__("tlbsync");
2399 #elif defined(_M_MIPS)
2400 DPRINT1("NtFlushInstructionCache() is not implemented\n");
2401 DbgBreakPoint();
2402 #elif defined(_M_ARM)
2403 _MoveToCoprocessor(0, CP15_ICIALLU);
2404 #else
2405 #error Unknown architecture
2406 #endif
2407
2408 /* Check if we attached */
2409 if (ProcessHandle != NtCurrentProcess())
2410 {
2411 /* Detach from the process */
2412 KeUnstackDetachProcess(&ApcState);
2413 }
2414
2415 return STATUS_SUCCESS;
2416 }
2417
2418 ULONG
2419 NTAPI
2420 NtGetCurrentProcessorNumber(VOID)
2421 {
2422 /* Just return the CPU */
2423 return KeGetCurrentProcessorNumber();
2424 }
2425
2426 /*
2427 * @implemented
2428 */
2429 #undef ExGetPreviousMode
2430 KPROCESSOR_MODE
2431 NTAPI
2432 ExGetPreviousMode (VOID)
2433 {
2434 return KeGetPreviousMode();
2435 }