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