reactos/ntoskrnl/ex/sysinfo.c
Eugen Podrug 8e01dee251 [NTOS:EX] Fix swapped values in ExGetCurrentProcessorCounts() (#4565)
The function should return the kernel time for the idle thread in the
first argument, and kernel time + user time for the current thread in
the second argument.

Also retrieve the processor number from the cached PRCB instead of
calling KeGetCurrentProcessorNumber() which retrieves the PRCB again
since the processor could switch in-between those calls.

NdisGetCurrentProcessorCounts() function follows the same prototype
which is the correct one.
2023-07-02 16:10:36 +03:00

3066 lines
93 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ex/sysinfo.c
* PURPOSE: System information functions
*
* PROGRAMMERS: David Welch (welch@mcmail.com)
* Aleksey Bragin (aleksey@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#include <wmidata.h>
#include <wmistr.h>
#define NDEBUG
#include <debug.h>
/* The maximum size of an environment value (in bytes) */
#define MAX_ENVVAL_SIZE 1024
#define SIG_ACPI 0x41435049
#define SIG_FIRM 0x4649524D
#define SIG_RSMB 0x52534D42
extern LIST_ENTRY HandleTableListHead;
extern EX_PUSH_LOCK HandleTableListLock;
FAST_MUTEX ExpEnvironmentLock;
ERESOURCE ExpFirmwareTableResource;
LIST_ENTRY ExpFirmwareTableProviderListHead;
FORCEINLINE
NTSTATUS
ExpConvertLdrModuleToRtlModule(IN ULONG ModuleCount,
IN PLDR_DATA_TABLE_ENTRY LdrEntry,
OUT PRTL_PROCESS_MODULE_INFORMATION ModuleInfo)
{
PCHAR p;
NTSTATUS Status;
ANSI_STRING ModuleName;
/* Fill it out */
ModuleInfo->MappedBase = NULL;
ModuleInfo->ImageBase = LdrEntry->DllBase;
ModuleInfo->ImageSize = LdrEntry->SizeOfImage;
ModuleInfo->Flags = LdrEntry->Flags;
ModuleInfo->LoadCount = LdrEntry->LoadCount;
ModuleInfo->LoadOrderIndex = (USHORT)ModuleCount;
ModuleInfo->InitOrderIndex = 0;
/* Setup name */
RtlInitEmptyAnsiString(&ModuleName,
ModuleInfo->FullPathName,
sizeof(ModuleInfo->FullPathName));
/* Convert it */
Status = RtlUnicodeStringToAnsiString(&ModuleName,
&LdrEntry->FullDllName,
FALSE);
if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
{
/* Calculate offset to name */
p = ModuleName.Buffer + ModuleName.Length;
while ((p > ModuleName.Buffer) && (*--p))
{
/* Check if we found the separator */
if (*p == OBJ_NAME_PATH_SEPARATOR)
{
/* We did, break out */
p++;
break;
}
}
/* Set the offset */
ModuleInfo->OffsetToFileName = (USHORT)(p - ModuleName.Buffer);
}
else
{
/* Return empty name */
ModuleInfo->FullPathName[0] = ANSI_NULL;
ModuleInfo->OffsetToFileName = 0;
}
return Status;
}
NTSTATUS
NTAPI
ExpQueryModuleInformation(IN PLIST_ENTRY KernelModeList,
IN PLIST_ENTRY UserModeList,
OUT PRTL_PROCESS_MODULES Modules,
IN ULONG Length,
OUT PULONG ReturnLength)
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG RequiredLength;
PRTL_PROCESS_MODULE_INFORMATION ModuleInfo;
PLDR_DATA_TABLE_ENTRY LdrEntry;
ULONG ModuleCount = 0;
PLIST_ENTRY NextEntry;
/* Setup defaults */
RequiredLength = FIELD_OFFSET(RTL_PROCESS_MODULES, Modules);
ModuleInfo = &Modules->Modules[0];
/* Loop the kernel list */
NextEntry = KernelModeList->Flink;
while (NextEntry != KernelModeList)
{
/* Get the entry */
LdrEntry = CONTAINING_RECORD(NextEntry,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
/* Update size and check if we can manage one more entry */
RequiredLength += sizeof(RTL_PROCESS_MODULE_INFORMATION);
if (Length >= RequiredLength)
{
Status = ExpConvertLdrModuleToRtlModule(ModuleCount,
LdrEntry,
ModuleInfo);
/* Go to the next module */
ModuleInfo++;
}
else
{
/* Set error code */
Status = STATUS_INFO_LENGTH_MISMATCH;
}
/* Update count and move to next entry */
ModuleCount++;
NextEntry = NextEntry->Flink;
}
/* Check if caller also wanted user modules */
if (UserModeList)
{
NextEntry = UserModeList->Flink;
while (NextEntry != UserModeList)
{
/* Get the entry */
LdrEntry = CONTAINING_RECORD(NextEntry,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
/* Update size and check if we can manage one more entry */
RequiredLength += sizeof(RTL_PROCESS_MODULE_INFORMATION);
if (Length >= RequiredLength)
{
Status = ExpConvertLdrModuleToRtlModule(ModuleCount,
LdrEntry,
ModuleInfo);
/* Go to the next module */
ModuleInfo++;
}
else
{
/* Set error code */
Status = STATUS_INFO_LENGTH_MISMATCH;
}
/* Update count and move to next entry */
ModuleCount++;
NextEntry = NextEntry->Flink;
}
}
/* Update return length */
if (ReturnLength) *ReturnLength = RequiredLength;
/* Validate the length again */
if (Length >= FIELD_OFFSET(RTL_PROCESS_MODULES, Modules))
{
/* Set the final count */
Modules->NumberOfModules = ModuleCount;
}
else
{
/* Otherwise, we failed */
Status = STATUS_INFO_LENGTH_MISMATCH;
}
/* Done */
return Status;
}
VOID
NTAPI
ExUnlockUserBuffer(PMDL Mdl)
{
MmUnlockPages(Mdl);
ExFreePoolWithTag(Mdl, TAG_MDL);
}
NTSTATUS
NTAPI
ExLockUserBuffer(
PVOID BaseAddress,
ULONG Length,
KPROCESSOR_MODE AccessMode,
LOCK_OPERATION Operation,
PVOID *MappedSystemVa,
PMDL *OutMdl)
{
PMDL Mdl;
PAGED_CODE();
*MappedSystemVa = NULL;
*OutMdl = NULL;
/* Allocate an MDL for the buffer */
Mdl = IoAllocateMdl(BaseAddress, Length, FALSE, TRUE, NULL);
if (Mdl == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Enter SEH for probing */
_SEH2_TRY
{
MmProbeAndLockPages(Mdl, AccessMode, Operation);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ExFreePoolWithTag(Mdl, TAG_MDL);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
/* Return the safe kernel mode buffer */
*MappedSystemVa = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
if (*MappedSystemVa == NULL)
{
ExUnlockUserBuffer(Mdl);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Return the MDL */
*OutMdl = Mdl;
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
ExpGetRawSMBiosTable(
_Out_opt_ PVOID Buffer,
_Out_ ULONG * OutSize,
_In_ ULONG BufferSize)
{
NTSTATUS Status;
PVOID DataBlockObject;
PWNODE_ALL_DATA AllData;
ULONG WMIBufSize;
ASSERT(OutSize != NULL);
*OutSize = 0;
/* Open the data block object for the SMBIOS table */
Status = IoWMIOpenBlock(&MSSmBios_RawSMBiosTables_GUID,
WMIGUID_QUERY,
&DataBlockObject);
if (!NT_SUCCESS(Status))
{
DPRINT1("IoWMIOpenBlock failed: 0x%08lx\n", Status);
return Status;
}
/* Query the required buffer size */
WMIBufSize = 0;
Status = IoWMIQueryAllData(DataBlockObject, &WMIBufSize, NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("IoWMIOpenBlock failed: 0x%08lx\n", Status);
return Status;
}
AllData = ExAllocatePoolWithTag(PagedPool, WMIBufSize, 'itfS');
if (AllData == NULL)
{
DPRINT1("Failed to allocate %lu bytes for SMBIOS tables\n", WMIBufSize);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Query the buffer data */
Status = IoWMIQueryAllData(DataBlockObject, &WMIBufSize, AllData);
if (!NT_SUCCESS(Status))
{
DPRINT1("IoWMIOpenBlock failed: 0x%08lx\n", Status);
ExFreePoolWithTag(AllData, 'itfS');
return Status;
}
Status = STATUS_SUCCESS;
*OutSize = AllData->FixedInstanceSize;
if (Buffer != NULL)
{
if (BufferSize >= *OutSize)
{
RtlMoveMemory(Buffer, AllData + 1, *OutSize);
}
else
{
Status = STATUS_BUFFER_TOO_SMALL;
}
}
/* Free the buffer */
ExFreePoolWithTag(AllData, 'itfS');
return Status;
}
/* FUNCTIONS *****************************************************************/
/*
* @implemented
*/
VOID
NTAPI
ExGetCurrentProcessorCpuUsage(PULONG CpuUsage)
{
PKPRCB Prcb;
ULONG TotalTime;
ULONGLONG ScaledIdle;
Prcb = KeGetCurrentPrcb();
ScaledIdle = (ULONGLONG)Prcb->IdleThread->KernelTime * 100;
TotalTime = Prcb->KernelTime + Prcb->UserTime;
if (TotalTime != 0)
*CpuUsage = (ULONG)(100 - (ScaledIdle / TotalTime));
else
*CpuUsage = 0;
}
/*
* @implemented
*/
VOID
NTAPI
ExGetCurrentProcessorCounts(PULONG IdleTime,
PULONG KernelAndUserTime,
PULONG ProcessorNumber)
{
PKPRCB Prcb;
Prcb = KeGetCurrentPrcb();
*IdleTime = Prcb->IdleThread->KernelTime;
*KernelAndUserTime = Prcb->KernelTime + Prcb->UserTime;
*ProcessorNumber = (ULONG)Prcb->Number;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
ExIsProcessorFeaturePresent(IN ULONG ProcessorFeature)
{
/* Quick check to see if it exists at all */
if (ProcessorFeature >= PROCESSOR_FEATURE_MAX) return(FALSE);
/* Return our support for it */
return(SharedUserData->ProcessorFeatures[ProcessorFeature]);
}
/*
* @implemented
*/
BOOLEAN
NTAPI
ExVerifySuite(SUITE_TYPE SuiteType)
{
if (SuiteType == Personal) return TRUE;
return FALSE;
}
NTSTATUS
NTAPI
NtQuerySystemEnvironmentValue(IN PUNICODE_STRING VariableName,
OUT PWSTR ValueBuffer,
IN ULONG ValueBufferLength,
IN OUT PULONG ReturnLength OPTIONAL)
{
ANSI_STRING AName;
UNICODE_STRING WName;
ARC_STATUS Result;
PCH AnsiValueBuffer;
ANSI_STRING AValue;
UNICODE_STRING WValue;
KPROCESSOR_MODE PreviousMode;
NTSTATUS Status;
PAGED_CODE();
/* Check if the call came from user mode */
PreviousMode = ExGetPreviousMode();
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
/* Probe the input and output buffers */
ProbeForRead(VariableName, sizeof(UNICODE_STRING), sizeof(ULONG));
ProbeForWrite(ValueBuffer, ValueBufferLength, sizeof(WCHAR));
if (ReturnLength != NULL) ProbeForWriteUlong(ReturnLength);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* According to NTInternals the SeSystemEnvironmentName privilege is required! */
if (!SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege, PreviousMode))
{
DPRINT1("NtQuerySystemEnvironmentValue: Caller requires the SeSystemEnvironmentPrivilege privilege!\n");
return STATUS_PRIVILEGE_NOT_HELD;
}
/* Copy the name to kernel space if necessary */
Status = ProbeAndCaptureUnicodeString(&WName, PreviousMode, VariableName);
if (!NT_SUCCESS(Status)) return Status;
/* Convert the name to ANSI and release the captured UNICODE string */
Status = RtlUnicodeStringToAnsiString(&AName, &WName, TRUE);
ReleaseCapturedUnicodeString(&WName, PreviousMode);
if (!NT_SUCCESS(Status)) return Status;
/* Allocate a buffer for the ANSI environment variable */
AnsiValueBuffer = ExAllocatePoolWithTag(NonPagedPool, MAX_ENVVAL_SIZE, 'rvnE');
if (AnsiValueBuffer == NULL)
{
RtlFreeAnsiString(&AName);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Get the environment variable and free the ANSI name */
Result = HalGetEnvironmentVariable(AName.Buffer,
MAX_ENVVAL_SIZE,
AnsiValueBuffer);
RtlFreeAnsiString(&AName);
/* Check if we had success */
if (Result == ESUCCESS)
{
/* Copy the result back to the caller. */
_SEH2_TRY
{
/* Initialize ANSI string from the result */
RtlInitAnsiString(&AValue, AnsiValueBuffer);
/* Initialize a UNICODE string from the callers buffer */
RtlInitEmptyUnicodeString(&WValue, ValueBuffer, (USHORT)ValueBufferLength);
/* Convert the result to UNICODE */
Status = RtlAnsiStringToUnicodeString(&WValue, &AValue, FALSE);
if (ReturnLength != NULL)
*ReturnLength = WValue.Length;
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
else
{
Status = STATUS_UNSUCCESSFUL;
}
/* Free the allocated ANSI value buffer */
ExFreePoolWithTag(AnsiValueBuffer, 'rvnE');
return Status;
}
NTSTATUS
NTAPI
NtSetSystemEnvironmentValue(IN PUNICODE_STRING VariableName,
IN PUNICODE_STRING Value)
{
UNICODE_STRING CapturedName, CapturedValue;
ANSI_STRING AName, AValue;
KPROCESSOR_MODE PreviousMode;
NTSTATUS Status;
PAGED_CODE();
PreviousMode = ExGetPreviousMode();
/*
* Copy the strings to kernel space if necessary
*/
Status = ProbeAndCaptureUnicodeString(&CapturedName,
PreviousMode,
VariableName);
if (NT_SUCCESS(Status))
{
Status = ProbeAndCaptureUnicodeString(&CapturedValue,
PreviousMode,
Value);
if (NT_SUCCESS(Status))
{
/*
* according to ntinternals the SeSystemEnvironmentName privilege is required!
*/
if (SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege,
PreviousMode))
{
/*
* convert the strings to ANSI
*/
Status = RtlUnicodeStringToAnsiString(&AName,
&CapturedName,
TRUE);
if (NT_SUCCESS(Status))
{
Status = RtlUnicodeStringToAnsiString(&AValue,
&CapturedValue,
TRUE);
if (NT_SUCCESS(Status))
{
ARC_STATUS Result = HalSetEnvironmentVariable(AName.Buffer,
AValue.Buffer);
Status = (Result ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
}
}
}
else
{
DPRINT1("NtSetSystemEnvironmentValue: Caller requires the SeSystemEnvironmentPrivilege privilege!\n");
Status = STATUS_PRIVILEGE_NOT_HELD;
}
ReleaseCapturedUnicodeString(&CapturedValue,
PreviousMode);
}
ReleaseCapturedUnicodeString(&CapturedName,
PreviousMode);
}
return Status;
}
NTSTATUS
NTAPI
NtEnumerateSystemEnvironmentValuesEx(IN ULONG InformationClass,
IN PVOID Buffer,
IN ULONG BufferLength)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
NtQuerySystemEnvironmentValueEx(IN PUNICODE_STRING VariableName,
IN LPGUID VendorGuid,
IN PVOID Value,
IN OUT PULONG ReturnLength,
IN OUT PULONG Attributes)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
NtSetSystemEnvironmentValueEx(IN PUNICODE_STRING VariableName,
IN LPGUID VendorGuid,
IN PVOID Value,
IN OUT PULONG ReturnLength,
IN OUT PULONG Attributes)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/* --- Query/Set System Information --- */
/*
* NOTE: QSI_DEF(n) and SSI_DEF(n) define _cdecl function symbols
* so the stack is popped only in one place on x86 platform.
*/
#define QSI_USE(n) QSI##n
#define QSI_DEF(n) \
static NTSTATUS QSI_USE(n) (PVOID Buffer, ULONG Size, PULONG ReqSize)
#define SSI_USE(n) SSI##n
#define SSI_DEF(n) \
static NTSTATUS SSI_USE(n) (PVOID Buffer, ULONG Size)
VOID
NTAPI
ExQueryPoolUsage(OUT PULONG PagedPoolPages,
OUT PULONG NonPagedPoolPages,
OUT PULONG PagedPoolAllocs,
OUT PULONG PagedPoolFrees,
OUT PULONG PagedPoolLookasideHits,
OUT PULONG NonPagedPoolAllocs,
OUT PULONG NonPagedPoolFrees,
OUT PULONG NonPagedPoolLookasideHits);
/* Class 0 - Basic Information */
QSI_DEF(SystemBasicInformation)
{
PSYSTEM_BASIC_INFORMATION Sbi
= (PSYSTEM_BASIC_INFORMATION) Buffer;
*ReqSize = sizeof(SYSTEM_BASIC_INFORMATION);
/* Check user buffer's size */
if (Size != sizeof(SYSTEM_BASIC_INFORMATION))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
RtlZeroMemory(Sbi, Size);
Sbi->Reserved = 0;
Sbi->TimerResolution = KeMaximumIncrement;
Sbi->PageSize = PAGE_SIZE;
Sbi->NumberOfPhysicalPages = MmNumberOfPhysicalPages;
Sbi->LowestPhysicalPageNumber = (ULONG)MmLowestPhysicalPage;
Sbi->HighestPhysicalPageNumber = (ULONG)MmHighestPhysicalPage;
Sbi->AllocationGranularity = MM_VIRTMEM_GRANULARITY; /* hard coded on Intel? */
Sbi->MinimumUserModeAddress = 0x10000; /* Top of 64k */
Sbi->MaximumUserModeAddress = (ULONG_PTR)MmHighestUserAddress;
Sbi->ActiveProcessorsAffinityMask = KeActiveProcessors;
Sbi->NumberOfProcessors = KeNumberProcessors;
return STATUS_SUCCESS;
}
/* Class 1 - Processor Information */
QSI_DEF(SystemProcessorInformation)
{
PSYSTEM_PROCESSOR_INFORMATION Spi
= (PSYSTEM_PROCESSOR_INFORMATION) Buffer;
*ReqSize = sizeof(SYSTEM_PROCESSOR_INFORMATION);
/* Check user buffer's size */
if (Size < sizeof(SYSTEM_PROCESSOR_INFORMATION))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
Spi->ProcessorArchitecture = KeProcessorArchitecture;
Spi->ProcessorLevel = KeProcessorLevel;
Spi->ProcessorRevision = KeProcessorRevision;
#if (NTDDI_VERSION < NTDDI_WIN8)
Spi->Reserved = 0;
#else
Spi->MaximumProcessors = 0;
#endif
Spi->ProcessorFeatureBits = KeFeatureBits;
DPRINT("Arch %u Level %u Rev 0x%x\n", Spi->ProcessorArchitecture,
Spi->ProcessorLevel, Spi->ProcessorRevision);
return STATUS_SUCCESS;
}
/* Class 2 - Performance Information */
QSI_DEF(SystemPerformanceInformation)
{
LONG i;
ULONG IdleUser, IdleKernel;
PKPRCB Prcb;
PSYSTEM_PERFORMANCE_INFORMATION Spi
= (PSYSTEM_PERFORMANCE_INFORMATION) Buffer;
PEPROCESS TheIdleProcess;
*ReqSize = sizeof(SYSTEM_PERFORMANCE_INFORMATION);
/* Check user buffer's size */
if (Size < sizeof(SYSTEM_PERFORMANCE_INFORMATION))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
TheIdleProcess = PsIdleProcess;
IdleKernel = KeQueryRuntimeProcess(&TheIdleProcess->Pcb, &IdleUser);
Spi->IdleProcessTime.QuadPart = UInt32x32To64(IdleKernel, KeMaximumIncrement);
Spi->IoReadTransferCount = IoReadTransferCount;
Spi->IoWriteTransferCount = IoWriteTransferCount;
Spi->IoOtherTransferCount = IoOtherTransferCount;
Spi->IoReadOperationCount = IoReadOperationCount;
Spi->IoWriteOperationCount = IoWriteOperationCount;
Spi->IoOtherOperationCount = IoOtherOperationCount;
for (i = 0; i < KeNumberProcessors; i ++)
{
Prcb = KiProcessorBlock[i];
if (Prcb)
{
Spi->IoReadTransferCount.QuadPart += Prcb->IoReadTransferCount.QuadPart;
Spi->IoWriteTransferCount.QuadPart += Prcb->IoWriteTransferCount.QuadPart;
Spi->IoOtherTransferCount.QuadPart += Prcb->IoOtherTransferCount.QuadPart;
Spi->IoReadOperationCount += Prcb->IoReadOperationCount;
Spi->IoWriteOperationCount += Prcb->IoWriteOperationCount;
Spi->IoOtherOperationCount += Prcb->IoOtherOperationCount;
}
}
Spi->AvailablePages = (ULONG)MmAvailablePages;
Spi->CommittedPages = MmTotalCommittedPages;
/*
* Add up the full system total + pagefile.
* All this make Taskmgr happy but not sure it is the right numbers.
* This too, fixes some of GlobalMemoryStatusEx numbers.
*/
Spi->CommitLimit = MmNumberOfPhysicalPages + MiFreeSwapPages + MiUsedSwapPages;
Spi->PeakCommitment = MmPeakCommitment;
Spi->PageFaultCount = 0; /* FIXME */
Spi->CopyOnWriteCount = 0; /* FIXME */
Spi->TransitionCount = 0; /* FIXME */
Spi->CacheTransitionCount = 0; /* FIXME */
Spi->DemandZeroCount = 0; /* FIXME */
Spi->PageReadCount = 0; /* FIXME */
Spi->PageReadIoCount = 0; /* FIXME */
Spi->CacheReadCount = 0; /* FIXME */
Spi->CacheIoCount = 0; /* FIXME */
Spi->DirtyPagesWriteCount = 0; /* FIXME */
Spi->DirtyWriteIoCount = 0; /* FIXME */
Spi->MappedPagesWriteCount = 0; /* FIXME */
Spi->MappedWriteIoCount = 0; /* FIXME */
Spi->PagedPoolPages = 0;
Spi->NonPagedPoolPages = 0;
Spi->PagedPoolAllocs = 0;
Spi->PagedPoolFrees = 0;
Spi->PagedPoolLookasideHits = 0;
Spi->NonPagedPoolAllocs = 0;
Spi->NonPagedPoolFrees = 0;
Spi->NonPagedPoolLookasideHits = 0;
ExQueryPoolUsage(&Spi->PagedPoolPages,
&Spi->NonPagedPoolPages,
&Spi->PagedPoolAllocs,
&Spi->PagedPoolFrees,
&Spi->PagedPoolLookasideHits,
&Spi->NonPagedPoolAllocs,
&Spi->NonPagedPoolFrees,
&Spi->NonPagedPoolLookasideHits);
Spi->FreeSystemPtes = 0; /* FIXME */
Spi->ResidentSystemCodePage = 0; /* FIXME */
Spi->TotalSystemDriverPages = 0; /* FIXME */
Spi->Spare3Count = 0; /* FIXME */
Spi->ResidentSystemCachePage = MiMemoryConsumers[MC_USER].PagesUsed; /* FIXME */
Spi->ResidentPagedPoolPage = 0; /* FIXME */
Spi->ResidentSystemDriverPage = 0; /* FIXME */
Spi->CcFastReadNoWait = 0; /* FIXME */
Spi->CcFastReadWait = 0; /* FIXME */
Spi->CcFastReadResourceMiss = 0; /* FIXME */
Spi->CcFastReadNotPossible = 0; /* FIXME */
Spi->CcFastMdlReadNoWait = 0; /* FIXME */
Spi->CcFastMdlReadWait = 0; /* FIXME */
Spi->CcFastMdlReadResourceMiss = 0; /* FIXME */
Spi->CcFastMdlReadNotPossible = 0; /* FIXME */
Spi->CcMapDataNoWait = CcMapDataNoWait;
Spi->CcMapDataWait = CcMapDataWait;
Spi->CcMapDataNoWaitMiss = 0; /* FIXME */
Spi->CcMapDataWaitMiss = 0; /* FIXME */
Spi->CcPinMappedDataCount = CcPinMappedDataCount;
Spi->CcPinReadNoWait = CcPinReadNoWait;
Spi->CcPinReadWait = CcPinReadWait;
Spi->CcPinReadNoWaitMiss = 0; /* FIXME */
Spi->CcPinReadWaitMiss = 0; /* FIXME */
Spi->CcCopyReadNoWait = 0; /* FIXME */
Spi->CcCopyReadWait = 0; /* FIXME */
Spi->CcCopyReadNoWaitMiss = 0; /* FIXME */
Spi->CcCopyReadWaitMiss = 0; /* FIXME */
Spi->CcMdlReadNoWait = 0; /* FIXME */
Spi->CcMdlReadWait = 0; /* FIXME */
Spi->CcMdlReadNoWaitMiss = 0; /* FIXME */
Spi->CcMdlReadWaitMiss = 0; /* FIXME */
Spi->CcReadAheadIos = 0; /* FIXME */
Spi->CcLazyWriteIos = CcLazyWriteIos;
Spi->CcLazyWritePages = CcLazyWritePages;
Spi->CcDataFlushes = CcDataFlushes;
Spi->CcDataPages = CcDataPages;
Spi->ContextSwitches = 0;
Spi->FirstLevelTbFills = 0;
Spi->SecondLevelTbFills = 0;
Spi->SystemCalls = 0;
for (i = 0; i < KeNumberProcessors; i ++)
{
Prcb = KiProcessorBlock[i];
if (Prcb)
{
Spi->ContextSwitches += KeGetContextSwitches(Prcb);
Spi->FirstLevelTbFills += Prcb->KeFirstLevelTbFills;
Spi->SecondLevelTbFills += Prcb->KeSecondLevelTbFills;
Spi->SystemCalls += Prcb->KeSystemCalls;
}
}
return STATUS_SUCCESS;
}
/* Class 3 - Time Of Day Information */
QSI_DEF(SystemTimeOfDayInformation)
{
SYSTEM_TIMEOFDAY_INFORMATION Sti;
LARGE_INTEGER CurrentTime;
/* Set amount of written information to 0 */
*ReqSize = 0;
/* Check user buffer's size */
if (Size > sizeof(SYSTEM_TIMEOFDAY_INFORMATION))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
/* Get current time */
KeQuerySystemTime(&CurrentTime);
/* Zero local buffer */
RtlZeroMemory(&Sti, sizeof(SYSTEM_TIMEOFDAY_INFORMATION));
/* Fill local time structure */
Sti.BootTime= KeBootTime;
Sti.CurrentTime = CurrentTime;
Sti.TimeZoneBias.QuadPart = ExpTimeZoneBias.QuadPart;
Sti.TimeZoneId = ExpTimeZoneId;
Sti.Reserved = 0;
/* Copy as much as requested by caller */
RtlCopyMemory(Buffer, &Sti, Size);
/* Set amount of information we copied */
*ReqSize = Size;
return STATUS_SUCCESS;
}
/* Class 4 - Path Information (DEPRECATED) */
QSI_DEF(SystemPathInformation)
{
/*
* Since NT 3.51, this information class is trivially implemented.
* The path to the NT directory is now stored in KUSER_SHARED_DATA
* as the NtSystemRoot member.
* Windows Checked builds show the following message and break to
* the debugger before failing the function as not implemented.
*/
#if DBG
DPRINT1("EX: SystemPathInformation now available via SharedUserData\n");
// DbgBreakPoint(); // Not needed in ReactOS.
#endif
return STATUS_NOT_IMPLEMENTED;
}
/* Class 5 - Process Information */
QSI_DEF(SystemProcessInformation)
{
PSYSTEM_PROCESS_INFORMATION SpiCurrent;
PSYSTEM_THREAD_INFORMATION ThreadInfo;
PEPROCESS Process = NULL, SystemProcess;
PETHREAD CurrentThread;
ANSI_STRING ImageName;
ULONG CurrentSize;
USHORT ImageNameMaximumLength; // image name length in bytes
USHORT ImageNameLength;
PLIST_ENTRY CurrentEntry;
ULONG TotalSize = 0, ThreadsCount;
ULONG TotalUser, TotalKernel;
PUCHAR Current;
NTSTATUS Status = STATUS_SUCCESS;
PUNICODE_STRING TempProcessImageName;
_SEH2_VOLATILE PUNICODE_STRING ProcessImageName = NULL;
PWCHAR szSrc;
BOOLEAN Overflow = FALSE;
_SEH2_TRY
{
/* scan the process list */
PSYSTEM_PROCESS_INFORMATION Spi
= (PSYSTEM_PROCESS_INFORMATION) Buffer;
*ReqSize = sizeof(SYSTEM_PROCESS_INFORMATION);
/* Check for overflow */
if (Size < sizeof(SYSTEM_PROCESS_INFORMATION))
{
Overflow = TRUE;
}
/* Zero user's buffer */
if (!Overflow) RtlZeroMemory(Spi, Size);
SystemProcess = PsIdleProcess;
Process = SystemProcess;
Current = (PUCHAR) Spi;
do
{
SpiCurrent = (PSYSTEM_PROCESS_INFORMATION) Current;
/* Lock the Process */
KeEnterCriticalRegion();
ExAcquirePushLockShared(&Process->ProcessLock);
if ((Process->ProcessExiting) &&
(Process->Pcb.Header.SignalState) &&
!(Process->ActiveThreads) &&
(IsListEmpty(&Process->Pcb.ThreadListHead)))
{
DPRINT1("Process %p (%s:%p) is a zombie\n",
Process, Process->ImageFileName, Process->UniqueProcessId);
CurrentSize = 0;
ImageNameMaximumLength = 0;
/* Unlock the Process */
ExReleasePushLockShared(&Process->ProcessLock);
KeLeaveCriticalRegion();
goto Skip;
}
ThreadsCount = 0;
CurrentEntry = Process->Pcb.ThreadListHead.Flink;
while (CurrentEntry != &Process->Pcb.ThreadListHead)
{
ThreadsCount++;
CurrentEntry = CurrentEntry->Flink;
}
// size of the structure for every process
CurrentSize = sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_THREAD_INFORMATION) * ThreadsCount;
ImageNameLength = 0;
Status = SeLocateProcessImageName(Process, &TempProcessImageName);
ProcessImageName = TempProcessImageName;
szSrc = NULL;
if (NT_SUCCESS(Status) && (ProcessImageName->Length > 0))
{
szSrc = (PWCHAR)((PCHAR)ProcessImageName->Buffer + ProcessImageName->Length);
/* Loop the file name*/
while (szSrc > ProcessImageName->Buffer)
{
/* Make sure this isn't a backslash */
if (*--szSrc == OBJ_NAME_PATH_SEPARATOR)
{
szSrc++;
break;
}
else
{
ImageNameLength += sizeof(WCHAR);
}
}
}
if (!ImageNameLength && Process != PsIdleProcess)
{
ImageNameLength = (USHORT)strlen(Process->ImageFileName) * sizeof(WCHAR);
}
/* Round up the image name length as NT does */
if (ImageNameLength > 0)
ImageNameMaximumLength = ROUND_UP(ImageNameLength + sizeof(WCHAR), 8);
else
ImageNameMaximumLength = 0;
TotalSize += CurrentSize + ImageNameMaximumLength;
/* Check for overflow */
if (TotalSize > Size)
{
Overflow = TRUE;
}
/* Fill system information */
if (!Overflow)
{
SpiCurrent->NextEntryOffset = CurrentSize + ImageNameMaximumLength; // relative offset to the beginning of the next structure
SpiCurrent->NumberOfThreads = ThreadsCount;
SpiCurrent->CreateTime = Process->CreateTime;
SpiCurrent->ImageName.Length = ImageNameLength;
SpiCurrent->ImageName.MaximumLength = ImageNameMaximumLength;
SpiCurrent->ImageName.Buffer = (void*)(Current + CurrentSize);
/* Copy name to the end of the struct */
if(Process != PsIdleProcess)
{
if (szSrc)
{
RtlCopyMemory(SpiCurrent->ImageName.Buffer, szSrc, SpiCurrent->ImageName.Length);
}
else
{
RtlInitAnsiString(&ImageName, Process->ImageFileName);
Status = RtlAnsiStringToUnicodeString(&SpiCurrent->ImageName, &ImageName, FALSE);
if (!NT_SUCCESS(Status))
{
SpiCurrent->ImageName.Length = 0;
}
}
}
else
{
RtlInitUnicodeString(&SpiCurrent->ImageName, NULL);
}
SpiCurrent->BasePriority = Process->Pcb.BasePriority;
SpiCurrent->UniqueProcessId = Process->UniqueProcessId;
SpiCurrent->InheritedFromUniqueProcessId = Process->InheritedFromUniqueProcessId;
/* PsIdleProcess shares its handle table with PsInitialSystemProcess,
* so return the handle count for System only, not Idle one. */
SpiCurrent->HandleCount = (Process == PsIdleProcess) ? 0 : ObGetProcessHandleCount(Process);
SpiCurrent->PeakVirtualSize = Process->PeakVirtualSize;
SpiCurrent->VirtualSize = Process->VirtualSize;
SpiCurrent->PageFaultCount = Process->Vm.PageFaultCount;
SpiCurrent->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
SpiCurrent->WorkingSetSize = Process->Vm.WorkingSetSize;
SpiCurrent->QuotaPeakPagedPoolUsage = Process->QuotaPeak[PsPagedPool];
SpiCurrent->QuotaPagedPoolUsage = Process->QuotaUsage[PsPagedPool];
SpiCurrent->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[PsNonPagedPool];
SpiCurrent->QuotaNonPagedPoolUsage = Process->QuotaUsage[PsNonPagedPool];
SpiCurrent->PagefileUsage = Process->QuotaUsage[PsPageFile];
SpiCurrent->PeakPagefileUsage = Process->QuotaPeak[PsPageFile];
SpiCurrent->PrivatePageCount = Process->CommitCharge;
ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(SpiCurrent + 1);
CurrentEntry = Process->Pcb.ThreadListHead.Flink;
while (CurrentEntry != &Process->Pcb.ThreadListHead)
{
CurrentThread = CONTAINING_RECORD(CurrentEntry, ETHREAD, Tcb.ThreadListEntry);
ThreadInfo->KernelTime.QuadPart = UInt32x32To64(CurrentThread->Tcb.KernelTime, KeMaximumIncrement);
ThreadInfo->UserTime.QuadPart = UInt32x32To64(CurrentThread->Tcb.UserTime, KeMaximumIncrement);
ThreadInfo->CreateTime.QuadPart = CurrentThread->CreateTime.QuadPart;
ThreadInfo->WaitTime = CurrentThread->Tcb.WaitTime;
ThreadInfo->StartAddress = (PVOID) CurrentThread->StartAddress;
ThreadInfo->ClientId = CurrentThread->Cid;
ThreadInfo->Priority = CurrentThread->Tcb.Priority;
ThreadInfo->BasePriority = CurrentThread->Tcb.BasePriority;
ThreadInfo->ContextSwitches = CurrentThread->Tcb.ContextSwitches;
ThreadInfo->ThreadState = CurrentThread->Tcb.State;
ThreadInfo->WaitReason = CurrentThread->Tcb.WaitReason;
ThreadInfo++;
CurrentEntry = CurrentEntry->Flink;
}
/* Query total user/kernel times of a process */
TotalKernel = KeQueryRuntimeProcess(&Process->Pcb, &TotalUser);
SpiCurrent->UserTime.QuadPart = UInt32x32To64(TotalUser, KeMaximumIncrement);
SpiCurrent->KernelTime.QuadPart = UInt32x32To64(TotalKernel, KeMaximumIncrement);
}
if (ProcessImageName)
{
/* Release the memory allocated by SeLocateProcessImageName */
ExFreePoolWithTag(ProcessImageName, TAG_SEPA);
ProcessImageName = NULL;
}
/* Unlock the Process */
ExReleasePushLockShared(&Process->ProcessLock);
KeLeaveCriticalRegion();
/* Handle idle process entry */
Skip:
if (Process == PsIdleProcess) Process = NULL;
Process = PsGetNextProcess(Process);
ThreadsCount = 0;
if ((Process == SystemProcess) || (Process == NULL))
{
if (!Overflow)
SpiCurrent->NextEntryOffset = 0;
break;
}
else
Current += CurrentSize + ImageNameMaximumLength;
} while ((Process != SystemProcess) && (Process != NULL));
if(Process != NULL)
ObDereferenceObject(Process);
Status = STATUS_SUCCESS;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
if(Process != NULL)
ObDereferenceObject(Process);
if (ProcessImageName)
{
/* Release the memory allocated by SeLocateProcessImageName */
ExFreePoolWithTag(ProcessImageName, TAG_SEPA);
}
Status = _SEH2_GetExceptionCode();
}
_SEH2_END
if (Overflow)
Status = STATUS_INFO_LENGTH_MISMATCH;
*ReqSize = TotalSize;
return Status;
}
/* Class 6 - Call Count Information */
QSI_DEF(SystemCallCountInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemCallCountInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 7 - Device Information */
QSI_DEF(SystemDeviceInformation)
{
PSYSTEM_DEVICE_INFORMATION Sdi
= (PSYSTEM_DEVICE_INFORMATION) Buffer;
PCONFIGURATION_INFORMATION ConfigInfo;
*ReqSize = sizeof(SYSTEM_DEVICE_INFORMATION);
/* Check user buffer's size */
if (Size < sizeof(SYSTEM_DEVICE_INFORMATION))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
ConfigInfo = IoGetConfigurationInformation();
Sdi->NumberOfDisks = ConfigInfo->DiskCount;
Sdi->NumberOfFloppies = ConfigInfo->FloppyCount;
Sdi->NumberOfCdRoms = ConfigInfo->CdRomCount;
Sdi->NumberOfTapes = ConfigInfo->TapeCount;
Sdi->NumberOfSerialPorts = ConfigInfo->SerialCount;
Sdi->NumberOfParallelPorts = ConfigInfo->ParallelCount;
return STATUS_SUCCESS;
}
/* Class 8 - Processor Performance Information */
QSI_DEF(SystemProcessorPerformanceInformation)
{
PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION Spi
= (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) Buffer;
LONG i;
ULONG TotalTime;
PKPRCB Prcb;
*ReqSize = KeNumberProcessors * sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
/* Check user buffer's size */
if (Size < *ReqSize)
{
return STATUS_INFO_LENGTH_MISMATCH;
}
for (i = 0; i < KeNumberProcessors; i++)
{
/* Get the PRCB on this processor */
Prcb = KiProcessorBlock[i];
/* Calculate total user and kernel times */
TotalTime = Prcb->IdleThread->KernelTime + Prcb->IdleThread->UserTime;
Spi->IdleTime.QuadPart = UInt32x32To64(TotalTime, KeMaximumIncrement);
Spi->KernelTime.QuadPart = UInt32x32To64(Prcb->KernelTime, KeMaximumIncrement);
Spi->UserTime.QuadPart = UInt32x32To64(Prcb->UserTime, KeMaximumIncrement);
Spi->DpcTime.QuadPart = UInt32x32To64(Prcb->DpcTime, KeMaximumIncrement);
Spi->InterruptTime.QuadPart = UInt32x32To64(Prcb->InterruptTime, KeMaximumIncrement);
Spi->InterruptCount = Prcb->InterruptCount;
Spi++;
}
return STATUS_SUCCESS;
}
/* Class 9 - Flags Information */
QSI_DEF(SystemFlagsInformation)
{
#if (NTDDI_VERSION >= NTDDI_VISTA)
*ReqSize = sizeof(SYSTEM_FLAGS_INFORMATION);
#endif
if (sizeof(SYSTEM_FLAGS_INFORMATION) != Size)
{
return STATUS_INFO_LENGTH_MISMATCH;
}
((PSYSTEM_FLAGS_INFORMATION) Buffer)->Flags = NtGlobalFlag;
#if (NTDDI_VERSION < NTDDI_VISTA)
*ReqSize = sizeof(SYSTEM_FLAGS_INFORMATION);
#endif
return STATUS_SUCCESS;
}
SSI_DEF(SystemFlagsInformation)
{
if (sizeof(SYSTEM_FLAGS_INFORMATION) != Size)
{
return STATUS_INFO_LENGTH_MISMATCH;
}
if (!SeSinglePrivilegeCheck(SeDebugPrivilege, ExGetPreviousMode()))
{
#if (NTDDI_VERSION < NTDDI_WIN7)
return STATUS_ACCESS_VIOLATION;
#else
return STATUS_ACCESS_DENIED;
#endif
}
NtGlobalFlag = ((PSYSTEM_FLAGS_INFORMATION) Buffer)->Flags;
return STATUS_SUCCESS;
}
/* Class 10 - Call Time Information */
QSI_DEF(SystemCallTimeInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemCallTimeInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 11 - Module Information */
QSI_DEF(SystemModuleInformation)
{
NTSTATUS Status;
/* Acquire system module list lock */
KeEnterCriticalRegion();
ExAcquireResourceExclusiveLite(&PsLoadedModuleResource, TRUE);
/* Call the generic handler with the system module list */
Status = ExpQueryModuleInformation(&PsLoadedModuleList,
&MmLoadedUserImageList,
(PRTL_PROCESS_MODULES)Buffer,
Size,
ReqSize);
/* Release list lock and return status */
ExReleaseResourceLite(&PsLoadedModuleResource);
KeLeaveCriticalRegion();
return Status;
}
/* Class 12 - Locks Information */
QSI_DEF(SystemLocksInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemLocksInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 13 - Stack Trace Information */
QSI_DEF(SystemStackTraceInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemStackTraceInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 14 - Paged Pool Information */
QSI_DEF(SystemPagedPoolInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemPagedPoolInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 15 - Non Paged Pool Information */
QSI_DEF(SystemNonPagedPoolInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemNonPagedPoolInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 16 - Handle Information */
QSI_DEF(SystemHandleInformation)
{
PSYSTEM_HANDLE_INFORMATION HandleInformation;
PLIST_ENTRY NextTableEntry;
PHANDLE_TABLE HandleTable;
PHANDLE_TABLE_ENTRY HandleTableEntry;
EXHANDLE Handle;
ULONG Index = 0;
NTSTATUS Status;
PMDL Mdl;
PAGED_CODE();
DPRINT("NtQuerySystemInformation - SystemHandleInformation\n");
/* Set initial required buffer size */
*ReqSize = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION, Handles);
/* Check user's buffer size */
if (Size < *ReqSize)
{
return STATUS_INFO_LENGTH_MISMATCH;
}
/* We need to lock down the memory */
Status = ExLockUserBuffer(Buffer,
Size,
ExGetPreviousMode(),
IoWriteAccess,
(PVOID*)&HandleInformation,
&Mdl);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to lock the user buffer: 0x%lx\n", Status);
return Status;
}
/* Reset of count of handles */
HandleInformation->NumberOfHandles = 0;
/* Enter a critical region */
KeEnterCriticalRegion();
/* Acquire the handle table lock */
ExAcquirePushLockShared(&HandleTableListLock);
/* Enumerate all system handles */
for (NextTableEntry = HandleTableListHead.Flink;
NextTableEntry != &HandleTableListHead;
NextTableEntry = NextTableEntry->Flink)
{
/* Get current handle table */
HandleTable = CONTAINING_RECORD(NextTableEntry, HANDLE_TABLE, HandleTableList);
/* Set the initial value and loop the entries */
Handle.Value = 0;
while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle)))
{
/* Validate the entry */
if ((HandleTableEntry->Object) &&
(HandleTableEntry->NextFreeTableEntry != -2))
{
/* Increase of count of handles */
++HandleInformation->NumberOfHandles;
/* Lock the entry */
if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
{
/* Increase required buffer size */
*ReqSize += sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO);
/* Check user's buffer size */
if (*ReqSize > Size)
{
Status = STATUS_INFO_LENGTH_MISMATCH;
}
else
{
POBJECT_HEADER ObjectHeader = ObpGetHandleObject(HandleTableEntry);
/* Filling handle information */
HandleInformation->Handles[Index].UniqueProcessId =
(USHORT)(ULONG_PTR) HandleTable->UniqueProcessId;
HandleInformation->Handles[Index].CreatorBackTraceIndex = 0;
#if 0 /* FIXME!!! Type field currupted */
HandleInformation->Handles[Index].ObjectTypeIndex =
(UCHAR) ObjectHeader->Type->Index;
#else
HandleInformation->Handles[Index].ObjectTypeIndex = 0;
#endif
HandleInformation->Handles[Index].HandleAttributes =
HandleTableEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
HandleInformation->Handles[Index].HandleValue =
(USHORT)(ULONG_PTR) Handle.GenericHandleOverlay;
HandleInformation->Handles[Index].Object = &ObjectHeader->Body;
HandleInformation->Handles[Index].GrantedAccess =
HandleTableEntry->GrantedAccess;
++Index;
}
/* Unlock it */
ExUnlockHandleTableEntry(HandleTable, HandleTableEntry);
}
}
/* Go to the next entry */
Handle.Value += sizeof(HANDLE);
}
}
/* Release the lock */
ExReleasePushLockShared(&HandleTableListLock);
/* Leave the critical region */
KeLeaveCriticalRegion();
/* Release the locked user buffer */
ExUnlockUserBuffer(Mdl);
return Status;
}
/* Class 17 - Information */
QSI_DEF(SystemObjectInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemObjectInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 18 - Information */
QSI_DEF(SystemPageFileInformation)
{
UNICODE_STRING FileName; /* FIXME */
SYSTEM_PAGEFILE_INFORMATION *Spfi = (SYSTEM_PAGEFILE_INFORMATION *) Buffer;
if (Size < sizeof(SYSTEM_PAGEFILE_INFORMATION))
{
* ReqSize = sizeof(SYSTEM_PAGEFILE_INFORMATION);
return STATUS_INFO_LENGTH_MISMATCH;
}
RtlInitUnicodeString(&FileName, NULL); /* FIXME */
/* FIXME */
Spfi->NextEntryOffset = 0;
Spfi->TotalSize = MiFreeSwapPages + MiUsedSwapPages;
Spfi->TotalInUse = MiUsedSwapPages;
Spfi->PeakUsage = MiUsedSwapPages; /* FIXME */
Spfi->PageFileName = FileName;
return STATUS_SUCCESS;
}
/* Class 19 - Vdm Instemul Information */
QSI_DEF(SystemVdmInstemulInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemVdmInstemulInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 20 - Vdm Bop Information */
QSI_DEF(SystemVdmBopInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemVdmBopInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 21 - File Cache Information */
QSI_DEF(SystemFileCacheInformation)
{
SYSTEM_FILECACHE_INFORMATION *Sci = (SYSTEM_FILECACHE_INFORMATION *) Buffer;
*ReqSize = sizeof(SYSTEM_FILECACHE_INFORMATION);
if (Size < *ReqSize)
{
return STATUS_INFO_LENGTH_MISMATCH;
}
RtlZeroMemory(Sci, sizeof(SYSTEM_FILECACHE_INFORMATION));
/* Return the Byte size not the page size. */
Sci->CurrentSize = MiMemoryConsumers[MC_USER].PagesUsed; /* FIXME */
Sci->PeakSize = MiMemoryConsumers[MC_USER].PagesUsed; /* FIXME */
/* Taskmgr multiplies this one by page size right away */
Sci->CurrentSizeIncludingTransitionInPages = MiMemoryConsumers[MC_USER].PagesUsed; /* FIXME: Should be */
/* system working set and standby pages. */
Sci->PageFaultCount = 0; /* FIXME */
Sci->MinimumWorkingSet = 0; /* FIXME */
Sci->MaximumWorkingSet = 0; /* FIXME */
return STATUS_SUCCESS;
}
SSI_DEF(SystemFileCacheInformation)
{
if (Size < sizeof(SYSTEM_FILECACHE_INFORMATION))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
/* FIXME */
DPRINT1("NtSetSystemInformation - SystemFileCacheInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 22 - Pool Tag Information */
QSI_DEF(SystemPoolTagInformation)
{
if (Size < sizeof(SYSTEM_POOLTAG_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
return ExGetPoolTagInfo(Buffer, Size, ReqSize);
}
/* Class 23 - Interrupt Information for all processors */
QSI_DEF(SystemInterruptInformation)
{
PKPRCB Prcb;
LONG i;
ULONG ti;
PSYSTEM_INTERRUPT_INFORMATION sii = (PSYSTEM_INTERRUPT_INFORMATION)Buffer;
if(Size < KeNumberProcessors * sizeof(SYSTEM_INTERRUPT_INFORMATION))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
ti = KeQueryTimeIncrement();
for (i = 0; i < KeNumberProcessors; i++)
{
Prcb = KiProcessorBlock[i];
sii->ContextSwitches = KeGetContextSwitches(Prcb);
sii->DpcCount = Prcb->DpcData[0].DpcCount;
sii->DpcRate = Prcb->DpcRequestRate;
sii->TimeIncrement = ti;
sii->DpcBypassCount = 0;
sii->ApcBypassCount = 0;
sii++;
}
return STATUS_SUCCESS;
}
/* Class 24 - DPC Behaviour Information */
QSI_DEF(SystemDpcBehaviourInformation)
{
PSYSTEM_DPC_BEHAVIOR_INFORMATION sdbi = (PSYSTEM_DPC_BEHAVIOR_INFORMATION)Buffer;
if (Size < sizeof(SYSTEM_DPC_BEHAVIOR_INFORMATION))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
sdbi->DpcQueueDepth = KiMaximumDpcQueueDepth;
sdbi->MinimumDpcRate = KiMinimumDpcRate;
sdbi->AdjustDpcThreshold = KiAdjustDpcThreshold;
sdbi->IdealDpcRate = KiIdealDpcRate;
return STATUS_SUCCESS;
}
SSI_DEF(SystemDpcBehaviourInformation)
{
/* FIXME */
DPRINT1("NtSetSystemInformation - SystemDpcBehaviourInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 25 - Full Memory Information */
QSI_DEF(SystemFullMemoryInformation)
{
PULONG Spi = (PULONG) Buffer;
PEPROCESS TheIdleProcess;
*ReqSize = sizeof(ULONG);
if (sizeof(ULONG) != Size)
{
return STATUS_INFO_LENGTH_MISMATCH;
}
DPRINT("SystemFullMemoryInformation\n");
TheIdleProcess = PsIdleProcess;
DPRINT("PID: %p, KernelTime: %u PFFree: %lu PFUsed: %lu\n",
TheIdleProcess->UniqueProcessId,
TheIdleProcess->Pcb.KernelTime,
MiFreeSwapPages,
MiUsedSwapPages);
*Spi = MiMemoryConsumers[MC_USER].PagesUsed;
return STATUS_SUCCESS;
}
/* Class 26 - Load Image */
SSI_DEF(SystemLoadGdiDriverInformation)
{
PSYSTEM_GDI_DRIVER_INFORMATION DriverInfo = (PVOID)Buffer;
UNICODE_STRING ImageName;
PVOID ImageBase;
PVOID SectionPointer;
ULONG_PTR EntryPoint;
NTSTATUS Status;
ULONG DirSize;
PIMAGE_NT_HEADERS NtHeader;
/* Validate size */
if (Size != sizeof(SYSTEM_GDI_DRIVER_INFORMATION))
{
/* Incorrect buffer length, fail */
return STATUS_INFO_LENGTH_MISMATCH;
}
/* Only kernel mode can call this function */
if (ExGetPreviousMode() != KernelMode) return STATUS_PRIVILEGE_NOT_HELD;
/* Load the driver */
ImageName = DriverInfo->DriverName;
Status = MmLoadSystemImage(&ImageName,
NULL,
NULL,
0,
&SectionPointer,
&ImageBase);
if (!NT_SUCCESS(Status)) return Status;
/* Return the export pointer */
DriverInfo->ExportSectionPointer =
RtlImageDirectoryEntryToData(ImageBase,
TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&DirSize);
/* Get the entrypoint */
NtHeader = RtlImageNtHeader(ImageBase);
EntryPoint = NtHeader->OptionalHeader.AddressOfEntryPoint;
EntryPoint += (ULONG_PTR)ImageBase;
/* Save other data */
DriverInfo->ImageAddress = ImageBase;
DriverInfo->SectionPointer = SectionPointer;
DriverInfo->EntryPoint = (PVOID)EntryPoint;
DriverInfo->ImageLength = NtHeader->OptionalHeader.SizeOfImage;
/* All is good */
return STATUS_SUCCESS;
}
/* Class 27 - Unload Image */
SSI_DEF(SystemUnloadGdiDriverInformation)
{
PVOID *SectionPointer = Buffer;
/* Validate size */
if (Size != sizeof(PVOID))
{
/* Incorrect length, fail */
return STATUS_INFO_LENGTH_MISMATCH;
}
/* Only kernel mode can call this function */
if (ExGetPreviousMode() != KernelMode) return STATUS_PRIVILEGE_NOT_HELD;
/* Unload the image */
MmUnloadSystemImage(*SectionPointer);
return STATUS_SUCCESS;
}
/* Class 28 - Time Adjustment Information */
QSI_DEF(SystemTimeAdjustmentInformation)
{
PSYSTEM_QUERY_TIME_ADJUST_INFORMATION TimeInfo =
(PSYSTEM_QUERY_TIME_ADJUST_INFORMATION)Buffer;
/* Check if enough storage was provided */
if (sizeof(SYSTEM_QUERY_TIME_ADJUST_INFORMATION) > Size)
{
* ReqSize = sizeof(SYSTEM_QUERY_TIME_ADJUST_INFORMATION);
return STATUS_INFO_LENGTH_MISMATCH;
}
/* Give time values to our caller */
TimeInfo->TimeIncrement = KeMaximumIncrement;
TimeInfo->TimeAdjustment = KeTimeAdjustment;
TimeInfo->Enable = !KiTimeAdjustmentEnabled;
return STATUS_SUCCESS;
}
SSI_DEF(SystemTimeAdjustmentInformation)
{
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
PSYSTEM_SET_TIME_ADJUST_INFORMATION TimeInfo =
(PSYSTEM_SET_TIME_ADJUST_INFORMATION)Buffer;
/* Check size of a buffer, it must match our expectations */
if (sizeof(SYSTEM_SET_TIME_ADJUST_INFORMATION) != Size)
return STATUS_INFO_LENGTH_MISMATCH;
/* Check who is calling */
if (PreviousMode != KernelMode)
{
/* Check access rights */
if (!SeSinglePrivilegeCheck(SeSystemtimePrivilege, PreviousMode))
{
return STATUS_PRIVILEGE_NOT_HELD;
}
}
/* FIXME: behaviour suggests the member be named 'Disable' */
if (TimeInfo->Enable)
{
/* Disable time adjustment and set default value */
KiTimeAdjustmentEnabled = FALSE;
KeTimeAdjustment = KeMaximumIncrement;
}
else
{
/* Check if a valid time adjustment value is given */
if (TimeInfo->TimeAdjustment == 0) return STATUS_INVALID_PARAMETER_2;
/* Enable time adjustment and set the adjustment value */
KiTimeAdjustmentEnabled = TRUE;
KeTimeAdjustment = TimeInfo->TimeAdjustment;
}
return STATUS_SUCCESS;
}
/* Class 29 - Summary Memory Information */
QSI_DEF(SystemSummaryMemoryInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemSummaryMemoryInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 30 - Next Event Id Information */
QSI_DEF(SystemNextEventIdInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemNextEventIdInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 31 */
QSI_DEF(SystemPerformanceTraceInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemPerformanceTraceInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 32 - Crash Dump Information */
QSI_DEF(SystemCrashDumpInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemCrashDumpInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 33 - Exception Information */
QSI_DEF(SystemExceptionInformation)
{
PSYSTEM_EXCEPTION_INFORMATION ExceptionInformation =
(PSYSTEM_EXCEPTION_INFORMATION)Buffer;
PKPRCB Prcb;
ULONG AlignmentFixupCount = 0, ExceptionDispatchCount = 0;
ULONG FloatingEmulationCount = 0, ByteWordEmulationCount = 0;
CHAR i;
/* Check size of a buffer, it must match our expectations */
if (sizeof(SYSTEM_EXCEPTION_INFORMATION) != Size)
return STATUS_INFO_LENGTH_MISMATCH;
/* Sum up exception count information from all processors */
for (i = 0; i < KeNumberProcessors; i++)
{
Prcb = KiProcessorBlock[i];
if (Prcb)
{
AlignmentFixupCount += Prcb->KeAlignmentFixupCount;
ExceptionDispatchCount += Prcb->KeExceptionDispatchCount;
#ifndef _M_ARM
FloatingEmulationCount += Prcb->KeFloatingEmulationCount;
#endif // _M_ARM
}
}
/* Save information in user's buffer */
ExceptionInformation->AlignmentFixupCount = AlignmentFixupCount;
ExceptionInformation->ExceptionDispatchCount = ExceptionDispatchCount;
ExceptionInformation->FloatingEmulationCount = FloatingEmulationCount;
ExceptionInformation->ByteWordEmulationCount = ByteWordEmulationCount;
return STATUS_SUCCESS;
}
/* Class 34 - Crash Dump State Information */
QSI_DEF(SystemCrashDumpStateInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemCrashDumpStateInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 35 - Kernel Debugger Information */
QSI_DEF(SystemKernelDebuggerInformation)
{
PSYSTEM_KERNEL_DEBUGGER_INFORMATION skdi = (PSYSTEM_KERNEL_DEBUGGER_INFORMATION) Buffer;
#if (NTDDI_VERSION >= NTDDI_VISTA)
*ReqSize = sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION);
#endif
if (Size < sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
skdi->KernelDebuggerEnabled = KD_DEBUGGER_ENABLED;
skdi->KernelDebuggerNotPresent = KD_DEBUGGER_NOT_PRESENT;
#if (NTDDI_VERSION < NTDDI_VISTA)
*ReqSize = sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION);
#endif
return STATUS_SUCCESS;
}
/* Class 36 - Context Switch Information */
QSI_DEF(SystemContextSwitchInformation)
{
PSYSTEM_CONTEXT_SWITCH_INFORMATION ContextSwitchInformation =
(PSYSTEM_CONTEXT_SWITCH_INFORMATION)Buffer;
ULONG ContextSwitches;
PKPRCB Prcb;
CHAR i;
/* Check size of a buffer, it must match our expectations */
if (sizeof(SYSTEM_CONTEXT_SWITCH_INFORMATION) != Size)
return STATUS_INFO_LENGTH_MISMATCH;
/* Calculate total value of context switches across all processors */
ContextSwitches = 0;
for (i = 0; i < KeNumberProcessors; i ++)
{
Prcb = KiProcessorBlock[i];
if (Prcb)
{
ContextSwitches += KeGetContextSwitches(Prcb);
}
}
ContextSwitchInformation->ContextSwitches = ContextSwitches;
/* FIXME */
ContextSwitchInformation->FindAny = 0;
ContextSwitchInformation->FindLast = 0;
ContextSwitchInformation->FindIdeal = 0;
ContextSwitchInformation->IdleAny = 0;
ContextSwitchInformation->IdleCurrent = 0;
ContextSwitchInformation->IdleLast = 0;
ContextSwitchInformation->IdleIdeal = 0;
ContextSwitchInformation->PreemptAny = 0;
ContextSwitchInformation->PreemptCurrent = 0;
ContextSwitchInformation->PreemptLast = 0;
ContextSwitchInformation->SwitchToIdle = 0;
return STATUS_SUCCESS;
}
/* Class 37 - Registry Quota Information */
QSI_DEF(SystemRegistryQuotaInformation)
{
PSYSTEM_REGISTRY_QUOTA_INFORMATION srqi = (PSYSTEM_REGISTRY_QUOTA_INFORMATION) Buffer;
*ReqSize = sizeof(SYSTEM_REGISTRY_QUOTA_INFORMATION);
if (Size < sizeof(SYSTEM_REGISTRY_QUOTA_INFORMATION))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
DPRINT1("Faking max registry size of 32 MB\n");
srqi->RegistryQuotaAllowed = 0x2000000;
srqi->RegistryQuotaUsed = 0x200000;
srqi->PagedPoolSize = 0x200000;
return STATUS_SUCCESS;
}
SSI_DEF(SystemRegistryQuotaInformation)
{
/* FIXME */
DPRINT1("NtSetSystemInformation - SystemRegistryQuotaInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 38 - Load And Call Image */
SSI_DEF(SystemExtendServiceTableInformation)
{
UNICODE_STRING ImageName;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
PLDR_DATA_TABLE_ENTRY ModuleObject;
NTSTATUS Status;
PIMAGE_NT_HEADERS NtHeader;
DRIVER_OBJECT Win32k;
PDRIVER_INITIALIZE DriverInit;
PVOID ImageBase;
ULONG_PTR EntryPoint;
/* Validate the size */
if (Size != sizeof(UNICODE_STRING)) return STATUS_INFO_LENGTH_MISMATCH;
/* Check who is calling */
if (PreviousMode != KernelMode)
{
static const UNICODE_STRING Win32kName =
RTL_CONSTANT_STRING(L"\\SystemRoot\\System32\\win32k.sys");
/* Make sure we can load drivers */
if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, UserMode))
{
/* FIXME: We can't, fail */
return STATUS_PRIVILEGE_NOT_HELD;
}
_SEH2_TRY
{
/* Probe and copy the unicode string */
ProbeForRead(Buffer, sizeof(ImageName), 1);
ImageName = *(PUNICODE_STRING)Buffer;
/* Probe the string buffer */
ProbeForRead(ImageName.Buffer, ImageName.Length, sizeof(WCHAR));
/* Check if we have the correct name (nothing else is allowed!) */
if (!RtlEqualUnicodeString(&ImageName, &Win32kName, FALSE))
{
_SEH2_YIELD(return STATUS_PRIVILEGE_NOT_HELD);
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
/* Recursively call the function, so that we are from kernel mode */
return ZwSetSystemInformation(SystemExtendServiceTableInformation,
(PVOID)&Win32kName,
sizeof(Win32kName));
}
/* Load the image */
Status = MmLoadSystemImage((PUNICODE_STRING)Buffer,
NULL,
NULL,
0,
(PVOID)&ModuleObject,
&ImageBase);
if (!NT_SUCCESS(Status)) return Status;
/* Get the headers */
NtHeader = RtlImageNtHeader(ImageBase);
if (!NtHeader)
{
/* Fail */
MmUnloadSystemImage(ModuleObject);
return STATUS_INVALID_IMAGE_FORMAT;
}
/* Get the entrypoint */
EntryPoint = NtHeader->OptionalHeader.AddressOfEntryPoint;
EntryPoint += (ULONG_PTR)ImageBase;
DriverInit = (PDRIVER_INITIALIZE)EntryPoint;
/* Create a dummy device */
RtlZeroMemory(&Win32k, sizeof(Win32k));
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
Win32k.DriverStart = ImageBase;
/* Call it */
Status = (DriverInit)(&Win32k, NULL);
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
/* Unload if we failed */
if (!NT_SUCCESS(Status)) MmUnloadSystemImage(ModuleObject);
return Status;
}
/* Class 39 - Priority Separation */
SSI_DEF(SystemPrioritySeperation)
{
/* Check if the size is correct */
if (Size != sizeof(ULONG))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
/* We need the TCB privilege */
if (!SeSinglePrivilegeCheck(SeTcbPrivilege, ExGetPreviousMode()))
{
return STATUS_PRIVILEGE_NOT_HELD;
}
/* Modify the quantum table */
PsChangeQuantumTable(TRUE, *(PULONG)Buffer);
return STATUS_SUCCESS;
}
/* Class 40 */
QSI_DEF(SystemVerifierAddDriverInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemVerifierAddDriverInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 41 */
QSI_DEF(SystemVerifierRemoveDriverInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemVerifierRemoveDriverInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 42 - Power Information */
QSI_DEF(SystemProcessorIdleInformation)
{
*ReqSize = sizeof(PROCESSOR_POWER_INFORMATION) * KeNumberProcessors;
if (sizeof(PROCESSOR_POWER_INFORMATION) * KeNumberProcessors > Size)
{
return STATUS_INFO_LENGTH_MISMATCH;
}
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemPowerInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 43 */
QSI_DEF(SystemLegacyDriverInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemLegacyDriverInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 44 - Current Time Zone Information */
QSI_DEF(SystemCurrentTimeZoneInformation)
{
*ReqSize = sizeof(RTL_TIME_ZONE_INFORMATION);
if (sizeof(RTL_TIME_ZONE_INFORMATION) != Size)
{
return STATUS_INFO_LENGTH_MISMATCH;
}
/* Copy the time zone information struct */
memcpy(Buffer,
&ExpTimeZoneInfo,
sizeof(RTL_TIME_ZONE_INFORMATION));
return STATUS_SUCCESS;
}
SSI_DEF(SystemCurrentTimeZoneInformation)
{
/* Check user buffer's size */
if (Size < sizeof(RTL_TIME_ZONE_INFORMATION))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
return ExpSetTimeZoneInformation((PRTL_TIME_ZONE_INFORMATION)Buffer);
}
static
VOID
ExpCopyLookasideInformation(
PSYSTEM_LOOKASIDE_INFORMATION *InfoPointer,
PULONG RemainingPointer,
PLIST_ENTRY ListHead,
BOOLEAN ListUsesMisses)
{
PSYSTEM_LOOKASIDE_INFORMATION Info;
PGENERAL_LOOKASIDE LookasideList;
PLIST_ENTRY ListEntry;
ULONG Remaining;
/* Get info pointer and remaining count of free array element */
Info = *InfoPointer;
Remaining = *RemainingPointer;
/* Loop as long as we have lookaside lists and free array elements */
for (ListEntry = ListHead->Flink;
(ListEntry != ListHead) && (Remaining > 0);
ListEntry = ListEntry->Flink, Remaining--)
{
LookasideList = CONTAINING_RECORD(ListEntry, GENERAL_LOOKASIDE, ListEntry);
/* Fill the next array element */
Info->CurrentDepth = LookasideList->Depth;
Info->MaximumDepth = LookasideList->MaximumDepth;
Info->TotalAllocates = LookasideList->TotalAllocates;
Info->TotalFrees = LookasideList->TotalFrees;
Info->Type = LookasideList->Type;
Info->Tag = LookasideList->Tag;
Info->Size = LookasideList->Size;
/* Check how the lists track misses/hits */
if (ListUsesMisses)
{
/* Copy misses */
Info->AllocateMisses = LookasideList->AllocateMisses;
Info->FreeMisses = LookasideList->FreeMisses;
}
else
{
/* Calculate misses */
Info->AllocateMisses = LookasideList->TotalAllocates
- LookasideList->AllocateHits;
Info->FreeMisses = LookasideList->TotalFrees
- LookasideList->FreeHits;
}
}
/* Return the updated pointer and remaining count */
*InfoPointer = Info;
*RemainingPointer = Remaining;
}
/* Class 45 - Lookaside Information */
QSI_DEF(SystemLookasideInformation)
{
KPROCESSOR_MODE PreviousMode;
PSYSTEM_LOOKASIDE_INFORMATION Info;
PMDL Mdl;
ULONG MaxCount, Remaining;
KIRQL OldIrql;
NTSTATUS Status;
/* First we need to lock down the memory, since we are going to access it
at high IRQL */
PreviousMode = ExGetPreviousMode();
Status = ExLockUserBuffer(Buffer,
Size,
PreviousMode,
IoWriteAccess,
(PVOID*)&Info,
&Mdl);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to lock the user buffer: 0x%lx\n", Status);
return Status;
}
/* Calculate how many items we can store */
Remaining = MaxCount = Size / sizeof(SYSTEM_LOOKASIDE_INFORMATION);
if (Remaining == 0)
{
goto Leave;
}
/* Copy info from pool lookaside lists */
ExpCopyLookasideInformation(&Info,
&Remaining,
&ExPoolLookasideListHead,
FALSE);
if (Remaining == 0)
{
goto Leave;
}
/* Copy info from system lookaside lists */
ExpCopyLookasideInformation(&Info,
&Remaining,
&ExSystemLookasideListHead,
TRUE);
if (Remaining == 0)
{
goto Leave;
}
/* Acquire spinlock for ExpNonPagedLookasideListHead */
KeAcquireSpinLock(&ExpNonPagedLookasideListLock, &OldIrql);
/* Copy info from non-paged lookaside lists */
ExpCopyLookasideInformation(&Info,
&Remaining,
&ExpNonPagedLookasideListHead,
TRUE);
/* Release spinlock for ExpNonPagedLookasideListHead */
KeReleaseSpinLock(&ExpNonPagedLookasideListLock, OldIrql);
if (Remaining == 0)
{
goto Leave;
}
/* Acquire spinlock for ExpPagedLookasideListHead */
KeAcquireSpinLock(&ExpPagedLookasideListLock, &OldIrql);
/* Copy info from paged lookaside lists */
ExpCopyLookasideInformation(&Info,
&Remaining,
&ExpPagedLookasideListHead,
TRUE);
/* Release spinlock for ExpPagedLookasideListHead */
KeReleaseSpinLock(&ExpPagedLookasideListLock, OldIrql);
Leave:
/* Release the locked user buffer */
ExUnlockUserBuffer(Mdl);
/* Return the size of the actually written data */
*ReqSize = (MaxCount - Remaining) * sizeof(SYSTEM_LOOKASIDE_INFORMATION);
return STATUS_SUCCESS;
}
/* Class 46 - Set time slip event */
SSI_DEF(SystemTimeSlipNotification)
{
/* FIXME */
DPRINT1("NtSetSystemInformation - SystemTimeSlipNotification not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
MmSessionCreate(OUT PULONG SessionId);
NTSTATUS
NTAPI
MmSessionDelete(IN ULONG SessionId);
/* Class 47 - Create a new session (TSE) */
SSI_DEF(SystemSessionCreate)
{
ULONG SessionId;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
NTSTATUS Status;
if (Size != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
if (PreviousMode != KernelMode)
{
if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
{
return STATUS_PRIVILEGE_NOT_HELD;
}
ProbeForWriteUlong(Buffer);
}
Status = MmSessionCreate(&SessionId);
if (NT_SUCCESS(Status)) *(PULONG)Buffer = SessionId;
return Status;
}
/* Class 48 - Delete an existing session (TSE) */
SSI_DEF(SystemSessionDetach)
{
ULONG SessionId;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
if (Size != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
if (PreviousMode != KernelMode)
{
if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
{
return STATUS_PRIVILEGE_NOT_HELD;
}
}
SessionId = *(PULONG)Buffer;
return MmSessionDelete(SessionId);
}
/* Class 49 - UNKNOWN */
QSI_DEF(SystemSessionInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemSessionInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 50 - System range start address */
QSI_DEF(SystemRangeStartInformation)
{
/* Check user buffer's size */
if (Size != sizeof(ULONG_PTR)) return STATUS_INFO_LENGTH_MISMATCH;
*(PULONG_PTR)Buffer = (ULONG_PTR)MmSystemRangeStart;
if (ReqSize) *ReqSize = sizeof(ULONG_PTR);
return STATUS_SUCCESS;
}
/* Class 51 - Driver verifier information */
QSI_DEF(SystemVerifierInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemVerifierInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
SSI_DEF(SystemVerifierInformation)
{
/* FIXME */
DPRINT1("NtSetSystemInformation - SystemVerifierInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 52 */
SSI_DEF(SystemVerifierThunkExtend)
{
/* FIXME */
DPRINT1("NtSetSystemInformation - SystemVerifierThunkExtend not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 53 - A session's processes */
QSI_DEF(SystemSessionProcessesInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemSessionProcessInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 54 - Load & map in system space */
SSI_DEF(SystemLoadGdiDriverInSystemSpaceInformation)
{
/* FIXME */
DPRINT1("NtSetSystemInformation - SystemLoadGdiDriverInSystemSpaceInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 55 - NUMA processor information */
QSI_DEF(SystemNumaProcessorMap)
{
ULONG MaxEntries, Node;
PSYSTEM_NUMA_INFORMATION NumaInformation = (PSYSTEM_NUMA_INFORMATION)Buffer;
/* Validate input size */
if (Size < sizeof(ULONG))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
/* Return highest node */
NumaInformation->HighestNodeNumber = KeNumberNodes - 1;
/* Compute how much entries we will be able to put in output structure */
MaxEntries = (Size - FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, ActiveProcessorsAffinityMask)) / sizeof(ULONGLONG);
/* Make sure we don't overflow KeNodeBlock */
if (MaxEntries > KeNumberNodes)
{
MaxEntries = KeNumberNodes;
}
/* If we have entries to write, and room for it */
if (Size >= FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, ActiveProcessorsAffinityMask) &&
MaxEntries != 0)
{
/* Already set size we return */
*ReqSize = FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, ActiveProcessorsAffinityMask) +
MaxEntries * sizeof(ULONGLONG);
/* For each node, return processor mask */
for (Node = 0; Node < MaxEntries; ++Node)
{
NumaInformation->ActiveProcessorsAffinityMask[Node] = KeNodeBlock[Node]->ProcessorMask;
}
}
else
{
/* We only returned highest node number */
*ReqSize = sizeof(ULONG);
}
return STATUS_SUCCESS;
}
/* Class 56 - Prefetcher information */
QSI_DEF(SystemPrefetcherInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemPrefetcherInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 57 - Extended process information */
QSI_DEF(SystemExtendedProcessInformation)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemExtendedProcessInformation not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 58 - Recommended shared data alignment */
QSI_DEF(SystemRecommendedSharedDataAlignment)
{
/* FIXME */
DPRINT1("NtQuerySystemInformation - SystemRecommendedSharedDataAlignment not implemented\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Class 60 - NUMA memory information */
QSI_DEF(SystemNumaAvailableMemory)
{
ULONG MaxEntries, Node;
PSYSTEM_NUMA_INFORMATION NumaInformation = (PSYSTEM_NUMA_INFORMATION)Buffer;
/* Validate input size */
if (Size < sizeof(ULONG))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
/* Return highest node */
NumaInformation->HighestNodeNumber = KeNumberNodes - 1;
/* Compute how much entries we will be able to put in output structure */
MaxEntries = (Size - FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, AvailableMemory)) / sizeof(ULONGLONG);
/* Make sure we don't overflow KeNodeBlock */
if (MaxEntries > KeNumberNodes)
{
MaxEntries = KeNumberNodes;
}
/* If we have entries to write, and room for it */
if (Size >= FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, AvailableMemory) &&
MaxEntries != 0)
{
/* Already set size we return */
*ReqSize = FIELD_OFFSET(SYSTEM_NUMA_INFORMATION, AvailableMemory) +
MaxEntries * sizeof(ULONGLONG);
/* If we have a single entry (us), directly return MM information */
if (MaxEntries == 1)
{
NumaInformation->AvailableMemory[0] = MmAvailablePages << PAGE_SHIFT;
}
else
{
/* Otherwise, for each node, return available bytes */
for (Node = 0; Node < MaxEntries; ++Node)
{
NumaInformation->AvailableMemory[Node] = (KeNodeBlock[Node]->FreeCount[0] + KeNodeBlock[Node]->FreeCount[1]) << PAGE_SHIFT;
}
}
}
else
{
/* We only returned highest node number */
*ReqSize = sizeof(ULONG);
}
return STATUS_SUCCESS;
}
/* Class 64 - Extended handle information */
QSI_DEF(SystemExtendedHandleInformation)
{
PSYSTEM_HANDLE_INFORMATION_EX HandleInformation;
PLIST_ENTRY NextTableEntry;
PHANDLE_TABLE HandleTable;
PHANDLE_TABLE_ENTRY HandleTableEntry;
EXHANDLE Handle;
ULONG Index = 0;
NTSTATUS Status;
PMDL Mdl;
PAGED_CODE();
DPRINT("NtQuerySystemInformation - SystemExtendedHandleInformation\n");
/* Set initial required buffer size */
*ReqSize = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handle);
/* Check user's buffer size */
if (Size < *ReqSize)
{
return STATUS_INFO_LENGTH_MISMATCH;
}
/* We need to lock down the memory */
Status = ExLockUserBuffer(Buffer,
Size,
ExGetPreviousMode(),
IoWriteAccess,
(PVOID*)&HandleInformation,
&Mdl);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to lock the user buffer: 0x%lx\n", Status);
return Status;
}
/* Reset of count of handles */
HandleInformation->Count = 0;
/* Enter a critical region */
KeEnterCriticalRegion();
/* Acquire the handle table lock */
ExAcquirePushLockShared(&HandleTableListLock);
/* Enumerate all system handles */
for (NextTableEntry = HandleTableListHead.Flink;
NextTableEntry != &HandleTableListHead;
NextTableEntry = NextTableEntry->Flink)
{
/* Get current handle table */
HandleTable = CONTAINING_RECORD(NextTableEntry, HANDLE_TABLE, HandleTableList);
/* Set the initial value and loop the entries */
Handle.Value = 0;
while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle)))
{
/* Validate the entry */
if ((HandleTableEntry->Object) &&
(HandleTableEntry->NextFreeTableEntry != -2))
{
/* Increase of count of handles */
++HandleInformation->Count;
/* Lock the entry */
if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
{
/* Increase required buffer size */
*ReqSize += sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX);
/* Check user's buffer size */
if (*ReqSize > Size)
{
Status = STATUS_INFO_LENGTH_MISMATCH;
}
else
{
POBJECT_HEADER ObjectHeader = ObpGetHandleObject(HandleTableEntry);
/* Filling handle information */
HandleInformation->Handle[Index].UniqueProcessId =
(USHORT)(ULONG_PTR) HandleTable->UniqueProcessId;
HandleInformation->Handle[Index].CreatorBackTraceIndex = 0;
#if 0 /* FIXME!!! Type field currupted */
HandleInformation->Handles[Index].ObjectTypeIndex =
(UCHAR) ObjectHeader->Type->Index;
#else
HandleInformation->Handle[Index].ObjectTypeIndex = 0;
#endif
HandleInformation->Handle[Index].HandleAttributes =
HandleTableEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
HandleInformation->Handle[Index].HandleValue =
(USHORT)(ULONG_PTR) Handle.GenericHandleOverlay;
HandleInformation->Handle[Index].Object = &ObjectHeader->Body;
HandleInformation->Handle[Index].GrantedAccess =
HandleTableEntry->GrantedAccess;
HandleInformation->Handle[Index].Reserved = 0;
++Index;
}
/* Unlock it */
ExUnlockHandleTableEntry(HandleTable, HandleTableEntry);
}
}
/* Go to the next entry */
Handle.Value += sizeof(HANDLE);
}
}
/* Release the lock */
ExReleasePushLockShared(&HandleTableListLock);
/* Leave the critical region */
KeLeaveCriticalRegion();
/* Release the locked user buffer */
ExUnlockUserBuffer(Mdl);
return Status;
}
/* Class 70 - System object security mode information */
QSI_DEF(SystemObjectSecurityMode)
{
PULONG ObjectSecurityInfo = (PULONG)Buffer;
/* Validate input size */
if (Size != sizeof(ULONG))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
*ObjectSecurityInfo = ObpObjectSecurityMode;
return STATUS_SUCCESS;
}
/* Class 73 - Logical processor information */
QSI_DEF(SystemLogicalProcessorInformation)
{
LONG i;
PKPRCB Prcb;
KAFFINITY CurrentProc;
NTSTATUS Status = STATUS_SUCCESS;
ULONG DataSize = 0, ProcessorFlags;
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION CurrentInfo;
/* First, browse active processors, thanks to the map */
i = 0;
CurrentInfo = Buffer;
CurrentProc = KeActiveProcessors;
do
{
/* If current processor is active and is main in case of HT/MC, return it */
Prcb = KiProcessorBlock[i];
if ((CurrentProc & 1) &&
Prcb == Prcb->MultiThreadSetMaster)
{
/* Assume processor can do HT or multicore */
ProcessorFlags = 1;
/* If set is the same for PRCB and multithread, then
* actually, the processor is single core
*/
if (Prcb->SetMember == Prcb->MultiThreadProcessorSet)
{
ProcessorFlags = 0;
}
/* Check we have enough room to return */
DataSize += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
if (DataSize > Size)
{
Status = STATUS_INFO_LENGTH_MISMATCH;
}
else
{
/* Zero output and return */
RtlZeroMemory(CurrentInfo, sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
CurrentInfo->ProcessorMask = Prcb->MultiThreadProcessorSet;
/* Processor core needs 1 if HT/MC is supported */
CurrentInfo->Relationship = RelationProcessorCore;
CurrentInfo->ProcessorCore.Flags = ProcessorFlags;
++CurrentInfo;
}
}
/* Move to the next proc */
CurrentProc >>= 1;
++i;
/* Loop while there's someone in the bitmask */
} while (CurrentProc != 0);
/* Now, return the NUMA nodes */
for (i = 0; i < KeNumberNodes; ++i)
{
/* Check we have enough room to return */
DataSize += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
if (DataSize > Size)
{
Status = STATUS_INFO_LENGTH_MISMATCH;
}
else
{
/* Zero output and return */
RtlZeroMemory(CurrentInfo, sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
CurrentInfo->ProcessorMask = KeActiveProcessors;
/* NUMA node needs its ID */
CurrentInfo->Relationship = RelationNumaNode;
CurrentInfo->NumaNode.NodeNumber = i;
++CurrentInfo;
}
}
*ReqSize = DataSize;
return Status;
}
/* Class 76 - System firmware table information */
QSI_DEF(SystemFirmwareTableInformation)
{
PSYSTEM_FIRMWARE_TABLE_INFORMATION SysFirmwareInfo = (PSYSTEM_FIRMWARE_TABLE_INFORMATION)Buffer;
NTSTATUS Status = STATUS_SUCCESS;
ULONG InputBufSize;
ULONG DataSize = 0;
ULONG TableCount = 0;
DPRINT("NtQuerySystemInformation - SystemFirmwareTableInformation\n");
/* Set initial required buffer size */
*ReqSize = FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
/* Check user's buffer size */
if (Size < *ReqSize)
{
return STATUS_INFO_LENGTH_MISMATCH;
}
InputBufSize = SysFirmwareInfo->TableBufferLength;
switch (SysFirmwareInfo->ProviderSignature)
{
/*
* ExpFirmwareTableResource and ExpFirmwareTableProviderListHead
* variables should be used there somehow...
*/
case SIG_ACPI:
{
/* FIXME: Not implemented yet */
DPRINT1("ACPI provider not implemented\n");
Status = STATUS_NOT_IMPLEMENTED;
break;
}
case SIG_FIRM:
{
/* FIXME: Not implemented yet */
DPRINT1("FIRM provider not implemented\n");
Status = STATUS_NOT_IMPLEMENTED;
break;
}
case SIG_RSMB:
{
Status = ExpGetRawSMBiosTable(NULL, &DataSize, 0);
if (DataSize > 0)
{
TableCount = 1;
if (SysFirmwareInfo->Action == SystemFirmwareTable_Enumerate)
{
DataSize = TableCount * sizeof(ULONG);
if (DataSize <= InputBufSize)
{
*(ULONG *)SysFirmwareInfo->TableBuffer = 0;
}
}
else if (SysFirmwareInfo->Action == SystemFirmwareTable_Get
&& DataSize <= InputBufSize)
{
Status = ExpGetRawSMBiosTable(SysFirmwareInfo->TableBuffer, &DataSize, InputBufSize);
}
SysFirmwareInfo->TableBufferLength = DataSize;
}
break;
}
default:
{
DPRINT1("SystemFirmwareTableInformation: Unsupported provider (0x%x)\n",
SysFirmwareInfo->ProviderSignature);
Status = STATUS_ILLEGAL_FUNCTION;
}
}
if (NT_SUCCESS(Status))
{
switch (SysFirmwareInfo->Action)
{
case SystemFirmwareTable_Enumerate:
case SystemFirmwareTable_Get:
{
if (SysFirmwareInfo->TableBufferLength > InputBufSize)
{
Status = STATUS_BUFFER_TOO_SMALL;
}
break;
}
default:
{
DPRINT1("SystemFirmwareTableInformation: Unsupported action (0x%x)\n",
SysFirmwareInfo->Action);
Status = STATUS_ILLEGAL_FUNCTION;
}
}
}
else
{
SysFirmwareInfo->TableBufferLength = 0;
}
return Status;
}
/* Query/Set Calls Table */
typedef
struct _QSSI_CALLS
{
NTSTATUS (* Query) (PVOID,ULONG,PULONG);
NTSTATUS (* Set) (PVOID,ULONG);
} QSSI_CALLS;
// QS Query & Set
// QX Query
// XS Set
// XX unknown behaviour
//
#define SI_QS(n) {QSI_USE(n),SSI_USE(n)}
#define SI_QX(n) {QSI_USE(n),NULL}
#define SI_XS(n) {NULL,SSI_USE(n)}
#define SI_XX(n) {NULL,NULL}
static
QSSI_CALLS
CallQS[] =
{
SI_QX(SystemBasicInformation),
SI_QX(SystemProcessorInformation),
SI_QX(SystemPerformanceInformation),
SI_QX(SystemTimeOfDayInformation),
SI_QX(SystemPathInformation),
SI_QX(SystemProcessInformation),
SI_QX(SystemCallCountInformation),
SI_QX(SystemDeviceInformation),
SI_QX(SystemProcessorPerformanceInformation),
SI_QS(SystemFlagsInformation),
SI_QX(SystemCallTimeInformation), /* should be SI_XX */
SI_QX(SystemModuleInformation),
SI_QX(SystemLocksInformation),
SI_QX(SystemStackTraceInformation), /* should be SI_XX */
SI_QX(SystemPagedPoolInformation), /* should be SI_XX */
SI_QX(SystemNonPagedPoolInformation), /* should be SI_XX */
SI_QX(SystemHandleInformation),
SI_QX(SystemObjectInformation),
SI_QX(SystemPageFileInformation),
SI_QX(SystemVdmInstemulInformation),
SI_QX(SystemVdmBopInformation), /* it should be SI_XX */
SI_QS(SystemFileCacheInformation),
SI_QX(SystemPoolTagInformation),
SI_QX(SystemInterruptInformation),
SI_QS(SystemDpcBehaviourInformation),
SI_QX(SystemFullMemoryInformation), /* it should be SI_XX */
SI_XS(SystemLoadGdiDriverInformation),
SI_XS(SystemUnloadGdiDriverInformation),
SI_QS(SystemTimeAdjustmentInformation),
SI_QX(SystemSummaryMemoryInformation), /* it should be SI_XX */
SI_QX(SystemNextEventIdInformation), /* it should be SI_XX */
SI_QX(SystemPerformanceTraceInformation), /* it should be SI_XX */
SI_QX(SystemCrashDumpInformation),
SI_QX(SystemExceptionInformation),
SI_QX(SystemCrashDumpStateInformation),
SI_QX(SystemKernelDebuggerInformation),
SI_QX(SystemContextSwitchInformation),
SI_QS(SystemRegistryQuotaInformation),
SI_XS(SystemExtendServiceTableInformation),
SI_XS(SystemPrioritySeperation),
SI_QX(SystemVerifierAddDriverInformation), /* it should be SI_XX */
SI_QX(SystemVerifierRemoveDriverInformation), /* it should be SI_XX */
SI_QX(SystemProcessorIdleInformation), /* it should be SI_XX */
SI_QX(SystemLegacyDriverInformation), /* it should be SI_XX */
SI_QS(SystemCurrentTimeZoneInformation), /* it should be SI_QX */
SI_QX(SystemLookasideInformation),
SI_XS(SystemTimeSlipNotification),
SI_XS(SystemSessionCreate),
SI_XS(SystemSessionDetach),
SI_QX(SystemSessionInformation), /* it should be SI_XX */
SI_QX(SystemRangeStartInformation),
SI_QS(SystemVerifierInformation),
SI_XS(SystemVerifierThunkExtend),
SI_QX(SystemSessionProcessesInformation),
SI_XS(SystemLoadGdiDriverInSystemSpaceInformation),
SI_QX(SystemNumaProcessorMap),
SI_QX(SystemPrefetcherInformation),
SI_QX(SystemExtendedProcessInformation),
SI_QX(SystemRecommendedSharedDataAlignment),
SI_XX(SystemComPlusPackage),
SI_QX(SystemNumaAvailableMemory),
SI_XX(SystemProcessorPowerInformation), /* FIXME: not implemented */
SI_XX(SystemEmulationBasicInformation), /* FIXME: not implemented */
SI_XX(SystemEmulationProcessorInformation), /* FIXME: not implemented */
SI_QX(SystemExtendedHandleInformation),
SI_XX(SystemLostDelayedWriteInformation), /* FIXME: not implemented */
SI_XX(SystemBigPoolInformation), /* FIXME: not implemented */
SI_XX(SystemSessionPoolTagInformation), /* FIXME: not implemented */
SI_XX(SystemSessionMappedViewInformation), /* FIXME: not implemented */
SI_XX(SystemHotpatchInformation), /* FIXME: not implemented */
SI_QX(SystemObjectSecurityMode),
SI_XX(SystemWatchdogTimerHandler), /* FIXME: not implemented */
SI_XX(SystemWatchdogTimerInformation), /* FIXME: not implemented */
SI_QX(SystemLogicalProcessorInformation),
SI_XX(SystemWow64SharedInformation), /* FIXME: not implemented */
SI_XX(SystemRegisterFirmwareTableInformationHandler), /* FIXME: not implemented */
SI_QX(SystemFirmwareTableInformation),
};
C_ASSERT(SystemBasicInformation == 0);
#define MIN_SYSTEM_INFO_CLASS (SystemBasicInformation)
#define MAX_SYSTEM_INFO_CLASS RTL_NUMBER_OF(CallQS)
/*
* @implemented
*/
__kernel_entry
NTSTATUS
NTAPI
NtQuerySystemInformation(
_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
_Out_writes_bytes_to_opt_(SystemInformationLength, *ReturnLength) PVOID SystemInformation,
_In_ ULONG SystemInformationLength,
_Out_opt_ PULONG ReturnLength)
{
NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
ULONG CapturedResultLength = 0;
ULONG Alignment = TYPE_ALIGNMENT(ULONG);
KPROCESSOR_MODE PreviousMode;
PAGED_CODE();
PreviousMode = ExGetPreviousMode();
_SEH2_TRY
{
#if (NTDDI_VERSION >= NTDDI_VISTA)
/*
* Check whether the request is valid.
*/
if (SystemInformationClass < MIN_SYSTEM_INFO_CLASS ||
SystemInformationClass >= MAX_SYSTEM_INFO_CLASS)
{
_SEH2_YIELD(return STATUS_INVALID_INFO_CLASS);
}
#endif
if (PreviousMode != KernelMode)
{
/* SystemKernelDebuggerInformation needs only BOOLEAN alignment */
if (SystemInformationClass == SystemKernelDebuggerInformation)
Alignment = TYPE_ALIGNMENT(BOOLEAN);
ProbeForWrite(SystemInformation, SystemInformationLength, Alignment);
if (ReturnLength != NULL)
ProbeForWriteUlong(ReturnLength);
}
if (ReturnLength)
*ReturnLength = 0;
#if (NTDDI_VERSION < NTDDI_VISTA)
/*
* Check whether the request is valid.
*/
if (SystemInformationClass < MIN_SYSTEM_INFO_CLASS ||
SystemInformationClass >= MAX_SYSTEM_INFO_CLASS)
{
_SEH2_YIELD(return STATUS_INVALID_INFO_CLASS);
}
#endif
if (CallQS[SystemInformationClass].Query != NULL)
{
/* Hand the request to a subhandler */
Status = CallQS[SystemInformationClass].Query(SystemInformation,
SystemInformationLength,
&CapturedResultLength);
/* Save the result length to the caller */
if (ReturnLength)
*ReturnLength = CapturedResultLength;
}
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
return Status;
}
__kernel_entry
NTSTATUS
NTAPI
NtSetSystemInformation(
_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
_In_reads_bytes_(SystemInformationLength) PVOID SystemInformation,
_In_ ULONG SystemInformationLength)
{
NTSTATUS Status = STATUS_INVALID_INFO_CLASS;
KPROCESSOR_MODE PreviousMode;
PAGED_CODE();
PreviousMode = ExGetPreviousMode();
_SEH2_TRY
{
/*
* If called from user mode, check possible unsafe arguments.
*/
if (PreviousMode != KernelMode)
{
ProbeForRead(SystemInformation, SystemInformationLength, sizeof(ULONG));
}
/*
* Check whether the request is valid.
*/
if ((SystemInformationClass >= MIN_SYSTEM_INFO_CLASS) &&
(SystemInformationClass < MAX_SYSTEM_INFO_CLASS))
{
if (CallQS[SystemInformationClass].Set != NULL)
{
/* Hand the request to a subhandler */
Status = CallQS[SystemInformationClass].Set(SystemInformation,
SystemInformationLength);
}
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
return Status;
}
ULONG
NTAPI
NtGetCurrentProcessorNumber(VOID)
{
/* Just use Ke */
return KeGetCurrentProcessorNumber();
}
#undef ExGetPreviousMode
KPROCESSOR_MODE
NTAPI
ExGetPreviousMode(VOID)
{
/* Just use Ke */
return KeGetPreviousMode();
}