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