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