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