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