[NTOSKNRL]
[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 (sizeof(SYSTEM_FLAGS_INFORMATION) != Size)
1069 {
1070 *ReqSize = sizeof(SYSTEM_FLAGS_INFORMATION);
1071 return (STATUS_INFO_LENGTH_MISMATCH);
1072 }
1073 ((PSYSTEM_FLAGS_INFORMATION) Buffer)->Flags = NtGlobalFlag;
1074 return STATUS_SUCCESS;
1075 }
1076
1077 SSI_DEF(SystemFlagsInformation)
1078 {
1079 if (sizeof(SYSTEM_FLAGS_INFORMATION) != Size)
1080 {
1081 return STATUS_INFO_LENGTH_MISMATCH;
1082 }
1083
1084 if (!SeSinglePrivilegeCheck(SeDebugPrivilege, ExGetPreviousMode()))
1085 {
1086 return STATUS_ACCESS_DENIED;
1087 }
1088
1089 NtGlobalFlag = ((PSYSTEM_FLAGS_INFORMATION) Buffer)->Flags;
1090 return STATUS_SUCCESS;
1091 }
1092
1093 /* Class 10 - Call Time Information */
1094 QSI_DEF(SystemCallTimeInformation)
1095 {
1096 /* FIXME */
1097 DPRINT1("NtQuerySystemInformation - SystemCallTimeInformation not implemented\n");
1098 return STATUS_NOT_IMPLEMENTED;
1099 }
1100
1101 /* Class 11 - Module Information */
1102 QSI_DEF(SystemModuleInformation)
1103 {
1104 NTSTATUS Status;
1105
1106 /* Acquire system module list lock */
1107 KeEnterCriticalRegion();
1108 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource, TRUE);
1109
1110 /* Call the generic handler with the system module list */
1111 Status = ExpQueryModuleInformation(&PsLoadedModuleList,
1112 &MmLoadedUserImageList,
1113 (PRTL_PROCESS_MODULES)Buffer,
1114 Size,
1115 ReqSize);
1116
1117 /* Release list lock and return status */
1118 ExReleaseResourceLite(&PsLoadedModuleResource);
1119 KeLeaveCriticalRegion();
1120 return Status;
1121 }
1122
1123 /* Class 12 - Locks Information */
1124 QSI_DEF(SystemLocksInformation)
1125 {
1126 /* FIXME */
1127 DPRINT1("NtQuerySystemInformation - SystemLocksInformation not implemented\n");
1128 return STATUS_NOT_IMPLEMENTED;
1129 }
1130
1131 /* Class 13 - Stack Trace Information */
1132 QSI_DEF(SystemStackTraceInformation)
1133 {
1134 /* FIXME */
1135 DPRINT1("NtQuerySystemInformation - SystemStackTraceInformation not implemented\n");
1136 return STATUS_NOT_IMPLEMENTED;
1137 }
1138
1139 /* Class 14 - Paged Pool Information */
1140 QSI_DEF(SystemPagedPoolInformation)
1141 {
1142 /* FIXME */
1143 DPRINT1("NtQuerySystemInformation - SystemPagedPoolInformation not implemented\n");
1144 return STATUS_NOT_IMPLEMENTED;
1145 }
1146
1147 /* Class 15 - Non Paged Pool Information */
1148 QSI_DEF(SystemNonPagedPoolInformation)
1149 {
1150 /* FIXME */
1151 DPRINT1("NtQuerySystemInformation - SystemNonPagedPoolInformation not implemented\n");
1152 return STATUS_NOT_IMPLEMENTED;
1153 }
1154
1155
1156 /* Class 16 - Handle Information */
1157 QSI_DEF(SystemHandleInformation)
1158 {
1159 PEPROCESS pr, syspr;
1160 ULONG curSize, i = 0;
1161 ULONG hCount = 0;
1162
1163 PSYSTEM_HANDLE_INFORMATION Shi =
1164 (PSYSTEM_HANDLE_INFORMATION) Buffer;
1165
1166 DPRINT("NtQuerySystemInformation - SystemHandleInformation\n");
1167
1168 if (Size < sizeof(SYSTEM_HANDLE_INFORMATION))
1169 {
1170 *ReqSize = sizeof(SYSTEM_HANDLE_INFORMATION);
1171 return STATUS_INFO_LENGTH_MISMATCH;
1172 }
1173
1174 DPRINT("SystemHandleInformation 1\n");
1175
1176 /* First Calc Size from Count. */
1177 syspr = PsGetNextProcess(NULL);
1178 pr = syspr;
1179
1180 do
1181 {
1182 hCount = hCount + ObGetProcessHandleCount(pr);
1183 pr = PsGetNextProcess(pr);
1184
1185 if ((pr == syspr) || (pr == NULL)) break;
1186 }
1187 while ((pr != syspr) && (pr != NULL));
1188
1189 if(pr != NULL)
1190 {
1191 ObDereferenceObject(pr);
1192 }
1193
1194 DPRINT("SystemHandleInformation 2\n");
1195
1196 curSize = sizeof(SYSTEM_HANDLE_INFORMATION) +
1197 ((sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO) * hCount) -
1198 (sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO)));
1199
1200 Shi->NumberOfHandles = hCount;
1201
1202 if (curSize > Size)
1203 {
1204 *ReqSize = curSize;
1205 return (STATUS_INFO_LENGTH_MISMATCH);
1206 }
1207
1208 DPRINT("SystemHandleInformation 3\n");
1209
1210 /* Now get Handles from all processes. */
1211 syspr = PsGetNextProcess(NULL);
1212 pr = syspr;
1213
1214 do
1215 {
1216 int Count = 0, HandleCount;
1217
1218 HandleCount = ObGetProcessHandleCount(pr);
1219
1220 for (Count = 0; HandleCount > 0 ; HandleCount--)
1221 {
1222 Shi->Handles[i].UniqueProcessId = (USHORT)(ULONG_PTR)pr->UniqueProcessId;
1223 Count++;
1224 i++;
1225 }
1226
1227 pr = PsGetNextProcess(pr);
1228
1229 if ((pr == syspr) || (pr == NULL)) break;
1230 }
1231 while ((pr != syspr) && (pr != NULL));
1232
1233 if(pr != NULL) ObDereferenceObject(pr);
1234
1235 DPRINT("SystemHandleInformation 4\n");
1236 return STATUS_SUCCESS;
1237
1238 }
1239 /*
1240 SSI_DEF(SystemHandleInformation)
1241 {
1242
1243 return STATUS_SUCCESS;
1244 }
1245 */
1246
1247 /* Class 17 - Information */
1248 QSI_DEF(SystemObjectInformation)
1249 {
1250 /* FIXME */
1251 DPRINT1("NtQuerySystemInformation - SystemObjectInformation not implemented\n");
1252 return STATUS_NOT_IMPLEMENTED;
1253 }
1254
1255 /* Class 18 - Information */
1256 QSI_DEF(SystemPageFileInformation)
1257 {
1258 UNICODE_STRING FileName; /* FIXME */
1259 SYSTEM_PAGEFILE_INFORMATION *Spfi = (SYSTEM_PAGEFILE_INFORMATION *) Buffer;
1260
1261 if (Size < sizeof(SYSTEM_PAGEFILE_INFORMATION))
1262 {
1263 * ReqSize = sizeof(SYSTEM_PAGEFILE_INFORMATION);
1264 return STATUS_INFO_LENGTH_MISMATCH;
1265 }
1266
1267 RtlInitUnicodeString(&FileName, NULL); /* FIXME */
1268
1269 /* FIXME */
1270 Spfi->NextEntryOffset = 0;
1271
1272 Spfi->TotalSize = MiFreeSwapPages + MiUsedSwapPages;
1273 Spfi->TotalInUse = MiUsedSwapPages;
1274 Spfi->PeakUsage = MiUsedSwapPages; /* FIXME */
1275 Spfi->PageFileName = FileName;
1276 return STATUS_SUCCESS;
1277 }
1278
1279 /* Class 19 - Vdm Instemul Information */
1280 QSI_DEF(SystemVdmInstemulInformation)
1281 {
1282 /* FIXME */
1283 DPRINT1("NtQuerySystemInformation - SystemVdmInstemulInformation not implemented\n");
1284 return STATUS_NOT_IMPLEMENTED;
1285 }
1286
1287 /* Class 20 - Vdm Bop Information */
1288 QSI_DEF(SystemVdmBopInformation)
1289 {
1290 /* FIXME */
1291 DPRINT1("NtQuerySystemInformation - SystemVdmBopInformation not implemented\n");
1292 return STATUS_NOT_IMPLEMENTED;
1293 }
1294
1295 /* Class 21 - File Cache Information */
1296 QSI_DEF(SystemFileCacheInformation)
1297 {
1298 SYSTEM_FILECACHE_INFORMATION *Sci = (SYSTEM_FILECACHE_INFORMATION *) Buffer;
1299
1300 *ReqSize = sizeof(SYSTEM_FILECACHE_INFORMATION);
1301
1302 if (Size < *ReqSize)
1303 {
1304 return STATUS_INFO_LENGTH_MISMATCH;
1305 }
1306
1307 RtlZeroMemory(Sci, sizeof(SYSTEM_FILECACHE_INFORMATION));
1308
1309 /* Return the Byte size not the page size. */
1310 Sci->CurrentSize =
1311 MiMemoryConsumers[MC_CACHE].PagesUsed * PAGE_SIZE;
1312 Sci->PeakSize =
1313 MiMemoryConsumers[MC_CACHE].PagesUsed * PAGE_SIZE; /* FIXME */
1314 /* Taskmgr multiplies this one by page size right away */
1315 Sci->CurrentSizeIncludingTransitionInPages =
1316 MiMemoryConsumers[MC_CACHE].PagesUsed; /* FIXME: Should be */
1317 /* system working set and standby pages. */
1318 Sci->PageFaultCount = 0; /* FIXME */
1319 Sci->MinimumWorkingSet = 0; /* FIXME */
1320 Sci->MaximumWorkingSet = 0; /* FIXME */
1321
1322 return STATUS_SUCCESS;
1323 }
1324
1325 SSI_DEF(SystemFileCacheInformation)
1326 {
1327 if (Size < sizeof(SYSTEM_FILECACHE_INFORMATION))
1328 {
1329 return STATUS_INFO_LENGTH_MISMATCH;
1330 }
1331 /* FIXME */
1332 DPRINT1("NtSetSystemInformation - SystemFileCacheInformation not implemented\n");
1333 return STATUS_NOT_IMPLEMENTED;
1334 }
1335
1336 /* Class 22 - Pool Tag Information */
1337 QSI_DEF(SystemPoolTagInformation)
1338 {
1339 if (Size < sizeof(SYSTEM_POOLTAG_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
1340 return ExGetPoolTagInfo(Buffer, Size, ReqSize);
1341 }
1342
1343 /* Class 23 - Interrupt Information for all processors */
1344 QSI_DEF(SystemInterruptInformation)
1345 {
1346 PKPRCB Prcb;
1347 LONG i;
1348 ULONG ti;
1349 PSYSTEM_INTERRUPT_INFORMATION sii = (PSYSTEM_INTERRUPT_INFORMATION)Buffer;
1350
1351 if(Size < KeNumberProcessors * sizeof(SYSTEM_INTERRUPT_INFORMATION))
1352 {
1353 return STATUS_INFO_LENGTH_MISMATCH;
1354 }
1355
1356 ti = KeQueryTimeIncrement();
1357
1358 for (i = 0; i < KeNumberProcessors; i++)
1359 {
1360 Prcb = KiProcessorBlock[i];
1361 sii->ContextSwitches = KeGetContextSwitches(Prcb);
1362 sii->DpcCount = Prcb->DpcData[0].DpcCount;
1363 sii->DpcRate = Prcb->DpcRequestRate;
1364 sii->TimeIncrement = ti;
1365 sii->DpcBypassCount = 0;
1366 sii->ApcBypassCount = 0;
1367 sii++;
1368 }
1369
1370 return STATUS_SUCCESS;
1371 }
1372
1373 /* Class 24 - DPC Behaviour Information */
1374 QSI_DEF(SystemDpcBehaviourInformation)
1375 {
1376 /* FIXME */
1377 DPRINT1("NtQuerySystemInformation - SystemDpcBehaviourInformation not implemented\n");
1378 return STATUS_NOT_IMPLEMENTED;
1379 }
1380
1381 SSI_DEF(SystemDpcBehaviourInformation)
1382 {
1383 /* FIXME */
1384 DPRINT1("NtSetSystemInformation - SystemDpcBehaviourInformation not implemented\n");
1385 return STATUS_NOT_IMPLEMENTED;
1386 }
1387
1388 /* Class 25 - Full Memory Information */
1389 QSI_DEF(SystemFullMemoryInformation)
1390 {
1391 PULONG Spi = (PULONG) Buffer;
1392
1393 PEPROCESS TheIdleProcess;
1394
1395 *ReqSize = sizeof(ULONG);
1396
1397 if (sizeof(ULONG) != Size)
1398 {
1399 return STATUS_INFO_LENGTH_MISMATCH;
1400 }
1401
1402 DPRINT("SystemFullMemoryInformation\n");
1403
1404 TheIdleProcess = PsIdleProcess;
1405
1406 DPRINT("PID: %p, KernelTime: %u PFFree: %lu PFUsed: %lu\n",
1407 TheIdleProcess->UniqueProcessId,
1408 TheIdleProcess->Pcb.KernelTime,
1409 MiFreeSwapPages,
1410 MiUsedSwapPages);
1411
1412 *Spi = MiMemoryConsumers[MC_USER].PagesUsed;
1413
1414 return STATUS_SUCCESS;
1415 }
1416
1417 /* Class 26 - Load Image */
1418 SSI_DEF(SystemLoadGdiDriverInformation)
1419 {
1420 PSYSTEM_GDI_DRIVER_INFORMATION DriverInfo = (PVOID)Buffer;
1421 UNICODE_STRING ImageName;
1422 PVOID ImageBase;
1423 PVOID SectionPointer;
1424 ULONG_PTR EntryPoint;
1425 NTSTATUS Status;
1426 ULONG DirSize;
1427 PIMAGE_NT_HEADERS NtHeader;
1428
1429 /* Validate size */
1430 if (Size != sizeof(SYSTEM_GDI_DRIVER_INFORMATION))
1431 {
1432 /* Incorrect buffer length, fail */
1433 return STATUS_INFO_LENGTH_MISMATCH;
1434 }
1435
1436 /* Only kernel mode can call this function */
1437 if (ExGetPreviousMode() != KernelMode) return STATUS_PRIVILEGE_NOT_HELD;
1438
1439 /* Load the driver */
1440 ImageName = DriverInfo->DriverName;
1441 Status = MmLoadSystemImage(&ImageName,
1442 NULL,
1443 NULL,
1444 0,
1445 &SectionPointer,
1446 &ImageBase);
1447 if (!NT_SUCCESS(Status)) return Status;
1448
1449 /* Return the export pointer */
1450 DriverInfo->ExportSectionPointer =
1451 RtlImageDirectoryEntryToData(ImageBase,
1452 TRUE,
1453 IMAGE_DIRECTORY_ENTRY_EXPORT,
1454 &DirSize);
1455
1456 /* Get the entrypoint */
1457 NtHeader = RtlImageNtHeader(ImageBase);
1458 EntryPoint = NtHeader->OptionalHeader.AddressOfEntryPoint;
1459 EntryPoint += (ULONG_PTR)ImageBase;
1460
1461 /* Save other data */
1462 DriverInfo->ImageAddress = ImageBase;
1463 DriverInfo->SectionPointer = SectionPointer;
1464 DriverInfo->EntryPoint = (PVOID)EntryPoint;
1465 DriverInfo->ImageLength = NtHeader->OptionalHeader.SizeOfImage;
1466
1467 /* All is good */
1468 return STATUS_SUCCESS;
1469 }
1470
1471 /* Class 27 - Unload Image */
1472 SSI_DEF(SystemUnloadGdiDriverInformation)
1473 {
1474 PVOID *SectionPointer = Buffer;
1475
1476 /* Validate size */
1477 if (Size != sizeof(PVOID))
1478 {
1479 /* Incorrect length, fail */
1480 return STATUS_INFO_LENGTH_MISMATCH;
1481 }
1482
1483 /* Only kernel mode can call this function */
1484 if (ExGetPreviousMode() != KernelMode) return STATUS_PRIVILEGE_NOT_HELD;
1485
1486 /* Unload the image */
1487 MmUnloadSystemImage(*SectionPointer);
1488 return STATUS_SUCCESS;
1489 }
1490
1491 /* Class 28 - Time Adjustment Information */
1492 QSI_DEF(SystemTimeAdjustmentInformation)
1493 {
1494 PSYSTEM_QUERY_TIME_ADJUST_INFORMATION TimeInfo =
1495 (PSYSTEM_QUERY_TIME_ADJUST_INFORMATION)Buffer;
1496
1497 /* Check if enough storage was provided */
1498 if (sizeof(SYSTEM_QUERY_TIME_ADJUST_INFORMATION) > Size)
1499 {
1500 * ReqSize = sizeof(SYSTEM_QUERY_TIME_ADJUST_INFORMATION);
1501 return STATUS_INFO_LENGTH_MISMATCH;
1502 }
1503
1504 /* Give time values to our caller */
1505 TimeInfo->TimeIncrement = KeMaximumIncrement;
1506 TimeInfo->TimeAdjustment = KeTimeAdjustment;
1507 TimeInfo->Enable = !KiTimeAdjustmentEnabled;
1508
1509 return STATUS_SUCCESS;
1510 }
1511
1512 SSI_DEF(SystemTimeAdjustmentInformation)
1513 {
1514 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1515 PSYSTEM_SET_TIME_ADJUST_INFORMATION TimeInfo =
1516 (PSYSTEM_SET_TIME_ADJUST_INFORMATION)Buffer;
1517
1518 /* Check size of a buffer, it must match our expectations */
1519 if (sizeof(SYSTEM_SET_TIME_ADJUST_INFORMATION) != Size)
1520 return STATUS_INFO_LENGTH_MISMATCH;
1521
1522 /* Check who is calling */
1523 if (PreviousMode != KernelMode)
1524 {
1525 /* Check access rights */
1526 if (!SeSinglePrivilegeCheck(SeSystemtimePrivilege, PreviousMode))
1527 {
1528 return STATUS_PRIVILEGE_NOT_HELD;
1529 }
1530 }
1531
1532 /* FIXME: behaviour suggests the member be named 'Disable' */
1533 if (TimeInfo->Enable)
1534 {
1535 /* Disable time adjustment and set default value */
1536 KiTimeAdjustmentEnabled = FALSE;
1537 KeTimeAdjustment = KeMaximumIncrement;
1538 }
1539 else
1540 {
1541 /* Check if a valid time adjustment value is given */
1542 if (TimeInfo->TimeAdjustment == 0) return STATUS_INVALID_PARAMETER_2;
1543
1544 /* Enable time adjustment and set the adjustment value */
1545 KiTimeAdjustmentEnabled = TRUE;
1546 KeTimeAdjustment = TimeInfo->TimeAdjustment;
1547 }
1548
1549 return STATUS_SUCCESS;
1550 }
1551
1552 /* Class 29 - Summary Memory Information */
1553 QSI_DEF(SystemSummaryMemoryInformation)
1554 {
1555 /* FIXME */
1556 DPRINT1("NtQuerySystemInformation - SystemSummaryMemoryInformation not implemented\n");
1557 return STATUS_NOT_IMPLEMENTED;
1558 }
1559
1560 /* Class 30 - Next Event Id Information */
1561 QSI_DEF(SystemNextEventIdInformation)
1562 {
1563 /* FIXME */
1564 DPRINT1("NtQuerySystemInformation - SystemNextEventIdInformation not implemented\n");
1565 return STATUS_NOT_IMPLEMENTED;
1566 }
1567
1568 /* Class 31 */
1569 QSI_DEF(SystemPerformanceTraceInformation)
1570 {
1571 /* FIXME */
1572 DPRINT1("NtQuerySystemInformation - SystemPerformanceTraceInformation not implemented\n");
1573 return STATUS_NOT_IMPLEMENTED;
1574 }
1575
1576 /* Class 32 - Crash Dump Information */
1577 QSI_DEF(SystemCrashDumpInformation)
1578 {
1579 /* FIXME */
1580 DPRINT1("NtQuerySystemInformation - SystemCrashDumpInformation not implemented\n");
1581 return STATUS_NOT_IMPLEMENTED;
1582 }
1583
1584 /* Class 33 - Exception Information */
1585 QSI_DEF(SystemExceptionInformation)
1586 {
1587 PSYSTEM_EXCEPTION_INFORMATION ExceptionInformation =
1588 (PSYSTEM_EXCEPTION_INFORMATION)Buffer;
1589 PKPRCB Prcb;
1590 ULONG AlignmentFixupCount = 0, ExceptionDispatchCount = 0;
1591 ULONG FloatingEmulationCount = 0, ByteWordEmulationCount = 0;
1592 CHAR i;
1593
1594 /* Check size of a buffer, it must match our expectations */
1595 if (sizeof(SYSTEM_EXCEPTION_INFORMATION) != Size)
1596 return STATUS_INFO_LENGTH_MISMATCH;
1597
1598 /* Sum up exception count information from all processors */
1599 for (i = 0; i < KeNumberProcessors; i++)
1600 {
1601 Prcb = KiProcessorBlock[i];
1602 if (Prcb)
1603 {
1604 AlignmentFixupCount += Prcb->KeAlignmentFixupCount;
1605 ExceptionDispatchCount += Prcb->KeExceptionDispatchCount;
1606 #ifndef _M_ARM
1607 FloatingEmulationCount += Prcb->KeFloatingEmulationCount;
1608 #endif // _M_ARM
1609 }
1610 }
1611
1612 /* Save information in user's buffer */
1613 ExceptionInformation->AlignmentFixupCount = AlignmentFixupCount;
1614 ExceptionInformation->ExceptionDispatchCount = ExceptionDispatchCount;
1615 ExceptionInformation->FloatingEmulationCount = FloatingEmulationCount;
1616 ExceptionInformation->ByteWordEmulationCount = ByteWordEmulationCount;
1617
1618 return STATUS_SUCCESS;
1619 }
1620
1621 /* Class 34 - Crash Dump State Information */
1622 QSI_DEF(SystemCrashDumpStateInformation)
1623 {
1624 /* FIXME */
1625 DPRINT1("NtQuerySystemInformation - SystemCrashDumpStateInformation not implemented\n");
1626 return STATUS_NOT_IMPLEMENTED;
1627 }
1628
1629 /* Class 35 - Kernel Debugger Information */
1630 QSI_DEF(SystemKernelDebuggerInformation)
1631 {
1632 PSYSTEM_KERNEL_DEBUGGER_INFORMATION skdi = (PSYSTEM_KERNEL_DEBUGGER_INFORMATION) Buffer;
1633
1634 *ReqSize = sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION);
1635 if (Size < sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION))
1636 {
1637 return STATUS_INFO_LENGTH_MISMATCH;
1638 }
1639
1640 skdi->KernelDebuggerEnabled = KD_DEBUGGER_ENABLED;
1641 skdi->KernelDebuggerNotPresent = KD_DEBUGGER_NOT_PRESENT;
1642
1643 return STATUS_SUCCESS;
1644 }
1645
1646 /* Class 36 - Context Switch Information */
1647 QSI_DEF(SystemContextSwitchInformation)
1648 {
1649 PSYSTEM_CONTEXT_SWITCH_INFORMATION ContextSwitchInformation =
1650 (PSYSTEM_CONTEXT_SWITCH_INFORMATION)Buffer;
1651 ULONG ContextSwitches;
1652 PKPRCB Prcb;
1653 CHAR i;
1654
1655 /* Check size of a buffer, it must match our expectations */
1656 if (sizeof(SYSTEM_CONTEXT_SWITCH_INFORMATION) != Size)
1657 return STATUS_INFO_LENGTH_MISMATCH;
1658
1659 /* Calculate total value of context switches across all processors */
1660 ContextSwitches = 0;
1661 for (i = 0; i < KeNumberProcessors; i ++)
1662 {
1663 Prcb = KiProcessorBlock[i];
1664 if (Prcb)
1665 {
1666 ContextSwitches += KeGetContextSwitches(Prcb);
1667 }
1668 }
1669
1670 ContextSwitchInformation->ContextSwitches = ContextSwitches;
1671
1672 /* FIXME */
1673 ContextSwitchInformation->FindAny = 0;
1674 ContextSwitchInformation->FindLast = 0;
1675 ContextSwitchInformation->FindIdeal = 0;
1676 ContextSwitchInformation->IdleAny = 0;
1677 ContextSwitchInformation->IdleCurrent = 0;
1678 ContextSwitchInformation->IdleLast = 0;
1679 ContextSwitchInformation->IdleIdeal = 0;
1680 ContextSwitchInformation->PreemptAny = 0;
1681 ContextSwitchInformation->PreemptCurrent = 0;
1682 ContextSwitchInformation->PreemptLast = 0;
1683 ContextSwitchInformation->SwitchToIdle = 0;
1684
1685 return STATUS_SUCCESS;
1686 }
1687
1688 /* Class 37 - Registry Quota Information */
1689 QSI_DEF(SystemRegistryQuotaInformation)
1690 {
1691 PSYSTEM_REGISTRY_QUOTA_INFORMATION srqi = (PSYSTEM_REGISTRY_QUOTA_INFORMATION) Buffer;
1692
1693 *ReqSize = sizeof(SYSTEM_REGISTRY_QUOTA_INFORMATION);
1694 if (Size < sizeof(SYSTEM_REGISTRY_QUOTA_INFORMATION))
1695 {
1696 return STATUS_INFO_LENGTH_MISMATCH;
1697 }
1698
1699 DPRINT1("Faking max registry size of 32 MB\n");
1700 srqi->RegistryQuotaAllowed = 0x2000000;
1701 srqi->RegistryQuotaUsed = 0x200000;
1702 srqi->PagedPoolSize = 0x200000;
1703
1704 return STATUS_SUCCESS;
1705 }
1706
1707 SSI_DEF(SystemRegistryQuotaInformation)
1708 {
1709 /* FIXME */
1710 DPRINT1("NtSetSystemInformation - SystemRegistryQuotaInformation not implemented\n");
1711 return STATUS_NOT_IMPLEMENTED;
1712 }
1713
1714 /* Class 38 - Load And Call Image */
1715 SSI_DEF(SystemExtendServiceTableInformation)
1716 {
1717 UNICODE_STRING ImageName;
1718 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1719 PLDR_DATA_TABLE_ENTRY ModuleObject;
1720 NTSTATUS Status;
1721 PIMAGE_NT_HEADERS NtHeader;
1722 DRIVER_OBJECT Win32k;
1723 PDRIVER_INITIALIZE DriverInit;
1724 PVOID ImageBase;
1725 ULONG_PTR EntryPoint;
1726
1727 /* Validate the size */
1728 if (Size != sizeof(UNICODE_STRING)) return STATUS_INFO_LENGTH_MISMATCH;
1729
1730 /* Check who is calling */
1731 if (PreviousMode != KernelMode)
1732 {
1733 static const UNICODE_STRING Win32kName =
1734 RTL_CONSTANT_STRING(L"\\SystemRoot\\System32\\win32k.sys");
1735
1736 /* Make sure we can load drivers */
1737 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, UserMode))
1738 {
1739 /* FIXME: We can't, fail */
1740 return STATUS_PRIVILEGE_NOT_HELD;
1741 }
1742
1743 _SEH2_TRY
1744 {
1745 /* Probe and copy the unicode string */
1746 ProbeForRead(Buffer, sizeof(ImageName), 1);
1747 ImageName = *(PUNICODE_STRING)Buffer;
1748
1749 /* Probe the string buffer */
1750 ProbeForRead(ImageName.Buffer, ImageName.Length, sizeof(WCHAR));
1751
1752 /* Check if we have the correct name (nothing else is allowed!) */
1753 if (!RtlEqualUnicodeString(&ImageName, &Win32kName, FALSE))
1754 {
1755 _SEH2_YIELD(return STATUS_PRIVILEGE_NOT_HELD);
1756 }
1757 }
1758 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1759 {
1760 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1761 }
1762 _SEH2_END;
1763
1764 /* Recursively call the function, so that we are from kernel mode */
1765 return ZwSetSystemInformation(SystemExtendServiceTableInformation,
1766 (PVOID)&Win32kName,
1767 sizeof(Win32kName));
1768 }
1769
1770 /* Load the image */
1771 Status = MmLoadSystemImage((PUNICODE_STRING)Buffer,
1772 NULL,
1773 NULL,
1774 0,
1775 (PVOID)&ModuleObject,
1776 &ImageBase);
1777
1778 if (!NT_SUCCESS(Status)) return Status;
1779
1780 /* Get the headers */
1781 NtHeader = RtlImageNtHeader(ImageBase);
1782 if (!NtHeader)
1783 {
1784 /* Fail */
1785 MmUnloadSystemImage(ModuleObject);
1786 return STATUS_INVALID_IMAGE_FORMAT;
1787 }
1788
1789 /* Get the entrypoint */
1790 EntryPoint = NtHeader->OptionalHeader.AddressOfEntryPoint;
1791 EntryPoint += (ULONG_PTR)ImageBase;
1792 DriverInit = (PDRIVER_INITIALIZE)EntryPoint;
1793
1794 /* Create a dummy device */
1795 RtlZeroMemory(&Win32k, sizeof(Win32k));
1796 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
1797 Win32k.DriverStart = ImageBase;
1798
1799 /* Call it */
1800 Status = (DriverInit)(&Win32k, NULL);
1801 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
1802
1803 /* Unload if we failed */
1804 if (!NT_SUCCESS(Status)) MmUnloadSystemImage(ModuleObject);
1805 return Status;
1806 }
1807
1808 /* Class 39 - Priority Separation */
1809 SSI_DEF(SystemPrioritySeperation)
1810 {
1811 /* Check if the size is correct */
1812 if (Size != sizeof(ULONG))
1813 {
1814 return STATUS_INFO_LENGTH_MISMATCH;
1815 }
1816
1817 /* We need the TCB privilege */
1818 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, ExGetPreviousMode()))
1819 {
1820 return STATUS_PRIVILEGE_NOT_HELD;
1821 }
1822
1823 /* Modify the quantum table */
1824 PsChangeQuantumTable(TRUE, *(PULONG)Buffer);
1825
1826 return STATUS_SUCCESS;
1827 }
1828
1829 /* Class 40 */
1830 QSI_DEF(SystemVerifierAddDriverInformation)
1831 {
1832 /* FIXME */
1833 DPRINT1("NtQuerySystemInformation - SystemVerifierAddDriverInformation not implemented\n");
1834 return STATUS_NOT_IMPLEMENTED;
1835 }
1836
1837 /* Class 41 */
1838 QSI_DEF(SystemVerifierRemoveDriverInformation)
1839 {
1840 /* FIXME */
1841 DPRINT1("NtQuerySystemInformation - SystemVerifierRemoveDriverInformation not implemented\n");
1842 return STATUS_NOT_IMPLEMENTED;
1843 }
1844
1845 /* Class 42 - Power Information */
1846 QSI_DEF(SystemProcessorIdleInformation)
1847 {
1848 *ReqSize = sizeof(PROCESSOR_POWER_INFORMATION) * KeNumberProcessors;
1849
1850 if (sizeof(PROCESSOR_POWER_INFORMATION) * KeNumberProcessors > Size)
1851 {
1852 return STATUS_INFO_LENGTH_MISMATCH;
1853 }
1854
1855 /* FIXME */
1856 DPRINT1("NtQuerySystemInformation - SystemPowerInformation not implemented\n");
1857 return STATUS_NOT_IMPLEMENTED;
1858 }
1859
1860 /* Class 43 */
1861 QSI_DEF(SystemLegacyDriverInformation)
1862 {
1863 /* FIXME */
1864 DPRINT1("NtQuerySystemInformation - SystemLegacyDriverInformation not implemented\n");
1865 return STATUS_NOT_IMPLEMENTED;
1866 }
1867
1868 /* Class 44 - Current Time Zone Information */
1869 QSI_DEF(SystemCurrentTimeZoneInformation)
1870 {
1871 *ReqSize = sizeof(TIME_ZONE_INFORMATION);
1872
1873 if (sizeof(TIME_ZONE_INFORMATION) != Size)
1874 {
1875 return STATUS_INFO_LENGTH_MISMATCH;
1876 }
1877
1878 /* Copy the time zone information struct */
1879 memcpy(Buffer,
1880 &ExpTimeZoneInfo,
1881 sizeof(TIME_ZONE_INFORMATION));
1882
1883 return STATUS_SUCCESS;
1884 }
1885
1886
1887 SSI_DEF(SystemCurrentTimeZoneInformation)
1888 {
1889 /* Check user buffer's size */
1890 if (Size < sizeof(TIME_ZONE_INFORMATION))
1891 {
1892 return STATUS_INFO_LENGTH_MISMATCH;
1893 }
1894
1895 return ExpSetTimeZoneInformation((PTIME_ZONE_INFORMATION)Buffer);
1896 }
1897
1898 static
1899 VOID
1900 ExpCopyLookasideInformation(
1901 PSYSTEM_LOOKASIDE_INFORMATION *InfoPointer,
1902 PULONG RemainingPointer,
1903 PLIST_ENTRY ListHead,
1904 BOOLEAN ListUsesMisses)
1905
1906 {
1907 PSYSTEM_LOOKASIDE_INFORMATION Info;
1908 PGENERAL_LOOKASIDE LookasideList;
1909 PLIST_ENTRY ListEntry;
1910 ULONG Remaining;
1911
1912 /* Get info pointer and remaining count of free array element */
1913 Info = *InfoPointer;
1914 Remaining = *RemainingPointer;
1915
1916 /* Loop as long as we have lookaside lists and free array elements */
1917 for (ListEntry = ListHead->Flink;
1918 (ListEntry != ListHead) && (Remaining > 0);
1919 ListEntry = ListEntry->Flink, Remaining--)
1920 {
1921 LookasideList = CONTAINING_RECORD(ListEntry, GENERAL_LOOKASIDE, ListEntry);
1922
1923 /* Fill the next array element */
1924 Info->CurrentDepth = LookasideList->Depth;
1925 Info->MaximumDepth = LookasideList->MaximumDepth;
1926 Info->TotalAllocates = LookasideList->TotalAllocates;
1927 Info->TotalFrees = LookasideList->TotalFrees;
1928 Info->Type = LookasideList->Type;
1929 Info->Tag = LookasideList->Tag;
1930 Info->Size = LookasideList->Size;
1931
1932 /* Check how the lists track misses/hits */
1933 if (ListUsesMisses)
1934 {
1935 /* Copy misses */
1936 Info->AllocateMisses = LookasideList->AllocateMisses;
1937 Info->FreeMisses = LookasideList->FreeMisses;
1938 }
1939 else
1940 {
1941 /* Calculate misses */
1942 Info->AllocateMisses = LookasideList->TotalAllocates
1943 - LookasideList->AllocateHits;
1944 Info->FreeMisses = LookasideList->TotalFrees
1945 - LookasideList->FreeHits;
1946 }
1947 }
1948
1949 /* Return the updated pointer and remaining count */
1950 *InfoPointer = Info;
1951 *RemainingPointer = Remaining;
1952 }
1953
1954 /* Class 45 - Lookaside Information */
1955 QSI_DEF(SystemLookasideInformation)
1956 {
1957 KPROCESSOR_MODE PreviousMode;
1958 PSYSTEM_LOOKASIDE_INFORMATION Info;
1959 PMDL Mdl;
1960 ULONG MaxCount, Remaining;
1961 KIRQL OldIrql;
1962 NTSTATUS Status;
1963
1964 /* First we need to lock down the memory, since we are going to access it
1965 at high IRQL */
1966 PreviousMode = ExGetPreviousMode();
1967 Status = ExLockUserBuffer(Buffer,
1968 Size,
1969 PreviousMode,
1970 IoWriteAccess,
1971 (PVOID*)&Info,
1972 &Mdl);
1973 if (!NT_SUCCESS(Status))
1974 {
1975 DPRINT1("Failed to lock the user buffer: 0x%lx\n", Status);
1976 return Status;
1977 }
1978
1979 /* Calculate how many items we can store */
1980 Remaining = MaxCount = Size / sizeof(SYSTEM_LOOKASIDE_INFORMATION);
1981 if (Remaining == 0)
1982 {
1983 goto Leave;
1984 }
1985
1986 /* Copy info from pool lookaside lists */
1987 ExpCopyLookasideInformation(&Info,
1988 &Remaining,
1989 &ExPoolLookasideListHead,
1990 FALSE);
1991 if (Remaining == 0)
1992 {
1993 goto Leave;
1994 }
1995
1996 /* Copy info from system lookaside lists */
1997 ExpCopyLookasideInformation(&Info,
1998 &Remaining,
1999 &ExSystemLookasideListHead,
2000 TRUE);
2001 if (Remaining == 0)
2002 {
2003 goto Leave;
2004 }
2005
2006 /* Acquire spinlock for ExpNonPagedLookasideListHead */
2007 KeAcquireSpinLock(&ExpNonPagedLookasideListLock, &OldIrql);
2008
2009 /* Copy info from non-paged lookaside lists */
2010 ExpCopyLookasideInformation(&Info,
2011 &Remaining,
2012 &ExpNonPagedLookasideListHead,
2013 TRUE);
2014
2015 /* Release spinlock for ExpNonPagedLookasideListHead */
2016 KeReleaseSpinLock(&ExpNonPagedLookasideListLock, OldIrql);
2017
2018 if (Remaining == 0)
2019 {
2020 goto Leave;
2021 }
2022
2023 /* Acquire spinlock for ExpPagedLookasideListHead */
2024 KeAcquireSpinLock(&ExpPagedLookasideListLock, &OldIrql);
2025
2026 /* Copy info from paged lookaside lists */
2027 ExpCopyLookasideInformation(&Info,
2028 &Remaining,
2029 &ExpPagedLookasideListHead,
2030 TRUE);
2031
2032 /* Release spinlock for ExpPagedLookasideListHead */
2033 KeReleaseSpinLock(&ExpPagedLookasideListLock, OldIrql);
2034
2035 Leave:
2036
2037 /* Release the locked user buffer */
2038 ExUnlockUserBuffer(Mdl);
2039
2040 /* Return the size of the actually written data */
2041 *ReqSize = (MaxCount - Remaining) * sizeof(SYSTEM_LOOKASIDE_INFORMATION);
2042 return STATUS_SUCCESS;
2043 }
2044
2045
2046 /* Class 46 - Set time slip event */
2047 SSI_DEF(SystemTimeSlipNotification)
2048 {
2049 /* FIXME */
2050 DPRINT1("NtSetSystemInformation - SystemTimeSlipNotification not implemented\n");
2051 return STATUS_NOT_IMPLEMENTED;
2052 }
2053
2054 NTSTATUS
2055 NTAPI
2056 MmSessionCreate(OUT PULONG SessionId);
2057
2058 NTSTATUS
2059 NTAPI
2060 MmSessionDelete(IN ULONG SessionId);
2061
2062 /* Class 47 - Create a new session (TSE) */
2063 SSI_DEF(SystemSessionCreate)
2064 {
2065 ULONG SessionId;
2066 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2067 NTSTATUS Status;
2068
2069 if (Size != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2070
2071 if (PreviousMode != KernelMode)
2072 {
2073 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2074 {
2075 return STATUS_PRIVILEGE_NOT_HELD;
2076 }
2077
2078 ProbeForWriteUlong(Buffer);
2079 }
2080
2081 Status = MmSessionCreate(&SessionId);
2082 if (NT_SUCCESS(Status)) *(PULONG)Buffer = SessionId;
2083
2084 return Status;
2085 }
2086
2087
2088 /* Class 48 - Delete an existing session (TSE) */
2089 SSI_DEF(SystemSessionDetach)
2090 {
2091 ULONG SessionId;
2092 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2093
2094 if (Size != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2095
2096 if (PreviousMode != KernelMode)
2097 {
2098 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2099 {
2100 return STATUS_PRIVILEGE_NOT_HELD;
2101 }
2102 }
2103
2104 SessionId = *(PULONG)Buffer;
2105
2106 return MmSessionDelete(SessionId);
2107 }
2108
2109
2110 /* Class 49 - UNKNOWN */
2111 QSI_DEF(SystemSessionInformation)
2112 {
2113 /* FIXME */
2114 DPRINT1("NtQuerySystemInformation - SystemSessionInformation not implemented\n");
2115 return STATUS_NOT_IMPLEMENTED;
2116 }
2117
2118
2119 /* Class 50 - System range start address */
2120 QSI_DEF(SystemRangeStartInformation)
2121 {
2122 /* Check user buffer's size */
2123 if (Size != sizeof(ULONG_PTR)) return STATUS_INFO_LENGTH_MISMATCH;
2124
2125 *(PULONG_PTR)Buffer = (ULONG_PTR)MmSystemRangeStart;
2126
2127 if (ReqSize) *ReqSize = sizeof(ULONG_PTR);
2128
2129 return STATUS_SUCCESS;
2130 }
2131
2132 /* Class 51 - Driver verifier information */
2133 QSI_DEF(SystemVerifierInformation)
2134 {
2135 /* FIXME */
2136 DPRINT1("NtQuerySystemInformation - SystemVerifierInformation not implemented\n");
2137 return STATUS_NOT_IMPLEMENTED;
2138 }
2139
2140
2141 SSI_DEF(SystemVerifierInformation)
2142 {
2143 /* FIXME */
2144 DPRINT1("NtSetSystemInformation - SystemVerifierInformation not implemented\n");
2145 return STATUS_NOT_IMPLEMENTED;
2146 }
2147
2148
2149 /* Class 52 */
2150 SSI_DEF(SystemVerifierThunkExtend)
2151 {
2152 /* FIXME */
2153 DPRINT1("NtSetSystemInformation - SystemVerifierThunkExtend not implemented\n");
2154 return STATUS_NOT_IMPLEMENTED;
2155 }
2156
2157
2158 /* Class 53 - A session's processes */
2159 QSI_DEF(SystemSessionProcessesInformation)
2160 {
2161 /* FIXME */
2162 DPRINT1("NtQuerySystemInformation - SystemSessionProcessInformation not implemented\n");
2163 return STATUS_NOT_IMPLEMENTED;
2164 }
2165
2166
2167 /* Class 54 - Load & map in system space */
2168 SSI_DEF(SystemLoadGdiDriverInSystemSpaceInformation)
2169 {
2170 /* FIXME */
2171 DPRINT1("NtSetSystemInformation - SystemLoadGdiDriverInSystemSpaceInformation not implemented\n");
2172 return STATUS_NOT_IMPLEMENTED;
2173 }
2174
2175
2176 /* Class 55 - NUMA processor information */
2177 QSI_DEF(SystemNumaProcessorMap)
2178 {
2179 ULONG MaxEntries, Node;
2180 PSYSTEM_NUMA_INFORMATION NumaInformation = (PSYSTEM_NUMA_INFORMATION)Buffer;
2181
2182 /* Validate input size */
2183 if (Size < sizeof(ULONG))
2184 {
2185 return STATUS_INFO_LENGTH_MISMATCH;
2186 }
2187
2188 /* Return highest node */
2189 NumaInformation->HighestNodeNumber = KeNumberNodes - 1;
2190
2191 /* Compute how much entries we will be able to put in output structure */
2192 MaxEntries = (Size - FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, ActiveProcessorsAffinityMask)) / sizeof(ULONGLONG);
2193 /* Make sure we don't overflow KeNodeBlock */
2194 if (MaxEntries > KeNumberNodes)
2195 {
2196 MaxEntries = KeNumberNodes;
2197 }
2198
2199 /* If we have entries to write, and room for it */
2200 if (Size >= FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, ActiveProcessorsAffinityMask) &&
2201 MaxEntries != 0)
2202 {
2203 /* Already set size we return */
2204 *ReqSize = FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, ActiveProcessorsAffinityMask) +
2205 MaxEntries * sizeof(ULONGLONG);
2206
2207 /* For each node, return processor mask */
2208 for (Node = 0; Node < MaxEntries; ++Node)
2209 {
2210 NumaInformation->ActiveProcessorsAffinityMask[Node] = KeNodeBlock[Node]->ProcessorMask;
2211 }
2212 }
2213 else
2214 {
2215 /* We only returned highest node number */
2216 *ReqSize = sizeof(ULONG);
2217 }
2218
2219 return STATUS_SUCCESS;
2220 }
2221
2222
2223 /* Class 56 - Prefetcher information */
2224 QSI_DEF(SystemPrefetcherInformation)
2225 {
2226 /* FIXME */
2227 DPRINT1("NtQuerySystemInformation - SystemPrefetcherInformation not implemented\n");
2228 return STATUS_NOT_IMPLEMENTED;
2229 }
2230
2231
2232 /* Class 57 - Extended process information */
2233 QSI_DEF(SystemExtendedProcessInformation)
2234 {
2235 /* FIXME */
2236 DPRINT1("NtQuerySystemInformation - SystemExtendedProcessInformation not implemented\n");
2237 return STATUS_NOT_IMPLEMENTED;
2238 }
2239
2240
2241 /* Class 58 - Recommended shared ata alignment */
2242 QSI_DEF(SystemRecommendedSharedDataAlignment)
2243 {
2244 /* FIXME */
2245 DPRINT1("NtQuerySystemInformation - SystemRecommendedSharedDataAlignment not implemented\n");
2246 return STATUS_NOT_IMPLEMENTED;
2247 }
2248
2249
2250 /* Class 60 - NUMA memory information */
2251 QSI_DEF(SystemNumaAvailableMemory)
2252 {
2253 ULONG MaxEntries, Node;
2254 PSYSTEM_NUMA_INFORMATION NumaInformation = (PSYSTEM_NUMA_INFORMATION)Buffer;
2255
2256 /* Validate input size */
2257 if (Size < sizeof(ULONG))
2258 {
2259 return STATUS_INFO_LENGTH_MISMATCH;
2260 }
2261
2262 /* Return highest node */
2263 NumaInformation->HighestNodeNumber = KeNumberNodes - 1;
2264
2265 /* Compute how much entries we will be able to put in output structure */
2266 MaxEntries = (Size - FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, AvailableMemory)) / sizeof(ULONGLONG);
2267 /* Make sure we don't overflow KeNodeBlock */
2268 if (MaxEntries > KeNumberNodes)
2269 {
2270 MaxEntries = KeNumberNodes;
2271 }
2272
2273 /* If we have entries to write, and room for it */
2274 if (Size >= FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, AvailableMemory) &&
2275 MaxEntries != 0)
2276 {
2277 /* Already set size we return */
2278 *ReqSize = FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, AvailableMemory) +
2279 MaxEntries * sizeof(ULONGLONG);
2280
2281 /* If we have a single entry (us), directly return MM information */
2282 if (MaxEntries == 1)
2283 {
2284 NumaInformation->AvailableMemory[0] = MmAvailablePages << PAGE_SHIFT;
2285 }
2286 else
2287 {
2288 /* Otherwise, for each node, return available bytes */
2289 for (Node = 0; Node < MaxEntries; ++Node)
2290 {
2291 NumaInformation->AvailableMemory[Node] = (KeNodeBlock[Node]->FreeCount[0] + KeNodeBlock[Node]->FreeCount[1]) << PAGE_SHIFT;
2292 }
2293 }
2294 }
2295 else
2296 {
2297 /* We only returned highest node number */
2298 *ReqSize = sizeof(ULONG);
2299 }
2300
2301 return STATUS_SUCCESS;
2302 }
2303
2304
2305 /* Query/Set Calls Table */
2306 typedef
2307 struct _QSSI_CALLS
2308 {
2309 NTSTATUS (* Query) (PVOID,ULONG,PULONG);
2310 NTSTATUS (* Set) (PVOID,ULONG);
2311
2312 } QSSI_CALLS;
2313
2314 // QS Query & Set
2315 // QX Query
2316 // XS Set
2317 // XX unknown behaviour
2318 //
2319 #define SI_QS(n) {QSI_USE(n),SSI_USE(n)}
2320 #define SI_QX(n) {QSI_USE(n),NULL}
2321 #define SI_XS(n) {NULL,SSI_USE(n)}
2322 #define SI_XX(n) {NULL,NULL}
2323
2324 static
2325 QSSI_CALLS
2326 CallQS [] =
2327 {
2328 SI_QX(SystemBasicInformation),
2329 SI_QX(SystemProcessorInformation),
2330 SI_QX(SystemPerformanceInformation),
2331 SI_QX(SystemTimeOfDayInformation),
2332 SI_QX(SystemPathInformation), /* should be SI_XX */
2333 SI_QX(SystemProcessInformation),
2334 SI_QX(SystemCallCountInformation),
2335 SI_QX(SystemDeviceInformation),
2336 SI_QX(SystemProcessorPerformanceInformation),
2337 SI_QS(SystemFlagsInformation),
2338 SI_QX(SystemCallTimeInformation), /* should be SI_XX */
2339 SI_QX(SystemModuleInformation),
2340 SI_QX(SystemLocksInformation),
2341 SI_QX(SystemStackTraceInformation), /* should be SI_XX */
2342 SI_QX(SystemPagedPoolInformation), /* should be SI_XX */
2343 SI_QX(SystemNonPagedPoolInformation), /* should be SI_XX */
2344 SI_QX(SystemHandleInformation),
2345 SI_QX(SystemObjectInformation),
2346 SI_QX(SystemPageFileInformation),
2347 SI_QX(SystemVdmInstemulInformation),
2348 SI_QX(SystemVdmBopInformation), /* it should be SI_XX */
2349 SI_QS(SystemFileCacheInformation),
2350 SI_QX(SystemPoolTagInformation),
2351 SI_QX(SystemInterruptInformation),
2352 SI_QS(SystemDpcBehaviourInformation),
2353 SI_QX(SystemFullMemoryInformation), /* it should be SI_XX */
2354 SI_XS(SystemLoadGdiDriverInformation),
2355 SI_XS(SystemUnloadGdiDriverInformation),
2356 SI_QS(SystemTimeAdjustmentInformation),
2357 SI_QX(SystemSummaryMemoryInformation), /* it should be SI_XX */
2358 SI_QX(SystemNextEventIdInformation), /* it should be SI_XX */
2359 SI_QX(SystemPerformanceTraceInformation), /* it should be SI_XX */
2360 SI_QX(SystemCrashDumpInformation),
2361 SI_QX(SystemExceptionInformation),
2362 SI_QX(SystemCrashDumpStateInformation),
2363 SI_QX(SystemKernelDebuggerInformation),
2364 SI_QX(SystemContextSwitchInformation),
2365 SI_QS(SystemRegistryQuotaInformation),
2366 SI_XS(SystemExtendServiceTableInformation),
2367 SI_XS(SystemPrioritySeperation),
2368 SI_QX(SystemVerifierAddDriverInformation), /* it should be SI_XX */
2369 SI_QX(SystemVerifierRemoveDriverInformation), /* it should be SI_XX */
2370 SI_QX(SystemProcessorIdleInformation), /* it should be SI_XX */
2371 SI_QX(SystemLegacyDriverInformation), /* it should be SI_XX */
2372 SI_QS(SystemCurrentTimeZoneInformation), /* it should be SI_QX */
2373 SI_QX(SystemLookasideInformation),
2374 SI_XS(SystemTimeSlipNotification),
2375 SI_XS(SystemSessionCreate),
2376 SI_XS(SystemSessionDetach),
2377 SI_QX(SystemSessionInformation), /* it should be SI_XX */
2378 SI_QX(SystemRangeStartInformation),
2379 SI_QS(SystemVerifierInformation),
2380 SI_XS(SystemVerifierThunkExtend),
2381 SI_QX(SystemSessionProcessesInformation),
2382 SI_XS(SystemLoadGdiDriverInSystemSpaceInformation),
2383 SI_QX(SystemNumaProcessorMap),
2384 SI_QX(SystemPrefetcherInformation),
2385 SI_QX(SystemExtendedProcessInformation),
2386 SI_QX(SystemRecommendedSharedDataAlignment),
2387 SI_XX(SystemComPlusPackage),
2388 SI_QX(SystemNumaAvailableMemory)
2389 };
2390
2391 C_ASSERT(SystemBasicInformation == 0);
2392 #define MIN_SYSTEM_INFO_CLASS (SystemBasicInformation)
2393 #define MAX_SYSTEM_INFO_CLASS (sizeof(CallQS) / sizeof(CallQS[0]))
2394
2395 /*
2396 * @implemented
2397 */
2398 NTSTATUS NTAPI
2399 NtQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
2400 OUT PVOID SystemInformation,
2401 IN ULONG Length,
2402 OUT PULONG UnsafeResultLength)
2403 {
2404 KPROCESSOR_MODE PreviousMode;
2405 ULONG ResultLength = 0;
2406 NTSTATUS FStatus = STATUS_NOT_IMPLEMENTED;
2407
2408 PAGED_CODE();
2409
2410 PreviousMode = ExGetPreviousMode();
2411
2412 _SEH2_TRY
2413 {
2414 if (PreviousMode != KernelMode)
2415 {
2416 /* SystemKernelDebuggerInformation needs only BOOLEAN alignment */
2417 ProbeForWrite(SystemInformation, Length, 1);
2418 if (UnsafeResultLength != NULL)
2419 ProbeForWriteUlong(UnsafeResultLength);
2420 }
2421
2422 if (UnsafeResultLength)
2423 *UnsafeResultLength = 0;
2424
2425 /*
2426 * Check if the request is valid.
2427 */
2428 if (SystemInformationClass >= MAX_SYSTEM_INFO_CLASS)
2429 {
2430 _SEH2_YIELD(return STATUS_INVALID_INFO_CLASS);
2431 }
2432
2433 if (NULL != CallQS [SystemInformationClass].Query)
2434 {
2435 /*
2436 * Hand the request to a subhandler.
2437 */
2438 FStatus = CallQS [SystemInformationClass].Query(SystemInformation,
2439 Length,
2440 &ResultLength);
2441
2442 /* Save the result length to the caller */
2443 if (UnsafeResultLength)
2444 *UnsafeResultLength = ResultLength;
2445 }
2446 }
2447 _SEH2_EXCEPT(ExSystemExceptionFilter())
2448 {
2449 FStatus = _SEH2_GetExceptionCode();
2450 }
2451 _SEH2_END;
2452
2453 return FStatus;
2454 }
2455
2456
2457 NTSTATUS
2458 NTAPI
2459 NtSetSystemInformation (IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
2460 IN PVOID SystemInformation,
2461 IN ULONG SystemInformationLength)
2462 {
2463 NTSTATUS Status = STATUS_INVALID_INFO_CLASS;
2464 KPROCESSOR_MODE PreviousMode;
2465
2466 PAGED_CODE();
2467
2468 PreviousMode = ExGetPreviousMode();
2469
2470 _SEH2_TRY
2471 {
2472 /*
2473 * If called from user mode, check
2474 * possible unsafe arguments.
2475 */
2476 if (PreviousMode != KernelMode)
2477 {
2478 ProbeForRead(SystemInformation, SystemInformationLength, sizeof(ULONG));
2479 }
2480
2481 /*
2482 * Check the request is valid.
2483 */
2484 if ((SystemInformationClass >= MIN_SYSTEM_INFO_CLASS) &&
2485 (SystemInformationClass < MAX_SYSTEM_INFO_CLASS))
2486 {
2487 if (NULL != CallQS [SystemInformationClass].Set)
2488 {
2489 /*
2490 * Hand the request to a subhandler.
2491 */
2492 Status = CallQS [SystemInformationClass].Set(SystemInformation,
2493 SystemInformationLength);
2494 }
2495 }
2496 }
2497 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2498 {
2499 Status = _SEH2_GetExceptionCode();
2500 }
2501 _SEH2_END;
2502
2503 return Status;
2504 }
2505
2506 NTSTATUS
2507 NTAPI
2508 NtFlushInstructionCache(
2509 _In_ HANDLE ProcessHandle,
2510 _In_opt_ PVOID BaseAddress,
2511 _In_ ULONG FlushSize)
2512 {
2513 KAPC_STATE ApcState;
2514 PKPROCESS Process;
2515 NTSTATUS Status;
2516 PAGED_CODE();
2517
2518 /* Is a base address given? */
2519 if (BaseAddress != NULL)
2520 {
2521 /* If the requested size is 0, there is nothing to do */
2522 if (FlushSize == 0)
2523 {
2524 return STATUS_SUCCESS;
2525 }
2526
2527 /* Is this a user mode call? */
2528 if (KeGetPreviousMode() != KernelMode)
2529 {
2530 /* Make sure the base address is in user space */
2531 if (BaseAddress > MmHighestUserAddress)
2532 {
2533 DPRINT1("Invalid BaseAddress 0x%p\n", BaseAddress);
2534 return STATUS_ACCESS_VIOLATION;
2535 }
2536 }
2537 }
2538
2539 /* Is another process requested? */
2540 if (ProcessHandle != NtCurrentProcess())
2541 {
2542 /* Reference the process */
2543 Status = ObReferenceObjectByHandle(ProcessHandle,
2544 PROCESS_VM_WRITE,
2545 PsProcessType,
2546 KeGetPreviousMode(),
2547 (PVOID*)&Process,
2548 NULL);
2549 if (!NT_SUCCESS(Status))
2550 {
2551 DPRINT1("Failed to reference the process %p\n", ProcessHandle);
2552 return Status;
2553 }
2554
2555 /* Attach to the process */
2556 KeStackAttachProcess(Process, &ApcState);
2557 }
2558
2559 /* FIXME: don't flush everything if a range is requested */
2560 #if defined(_M_IX86) || defined(_M_AMD64)
2561 __wbinvd();
2562 #elif defined(_M_PPC)
2563 __asm__ __volatile__("tlbsync");
2564 #elif defined(_M_MIPS)
2565 DPRINT1("NtFlushInstructionCache() is not implemented\n");
2566 DbgBreakPoint();
2567 #elif defined(_M_ARM)
2568 _MoveToCoprocessor(0, CP15_ICIALLU);
2569 #else
2570 #error Unknown architecture
2571 #endif
2572
2573 /* Check if we attached */
2574 if (ProcessHandle != NtCurrentProcess())
2575 {
2576 /* Detach from the process */
2577 KeUnstackDetachProcess(&ApcState);
2578 }
2579
2580 return STATUS_SUCCESS;
2581 }
2582
2583 ULONG
2584 NTAPI
2585 NtGetCurrentProcessorNumber(VOID)
2586 {
2587 /* Just return the CPU */
2588 return KeGetCurrentProcessorNumber();
2589 }
2590
2591 /*
2592 * @implemented
2593 */
2594 #undef ExGetPreviousMode
2595 KPROCESSOR_MODE
2596 NTAPI
2597 ExGetPreviousMode (VOID)
2598 {
2599 return KeGetPreviousMode();
2600 }