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