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