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