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