mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3771 lines
132 KiB
3771 lines
132 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sysinfo.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the NT set and query system information services.
|
|
|
|
Author:
|
|
|
|
Steve Wood (stevewo) 21-Aug-1989
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "exp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "stdlib.h"
|
|
#include "string.h"
|
|
#include "vdmntos.h"
|
|
#include <nturtl.h>
|
|
#include "pool.h"
|
|
#include "stktrace.h"
|
|
#include "..\..\..\inc\alpha.h"
|
|
|
|
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'ofnI');
|
|
|
|
#define PSP_INVALID_ID 2 // BUGBUG - Copied from ps\psp.h
|
|
extern PVOID PspCidTable; // BUGBUG - Copied from ps\psp.h
|
|
|
|
extern ULONG MmAvailablePages;
|
|
extern ULONG MmTotalCommittedPages;
|
|
extern ULONG MmTotalCommitLimit;
|
|
extern ULONG MmPeakCommitment;
|
|
extern ULONG MmLowestPhysicalPage;
|
|
extern ULONG MmHighestPhysicalPage;
|
|
extern ULONG MmTotalFreeSystemPtes[1];
|
|
extern ULONG MmSystemCodePage;
|
|
extern ULONG MmSystemCachePage;
|
|
extern ULONG MmPagedPoolPage;
|
|
extern ULONG MmSystemDriverPage;
|
|
extern ULONG MmTotalSystemCodePages;
|
|
extern ULONG MmTotalSystemDriverPages;
|
|
extern RTL_TIME_ZONE_INFORMATION ExpTimeZoneInformation;
|
|
|
|
//
|
|
// For SystemDpcBehaviorInformation
|
|
//
|
|
extern ULONG KiMaximumDpcQueueDepth;
|
|
extern ULONG KiMinimumDpcRate;
|
|
extern ULONG KiAdjustDpcThreshold;
|
|
extern ULONG KiIdealDpcRate;
|
|
|
|
extern LIST_ENTRY MmLoadedUserImageList;
|
|
|
|
extern MMSUPPORT MmSystemCacheWs;
|
|
|
|
#define ROUND_UP(VALUE,ROUND) ((ULONG)(((ULONG)VALUE + \
|
|
((ULONG)ROUND - 1L)) & (~((ULONG)ROUND - 1L))))
|
|
|
|
NTSTATUS
|
|
ExpGetProcessInformation (
|
|
OUT PVOID SystemInformation,
|
|
IN ULONG SystemInformationLength,
|
|
OUT PULONG Length
|
|
);
|
|
|
|
VOID
|
|
ExpCopyProcessInfo (
|
|
IN PSYSTEM_PROCESS_INFORMATION ProcessInfo,
|
|
IN PEPROCESS Process
|
|
);
|
|
|
|
VOID
|
|
ExpCopyThreadInfo (
|
|
IN PSYSTEM_THREAD_INFORMATION ThreadInfo,
|
|
IN PETHREAD Thread
|
|
);
|
|
|
|
#if i386 && !FPO
|
|
NTSTATUS
|
|
ExpGetStackTraceInformation (
|
|
OUT PVOID SystemInformation,
|
|
IN ULONG SystemInformationLength,
|
|
OUT PULONG Length
|
|
);
|
|
#endif // i386 && !FPO
|
|
|
|
NTSTATUS
|
|
ExpGetLockInformation (
|
|
OUT PVOID SystemInformation,
|
|
IN ULONG SystemInformationLength,
|
|
OUT PULONG Length
|
|
);
|
|
|
|
NTSTATUS
|
|
ExpGetLookasideInformation (
|
|
OUT PVOID Buffer,
|
|
IN ULONG BufferLength,
|
|
OUT PULONG Length
|
|
);
|
|
|
|
NTSTATUS
|
|
ExpGetPoolInformation(
|
|
IN POOL_TYPE PoolType,
|
|
OUT PVOID SystemInformation,
|
|
IN ULONG SystemInformationLength,
|
|
OUT PULONG Length
|
|
);
|
|
|
|
NTSTATUS
|
|
ExpGetHandleInformation(
|
|
OUT PVOID SystemInformation,
|
|
IN ULONG SystemInformationLength,
|
|
OUT PULONG Length
|
|
);
|
|
|
|
NTSTATUS
|
|
ExpGetObjectInformation(
|
|
OUT PVOID SystemInformation,
|
|
IN ULONG SystemInformationLength,
|
|
OUT PULONG Length
|
|
);
|
|
|
|
|
|
NTSTATUS
|
|
ExpGetInstemulInformation(
|
|
OUT PSYSTEM_VDM_INSTEMUL_INFO Info
|
|
);
|
|
|
|
NTSTATUS
|
|
ExpGetPoolTagInfo (
|
|
IN PVOID SystemInformation,
|
|
IN ULONG SystemInformationLength,
|
|
IN OUT PULONG ReturnLength OPTIONAL
|
|
);
|
|
|
|
NTSTATUS
|
|
ExpQueryModuleInformation(
|
|
IN PLIST_ENTRY LoadOrderListHead,
|
|
IN PLIST_ENTRY UserModeLoadOrderListHead,
|
|
OUT PRTL_PROCESS_MODULES ModuleInformation,
|
|
IN ULONG ModuleInformationLength,
|
|
OUT PULONG ReturnLength OPTIONAL
|
|
);
|
|
|
|
#if defined(ALLOC_PRAGMA)
|
|
#pragma alloc_text(PAGE, NtQueryDefaultLocale)
|
|
#pragma alloc_text(PAGE, NtSetDefaultLocale)
|
|
#pragma alloc_text(PAGE, NtQuerySystemInformation)
|
|
#pragma alloc_text(PAGE, NtSetSystemInformation)
|
|
#pragma alloc_text(PAGE, ExpGetHandleInformation)
|
|
#pragma alloc_text(PAGE, ExpGetObjectInformation)
|
|
#pragma alloc_text(PAGE, ExpGetPoolTagInfo)
|
|
#pragma alloc_text(PAGE, ExpQueryModuleInformation)
|
|
#pragma alloc_text(PAGE, ExpCopyProcessInfo)
|
|
#pragma alloc_text(PAGELK, ExpGetProcessInformation)
|
|
#pragma alloc_text(PAGELK, ExpCopyThreadInfo)
|
|
#pragma alloc_text(PAGELK, ExpGetLockInformation)
|
|
#pragma alloc_text(PAGELK, ExpGetLookasideInformation)
|
|
#pragma alloc_text(PAGELK, ExpGetPoolInformation)
|
|
#endif
|
|
|
|
|
|
|
|
NTSTATUS
|
|
NtQueryDefaultLocale(
|
|
IN BOOLEAN UserProfile,
|
|
OUT PLCID DefaultLocaleId
|
|
)
|
|
{
|
|
KPROCESSOR_MODE PreviousMode;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
Status = STATUS_SUCCESS;
|
|
try {
|
|
|
|
//
|
|
// Get previous processor mode and probe output argument if necessary.
|
|
//
|
|
|
|
PreviousMode = KeGetPreviousMode();
|
|
if (PreviousMode != KernelMode) {
|
|
ProbeForWriteUlong( (PULONG)DefaultLocaleId );
|
|
}
|
|
|
|
if (UserProfile) {
|
|
*DefaultLocaleId = PsDefaultThreadLocaleId;
|
|
}
|
|
else {
|
|
*DefaultLocaleId = PsDefaultSystemLocaleId;
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NtSetDefaultLocale(
|
|
IN BOOLEAN UserProfile,
|
|
IN LCID DefaultLocaleId
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING KeyPath, KeyValueName;
|
|
HANDLE CurrentUserKey, Key;
|
|
WCHAR KeyValueBuffer[ 128 ];
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
|
|
ULONG ResultLength;
|
|
PWSTR s;
|
|
ULONG n, i, Digit;
|
|
WCHAR c;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (DefaultLocaleId & 0xFFFF0000) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer;
|
|
if (UserProfile) {
|
|
Status = RtlOpenCurrentUser( MAXIMUM_ALLOWED, &CurrentUserKey );
|
|
if (!NT_SUCCESS( Status )) {
|
|
return Status;
|
|
}
|
|
|
|
RtlInitUnicodeString( &KeyValueName, L"Locale" );
|
|
RtlInitUnicodeString( &KeyPath, L"Control Panel\\International" );
|
|
}
|
|
else {
|
|
RtlInitUnicodeString( &KeyValueName, L"Default" );
|
|
RtlInitUnicodeString( &KeyPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\Language" );
|
|
CurrentUserKey = NULL;
|
|
}
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&KeyPath,
|
|
OBJ_CASE_INSENSITIVE,
|
|
CurrentUserKey,
|
|
NULL
|
|
);
|
|
if (DefaultLocaleId == 0) {
|
|
Status = ZwOpenKey( &Key,
|
|
GENERIC_READ,
|
|
&ObjectAttributes
|
|
);
|
|
if (NT_SUCCESS( Status )) {
|
|
Status = ZwQueryValueKey( Key,
|
|
&KeyValueName,
|
|
KeyValuePartialInformation,
|
|
KeyValueInformation,
|
|
sizeof( KeyValueBuffer ),
|
|
&ResultLength
|
|
);
|
|
if (NT_SUCCESS( Status )) {
|
|
if (KeyValueInformation->Type == REG_SZ) {
|
|
s = (PWSTR)KeyValueInformation->Data;
|
|
for (i=0; i<KeyValueInformation->DataLength; i += sizeof( WCHAR )) {
|
|
c = *s++;
|
|
if (c >= L'0' && c <= L'9') {
|
|
Digit = c - L'0';
|
|
}
|
|
else
|
|
if (c >= L'A' && c <= L'F') {
|
|
Digit = c - L'A' + 10;
|
|
}
|
|
else
|
|
if (c >= L'a' && c <= L'f') {
|
|
Digit = c - L'a' + 10;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
|
|
if (Digit >= 16) {
|
|
break;
|
|
}
|
|
|
|
DefaultLocaleId = (DefaultLocaleId << 4) | Digit;
|
|
}
|
|
}
|
|
else
|
|
if (KeyValueInformation->Type == REG_DWORD &&
|
|
KeyValueInformation->DataLength == sizeof( ULONG )
|
|
) {
|
|
DefaultLocaleId = *(PLCID)KeyValueInformation->Data;
|
|
}
|
|
else {
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
|
|
ZwClose( Key );
|
|
}
|
|
}
|
|
else {
|
|
Status = ZwOpenKey( &Key,
|
|
GENERIC_WRITE,
|
|
&ObjectAttributes
|
|
);
|
|
if (NT_SUCCESS( Status )) {
|
|
if (UserProfile) {
|
|
n = 8;
|
|
}
|
|
else {
|
|
n = 4;
|
|
}
|
|
s = &KeyValueBuffer[ n ];
|
|
*s-- = UNICODE_NULL;
|
|
i = (ULONG)DefaultLocaleId;
|
|
while (s >= KeyValueBuffer) {
|
|
Digit = i & 0x0000000F;
|
|
if (Digit <= 9) {
|
|
*s-- = (WCHAR)(Digit + L'0');
|
|
}
|
|
else {
|
|
*s-- = (WCHAR)((Digit - 10) + L'A');
|
|
}
|
|
|
|
i = i >> 4;
|
|
}
|
|
|
|
Status = ZwSetValueKey( Key,
|
|
&KeyValueName,
|
|
0,
|
|
REG_SZ,
|
|
KeyValueBuffer,
|
|
(n+1) * sizeof( WCHAR )
|
|
);
|
|
ZwClose( Key );
|
|
}
|
|
}
|
|
|
|
ZwClose( CurrentUserKey );
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
if (UserProfile) {
|
|
PsDefaultThreadLocaleId = DefaultLocaleId;
|
|
}
|
|
else {
|
|
PsDefaultSystemLocaleId = DefaultLocaleId;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NtQuerySystemInformation (
|
|
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
|
OUT PVOID SystemInformation,
|
|
IN ULONG SystemInformationLength,
|
|
OUT PULONG ReturnLength OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function queries information about the system.
|
|
|
|
Arguments:
|
|
|
|
SystemInformationClass - The system information class about which
|
|
to retrieve information.
|
|
|
|
SystemInformation - A pointer to a buffer which receives the specified
|
|
information. The format and content of the buffer depend on the
|
|
specified system information class.
|
|
|
|
SystemInformation Format by Information Class:
|
|
|
|
SystemBasicInformation - Data type is SYSTEM_BASIC_INFORMATION
|
|
|
|
SYSTEM_BASIC_INFORMATION Structure
|
|
|
|
ULONG Reserved - Always zero.
|
|
|
|
ULONG TimerResolutionInMicroSeconds - The resolution of
|
|
the hardware time. All time values in NT are
|
|
specified as 64-bit LARGE_INTEGER values in units of
|
|
100 nanoseconds. This field allows an application to
|
|
understand how many of the low order bits of a system
|
|
time value are insignificant.
|
|
|
|
ULONG PageSize - The physical page size for virtual memory
|
|
objects. Physical memory is committed in PageSize
|
|
chunks.
|
|
|
|
ULONG AllocationGranularity - The logical page size for
|
|
virtual memory objects. Allocating 1 byte of virtual
|
|
memory will actually allocate AllocationGranularity
|
|
bytes of virtual memory. Storing into that byte will
|
|
commit the first physical page of the virtual memory.
|
|
|
|
ULONG MinimumUserModeAddress - The smallest valid user mode
|
|
address. The first AllocationGranularity bytes of
|
|
the virtual address space are reserved. This forces
|
|
access violations for code the dereferences a zero
|
|
pointer.
|
|
|
|
ULONG MaximumUserModeAddress - The largest valid used mode
|
|
address. The next AllocationGranullarity bytes of
|
|
the virtual address space are reserved. This allows
|
|
system service routines to validate user mode pointer
|
|
parameters quickly.
|
|
|
|
KAFFINITY ActiveProcessorsAffinityMask - The affinity mask
|
|
for the current hardware configuration.
|
|
|
|
CCHAR NumberOfProcessors - The number of processors
|
|
in the current hardware configuration.
|
|
|
|
SystemProcessorInformation - Data type is SYSTEM_PROCESSOR_INFORMATION
|
|
|
|
SYSTEM_PROCESSOR_INFORMATION Structure
|
|
|
|
USHORT ProcessorArchitecture - The processor architecture:
|
|
PROCESSOR_ARCHITECTURE_INTEL
|
|
PROCESSOR_ARCHITECTURE_MIPS
|
|
PROCESSOR_ARCHITECTURE_ALPHA
|
|
PROCESSOR_ARCHITECTURE_PPC
|
|
|
|
USHORT ProcessorLevel - architecture dependent processor level.
|
|
This is the least common denominator for an MP system:
|
|
|
|
For PROCESSOR_ARCHITECTURE_INTEL:
|
|
3 - 386
|
|
4 - 486
|
|
5 - 586 or Pentium
|
|
|
|
For PROCESSOR_ARCHITECTURE_MIPS:
|
|
00xx - where xx is 8-bit implementation number (bits 8-15 of
|
|
PRId register.
|
|
0004 - R4000
|
|
|
|
For PROCESSOR_ARCHITECTURE_ALPHA:
|
|
xxxx - where xxxx is 16-bit processor version number (low
|
|
order 16 bits of processor version number from firmware)
|
|
|
|
21064 - 21064
|
|
21066 - 21066
|
|
21164 - 21164
|
|
|
|
For PROCESSOR_ARCHITECTURE_PPC:
|
|
xxxx - where xxxx is 16-bit processor version number (high
|
|
order 16 bits of Processor Version Register).
|
|
1 - 601
|
|
3 - 603
|
|
4 - 604
|
|
6 - 603+
|
|
9 - 604+
|
|
20 - 620
|
|
|
|
USHORT ProcessorRevision - architecture dependent processor revision.
|
|
This is the least common denominator for an MP system:
|
|
|
|
For PROCESSOR_ARCHITECTURE_INTEL:
|
|
For Old Intel 386 or 486:
|
|
FFxx - where xx is display as a hexidecimal CPU stepping
|
|
(e.g. FFD0 is D0 stepping)
|
|
|
|
For Intel Pentium or Cyrix/NextGen 486
|
|
xxyy - where xx is model number and yy is stepping, so
|
|
0201 is Model 2, Stepping 1
|
|
|
|
For PROCESSOR_ARCHITECTURE_MIPS:
|
|
00xx is 8-bit revision number of processor (low order 8 bits
|
|
of PRId Register
|
|
|
|
For PROCESSOR_ARCHITECTURE_ALPHA:
|
|
xxyy - where xxyy is 16-bit processor revision number (low
|
|
order 16 bits of processor revision number from firmware).
|
|
Displayed as Model 'A'+xx, Pass yy
|
|
|
|
For PROCESSOR_ARCHITECTURE_PPC:
|
|
xxyy - where xxyy is 16-bit processor revision number (low
|
|
order 16 bits of Processor Version Register). Displayed
|
|
as a fixed point number xx.yy
|
|
|
|
USHORT Reserved - Always zero.
|
|
|
|
ULONG ProcessorFeatureBits - architecture dependent processor feature bits.
|
|
This is the least common denominator for an MP system.
|
|
|
|
SystemPerformanceInformation - Data type is SYSTEM_PERFORMANCE_INFORMATION
|
|
|
|
SYSTEM_PERFORMANCE_INFORMATION Structure
|
|
|
|
LARGE_INTEGER IdleProcessTime - Returns the kernel time of the idle
|
|
process.
|
|
BUGBUG complete comment.
|
|
LARGE_INTEGER IoReadTransferCount;
|
|
LARGE_INTEGER IoWriteTransferCount;
|
|
LARGE_INTEGER IoOtherTransferCount;
|
|
LARGE_INTEGER KernelTime;
|
|
LARGE_INTEGER UserTime;
|
|
ULONG IoReadOperationCount;
|
|
ULONG IoWriteOperationCount;
|
|
ULONG IoOtherOperationCount;
|
|
ULONG AvailablePages;
|
|
ULONG CommittedPages;
|
|
ULONG PageFaultCount;
|
|
ULONG CopyOnWriteCount;
|
|
ULONG TransitionCount;
|
|
ULONG CacheTransitionCount;
|
|
ULONG DemandZeroCount;
|
|
ULONG PageReadCount;
|
|
ULONG PageReadIoCount;
|
|
ULONG CacheReadCount;
|
|
ULONG CacheIoCount;
|
|
ULONG DirtyPagesWriteCount;
|
|
ULONG DirtyWriteIoCount;
|
|
ULONG MappedPagesWriteCount;
|
|
ULONG MappedWriteIoCount;
|
|
ULONG PagedPoolPages;
|
|
ULONG NonPagedPoolPages;
|
|
ULONG PagedPoolAllocs;
|
|
ULONG PagedPoolFrees;
|
|
ULONG NonPagedPoolAllocs;
|
|
ULONG NonPagedPoolFrees;
|
|
ULONG LpcThreadsWaitingInReceive;
|
|
ULONG LpcThreadsWaitingForReply;
|
|
|
|
SystemProcessInformation - Data type is SYSTEM_PROCESS_INFORMATION
|
|
|
|
SYSTEM_PROCESSOR_INFORMATION Structure
|
|
BUGBUG - add here when done.
|
|
|
|
SystemPlugPlayBusInformation - Data type is SYSTEM_PLUGPLAY_BUS_INFORMATION
|
|
|
|
SYSTEM_PLUGPLAY_BUS_INFORMATION Structure
|
|
|
|
ULONG BusCount - Indicates the number of elements returned in the BusInstanceList array.
|
|
|
|
PLUGPLAY_BUS_INSTANCE BusInstanceList[ANYSIZE_ARRAY] - Supplies information about busses
|
|
in the machine.
|
|
|
|
SystemDockInformation - Data type is SYSTEM_DOCK_INFORMATION
|
|
|
|
SYSTEM_DOCK_INFORMATION Structure
|
|
|
|
SYSTEM_DOCKED_STATE DockState - Ordinal specifying the current docking state. Possible values:
|
|
SystemDockStateUnknown - The docking state of the system could not be determined.
|
|
SystemUndocked - The system is undocked.
|
|
SystemDocked - The system is docked.
|
|
|
|
ULONG DockIdLength - Specifies the length in characters of the Dock ID string
|
|
(not including terminating NULL).
|
|
|
|
ULONG SerialNumberOffset - Specifies the character offset of the Serial Number within
|
|
the DockId buffer.
|
|
|
|
ULONG SerialNumberLength - Specifies the length in characters of the Serial Number
|
|
string (not including terminating NULL).
|
|
|
|
WCHAR DockId - Character buffer containing two null-terminated strings. The first
|
|
string is a character representation of the dock ID number, starting
|
|
at the beginning of the buffer. The second string is a character
|
|
representation of the machine's serial number, starting at character
|
|
offset SerialNumberOffset in the buffer.
|
|
|
|
|
|
SystemPowerSettings - Data type is SYSTEM_POWER_SETTINGS
|
|
SYSTEM_POWER_INFORMATION Structure
|
|
BOOLEAN SystemSuspendSupported - Supplies a BOOLEAN as to
|
|
whether the system suspend is enabled or not.
|
|
BOOLEAN SystemHibernateSupported - Supplies a BOOLEAN as to
|
|
whether the system hibernate is enabled or not.
|
|
BOOLEAN ResumeTimerSupportsSuspend - Supplies a BOOLEAN as to
|
|
whether the resuming from an external programmed timer
|
|
from within a system suspend is enabled or not.
|
|
BOOLEAN ResumeTimerSupportsHibernate - Supplies a BOOLEAN as to
|
|
whether or resuming from an external programmed timer
|
|
from within a system hibernate is enabled or not.
|
|
BOOLEAN LidSupported - Supplies a BOOLEAN as to whether or not
|
|
the suspending and resuming by Lid are enabled or not.
|
|
BOOLEAN TurboSettingSupported - Supplies a BOOLEAN as to whether
|
|
or not the system supports a turbo mode setting.
|
|
BOOLEAN TurboMode - Supplies a BOOLEAN as to whether or not
|
|
the system is in turbo mode.
|
|
BOOLEAN SystemAcOrDc - Supplies a BOOLEAN as to whether or not
|
|
the system is in AC mode.
|
|
BOOLEAN DisablePowerDown - If TRUE, signifies that all requests to
|
|
PoRequestPowerChange for a SET_POWER-PowerDown irp are to
|
|
be ingored.
|
|
LARGE_INTEGER SpindownDrives - If non-zero, signifies to the
|
|
cache manager (or the IO susbsystem) to optimize drive
|
|
accesses based upon power saves, are that drives are to
|
|
be spun down as appropriate. The value represents to user's
|
|
requested disk spin down timeout.
|
|
|
|
SystemProcessorSpeedInformation - Data type is SYSTEM_PROCESSOR_SPEED_INFORMATION
|
|
SYSTEM_PROCESSOR_SPEED_INFORMATION Structure (same as HalProcessorSpeedInformation)
|
|
ULONG MaximumProcessorSpeed - The maximum hertz the processor is
|
|
capable of. This information is used by the UI to draw the
|
|
appropriate scale. This field is read-only and cannot be
|
|
set.
|
|
ULONG CurrentAvailableSpeed - The hertz for which the processor
|
|
runs at when not idle. This field is read-only and cannot
|
|
be set.
|
|
ULONG ConfiguredSpeedLimit - The herts for which the processor
|
|
is limited to due to the current configuration.
|
|
UCHAR PowerState
|
|
0 - Normal
|
|
1 - The processors speed is being limited due to available
|
|
power restrictions. This field id read-only by the system.
|
|
UCHAR ThermalState
|
|
0 - Normal
|
|
1 - The processors speed is being limited due to thermal
|
|
restrictions. This field is read-only by the system.
|
|
UCHAR TurboState
|
|
0 - Normal
|
|
1 - The processors speed is being limited by the fact that
|
|
the system turbo mode is currently disabled which is
|
|
requested to obtain more processor speed.
|
|
|
|
SystemInformationLength - Specifies the length in bytes of the system
|
|
information buffer.
|
|
|
|
ReturnLength - An optional pointer which, if specified, receives the
|
|
number of bytes placed in the system information buffer.
|
|
|
|
Return Value:
|
|
|
|
Returns one of the following status codes:
|
|
|
|
STATUS_SUCCESS - normal, successful completion.
|
|
|
|
STATUS_INVALID_INFO_CLASS - The SystemInformationClass parameter
|
|
did not specify a valid value.
|
|
|
|
STATUS_INFO_LENGTH_MISMATCH - The value of the SystemInformationLength
|
|
parameter did not match the length required for the information
|
|
class requested by the SystemInformationClass parameter.
|
|
|
|
STATUS_ACCESS_VIOLATION - Either the SystemInformation buffer pointer
|
|
or the ReturnLength pointer value specified an invalid address.
|
|
|
|
STATUS_WORKING_SET_QUOTA - The process does not have sufficient
|
|
working set to lock the specified output structure in memory.
|
|
|
|
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources exist
|
|
for this request to complete.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
KPROCESSOR_MODE PreviousMode;
|
|
PSYSTEM_BASIC_INFORMATION BasicInfo;
|
|
PSYSTEM_PROCESSOR_INFORMATION ProcessorInfo;
|
|
SYSTEM_TIMEOFDAY_INFORMATION LocalTimeOfDayInfo;
|
|
SYSTEM_PERFORMANCE_INFORMATION LocalPerformanceInfo;
|
|
PSYSTEM_PERFORMANCE_INFORMATION PerformanceInfo;
|
|
PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION ProcessorPerformanceInfo;
|
|
PSYSTEM_CALL_COUNT_INFORMATION CallCountInformation;
|
|
PSYSTEM_DEVICE_INFORMATION DeviceInformation;
|
|
PCONFIGURATION_INFORMATION ConfigInfo;
|
|
PSYSTEM_EXCEPTION_INFORMATION ExceptionInformation;
|
|
PSYSTEM_FILECACHE_INFORMATION FileCache;
|
|
PSYSTEM_QUERY_TIME_ADJUST_INFORMATION TimeAdjustmentInformation;
|
|
PSYSTEM_KERNEL_DEBUGGER_INFORMATION KernelDebuggerInformation;
|
|
PSYSTEM_CONTEXT_SWITCH_INFORMATION ContextSwitchInformation;
|
|
PSYSTEM_INTERRUPT_INFORMATION InterruptInformation;
|
|
|
|
#ifdef _PNP_POWER_
|
|
BOOLEAN ReleasePlugPlayBusListResource = FALSE;
|
|
PLIST_ENTRY CurrentPnPBusListEntry, CurrentPnPBusInstance;
|
|
PPLUGPLAY_BUS_ENUMERATOR CurrentPnPBusEnumerator;
|
|
PSYSTEM_PLUGPLAY_BUS_INFORMATION PlugPlayBusInformation;
|
|
PHAL_SYSTEM_DOCK_INFORMATION HalDockInformation;
|
|
PSYSTEM_DOCK_INFORMATION DockInformation;
|
|
PSYSTEM_POWER_INFORMATION PowerInformation;
|
|
PSYSTEM_PROCESSOR_SPEED_INFORMATION ProcessorSpeedInfo;
|
|
union {
|
|
HAL_POWER_INFORMATION HalPower;
|
|
HAL_PROCESSOR_SPEED_INFORMATION HalProcessorSpeed;
|
|
} Info;
|
|
|
|
ULONG ReturnLengthFromHal;
|
|
#endif // _PNP_POWER_
|
|
|
|
NTSTATUS Status;
|
|
BOOLEAN ReleaseModuleResoure = FALSE;
|
|
PKPRCB Prcb;
|
|
ULONG Length;
|
|
ULONG i;
|
|
ULONG ContextSwitches;
|
|
PULONG TableLimit, TableCounts;
|
|
PKSERVICE_TABLE_DESCRIPTOR Table;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Assume successful completion.
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
try {
|
|
|
|
//
|
|
// Get previous processor mode and probe output argument if necessary.
|
|
//
|
|
|
|
PreviousMode = KeGetPreviousMode();
|
|
if (PreviousMode != KernelMode) {
|
|
ProbeForWrite(SystemInformation,
|
|
SystemInformationLength,
|
|
SystemInformationClass == SystemKernelDebuggerInformation ? sizeof(BOOLEAN)
|
|
: sizeof(ULONG));
|
|
|
|
if (ARGUMENT_PRESENT(ReturnLength)) {
|
|
ProbeForWriteUlong(ReturnLength);
|
|
}
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT(ReturnLength)) {
|
|
*ReturnLength = 0;
|
|
}
|
|
|
|
switch (SystemInformationClass) {
|
|
|
|
case SystemBasicInformation:
|
|
|
|
if (SystemInformationLength != sizeof( SYSTEM_BASIC_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
BasicInfo = (PSYSTEM_BASIC_INFORMATION)SystemInformation;
|
|
BasicInfo->NumberOfProcessors = KeNumberProcessors;
|
|
BasicInfo->ActiveProcessorsAffinityMask = KeActiveProcessors;
|
|
BasicInfo->Reserved = 0;
|
|
BasicInfo->TimerResolution = KeMaximumIncrement;
|
|
BasicInfo->NumberOfPhysicalPages = MmNumberOfPhysicalPages;
|
|
BasicInfo->LowestPhysicalPageNumber = MmLowestPhysicalPage;
|
|
BasicInfo->HighestPhysicalPageNumber = MmHighestPhysicalPage;
|
|
BasicInfo->PageSize = PAGE_SIZE;
|
|
BasicInfo->AllocationGranularity = MM_ALLOCATION_GRANULARITY;
|
|
BasicInfo->MinimumUserModeAddress = (ULONG)MM_LOWEST_USER_ADDRESS;
|
|
BasicInfo->MaximumUserModeAddress = (ULONG)MM_HIGHEST_USER_ADDRESS;
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = sizeof( SYSTEM_BASIC_INFORMATION );
|
|
}
|
|
break;
|
|
|
|
case SystemProcessorInformation:
|
|
if (SystemInformationLength < sizeof( SYSTEM_PROCESSOR_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
ProcessorInfo = (PSYSTEM_PROCESSOR_INFORMATION)SystemInformation;
|
|
|
|
ProcessorInfo->ProcessorArchitecture = KeProcessorArchitecture;
|
|
ProcessorInfo->ProcessorLevel = KeProcessorLevel;
|
|
ProcessorInfo->ProcessorRevision = KeProcessorRevision;
|
|
ProcessorInfo->Reserved = 0;
|
|
ProcessorInfo->ProcessorFeatureBits = KeFeatureBits;
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = sizeof( SYSTEM_PROCESSOR_INFORMATION );
|
|
}
|
|
|
|
break;
|
|
|
|
case SystemPerformanceInformation:
|
|
if (SystemInformationLength < sizeof( SYSTEM_PERFORMANCE_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
PerformanceInfo = (PSYSTEM_PERFORMANCE_INFORMATION)SystemInformation;
|
|
|
|
//
|
|
// Io information.
|
|
//
|
|
|
|
LocalPerformanceInfo.IoReadTransferCount = IoReadTransferCount;
|
|
LocalPerformanceInfo.IoWriteTransferCount = IoWriteTransferCount;
|
|
LocalPerformanceInfo.IoOtherTransferCount = IoOtherTransferCount;
|
|
LocalPerformanceInfo.IoReadOperationCount = IoReadOperationCount;
|
|
LocalPerformanceInfo.IoWriteOperationCount = IoWriteOperationCount;
|
|
LocalPerformanceInfo.IoOtherOperationCount = IoOtherOperationCount;
|
|
|
|
//
|
|
// Ke information.
|
|
//
|
|
// These counters are kept on a per processor basis and must
|
|
// be totaled.
|
|
//
|
|
|
|
{
|
|
ULONG FirstLevelTbFills = 0;
|
|
ULONG SecondLevelTbFills = 0;
|
|
ULONG SystemCalls = 0;
|
|
// ULONG InterruptCount = 0;
|
|
|
|
ContextSwitches = 0;
|
|
for (i = 0; i < (ULONG)KeNumberProcessors; i += 1) {
|
|
Prcb = KiProcessorBlock[i];
|
|
if (Prcb != NULL) {
|
|
ContextSwitches += Prcb->KeContextSwitches;
|
|
FirstLevelTbFills += Prcb->KeFirstLevelTbFills;
|
|
// InterruptCount += Prcb->KeInterruptCount;
|
|
SecondLevelTbFills += Prcb->KeSecondLevelTbFills;
|
|
SystemCalls += Prcb->KeSystemCalls;
|
|
}
|
|
}
|
|
|
|
LocalPerformanceInfo.ContextSwitches = ContextSwitches;
|
|
LocalPerformanceInfo.FirstLevelTbFills = FirstLevelTbFills;
|
|
// LocalPerformanceInfo.InterruptCount = KeInterruptCount;
|
|
LocalPerformanceInfo.SecondLevelTbFills = SecondLevelTbFills;
|
|
LocalPerformanceInfo.SystemCalls = SystemCalls;
|
|
}
|
|
|
|
//
|
|
// Mm information.
|
|
//
|
|
|
|
LocalPerformanceInfo.AvailablePages = MmAvailablePages;
|
|
LocalPerformanceInfo.CommittedPages = MmTotalCommittedPages;
|
|
LocalPerformanceInfo.CommitLimit = MmTotalCommitLimit;
|
|
LocalPerformanceInfo.PeakCommitment = MmPeakCommitment;
|
|
LocalPerformanceInfo.PageFaultCount = MmInfoCounters.PageFaultCount;
|
|
LocalPerformanceInfo.CopyOnWriteCount = MmInfoCounters.CopyOnWriteCount;
|
|
LocalPerformanceInfo.TransitionCount = MmInfoCounters.TransitionCount;
|
|
LocalPerformanceInfo.CacheTransitionCount = MmInfoCounters.CacheTransitionCount;
|
|
LocalPerformanceInfo.DemandZeroCount = MmInfoCounters.DemandZeroCount;
|
|
LocalPerformanceInfo.PageReadCount = MmInfoCounters.PageReadCount;
|
|
LocalPerformanceInfo.PageReadIoCount = MmInfoCounters.PageReadIoCount;
|
|
LocalPerformanceInfo.CacheReadCount = MmInfoCounters.CacheReadCount;
|
|
LocalPerformanceInfo.CacheIoCount = MmInfoCounters.CacheIoCount;
|
|
LocalPerformanceInfo.DirtyPagesWriteCount = MmInfoCounters.DirtyPagesWriteCount;
|
|
LocalPerformanceInfo.DirtyWriteIoCount = MmInfoCounters.DirtyWriteIoCount;
|
|
LocalPerformanceInfo.MappedPagesWriteCount = MmInfoCounters.MappedPagesWriteCount;
|
|
LocalPerformanceInfo.MappedWriteIoCount = MmInfoCounters.MappedWriteIoCount;
|
|
LocalPerformanceInfo.AvailablePages = MmAvailablePages;
|
|
LocalPerformanceInfo.CommittedPages = MmTotalCommittedPages;
|
|
LocalPerformanceInfo.FreeSystemPtes = MmTotalFreeSystemPtes[0];
|
|
|
|
LocalPerformanceInfo.ResidentSystemCodePage = MmSystemCodePage;
|
|
LocalPerformanceInfo.ResidentSystemCachePage = MmSystemCachePage;
|
|
LocalPerformanceInfo.ResidentPagedPoolPage = MmPagedPoolPage;
|
|
LocalPerformanceInfo.ResidentSystemDriverPage = MmSystemDriverPage;
|
|
LocalPerformanceInfo.TotalSystemCodePages = MmTotalSystemCodePages;
|
|
LocalPerformanceInfo.TotalSystemDriverPages = MmTotalSystemDriverPages;
|
|
|
|
//
|
|
// Process information.
|
|
//
|
|
|
|
LocalPerformanceInfo.IdleProcessTime.QuadPart =
|
|
UInt32x32To64(PsIdleProcess->Pcb.KernelTime,
|
|
KeMaximumIncrement);
|
|
|
|
//
|
|
// Pool information.
|
|
//
|
|
|
|
ExQueryPoolUsage( &LocalPerformanceInfo.PagedPoolPages,
|
|
&LocalPerformanceInfo.NonPagedPoolPages,
|
|
&LocalPerformanceInfo.PagedPoolAllocs,
|
|
&LocalPerformanceInfo.PagedPoolFrees,
|
|
&LocalPerformanceInfo.PagedPoolLookasideHits,
|
|
&LocalPerformanceInfo.NonPagedPoolAllocs,
|
|
&LocalPerformanceInfo.NonPagedPoolFrees,
|
|
&LocalPerformanceInfo.NonPagedPoolLookasideHits
|
|
);
|
|
|
|
//
|
|
// Cache Manager information.
|
|
//
|
|
|
|
LocalPerformanceInfo.CcFastReadNoWait = CcFastReadNoWait;
|
|
LocalPerformanceInfo.CcFastReadWait = CcFastReadWait;
|
|
LocalPerformanceInfo.CcFastReadResourceMiss = CcFastReadResourceMiss;
|
|
LocalPerformanceInfo.CcFastReadNotPossible = CcFastReadNotPossible;
|
|
LocalPerformanceInfo.CcFastMdlReadNoWait = CcFastMdlReadNoWait;
|
|
LocalPerformanceInfo.CcFastMdlReadWait = CcFastMdlReadWait;
|
|
LocalPerformanceInfo.CcFastMdlReadResourceMiss = CcFastMdlReadResourceMiss;
|
|
LocalPerformanceInfo.CcFastMdlReadNotPossible = CcFastMdlReadNotPossible;
|
|
LocalPerformanceInfo.CcMapDataNoWait = CcMapDataNoWait;
|
|
LocalPerformanceInfo.CcMapDataWait = CcMapDataWait;
|
|
LocalPerformanceInfo.CcMapDataNoWaitMiss = CcMapDataNoWaitMiss;
|
|
LocalPerformanceInfo.CcMapDataWaitMiss = CcMapDataWaitMiss;
|
|
LocalPerformanceInfo.CcPinMappedDataCount = CcPinMappedDataCount;
|
|
LocalPerformanceInfo.CcPinReadNoWait = CcPinReadNoWait;
|
|
LocalPerformanceInfo.CcPinReadWait = CcPinReadWait;
|
|
LocalPerformanceInfo.CcPinReadNoWaitMiss = CcPinReadNoWaitMiss;
|
|
LocalPerformanceInfo.CcPinReadWaitMiss = CcPinReadWaitMiss;
|
|
LocalPerformanceInfo.CcCopyReadNoWait = CcCopyReadNoWait;
|
|
LocalPerformanceInfo.CcCopyReadWait = CcCopyReadWait;
|
|
LocalPerformanceInfo.CcCopyReadNoWaitMiss = CcCopyReadNoWaitMiss;
|
|
LocalPerformanceInfo.CcCopyReadWaitMiss = CcCopyReadWaitMiss;
|
|
LocalPerformanceInfo.CcMdlReadNoWait = CcMdlReadNoWait;
|
|
LocalPerformanceInfo.CcMdlReadWait = CcMdlReadWait;
|
|
LocalPerformanceInfo.CcMdlReadNoWaitMiss = CcMdlReadNoWaitMiss;
|
|
LocalPerformanceInfo.CcMdlReadWaitMiss = CcMdlReadWaitMiss;
|
|
LocalPerformanceInfo.CcReadAheadIos = CcReadAheadIos;
|
|
LocalPerformanceInfo.CcLazyWriteIos = CcLazyWriteIos;
|
|
LocalPerformanceInfo.CcLazyWritePages = CcLazyWritePages;
|
|
LocalPerformanceInfo.CcDataFlushes = CcDataFlushes;
|
|
LocalPerformanceInfo.CcDataPages = CcDataPages;
|
|
|
|
#if !defined(NT_UP)
|
|
//
|
|
// On an MP machines go sum up some other 'hot' cache manager
|
|
// statistics.
|
|
//
|
|
|
|
for (i = 0; i < (ULONG)KeNumberProcessors; i++) {
|
|
Prcb = KiProcessorBlock[i];
|
|
|
|
LocalPerformanceInfo.CcFastReadNoWait += Prcb->CcFastReadNoWait;
|
|
LocalPerformanceInfo.CcFastReadWait += Prcb->CcFastReadWait;
|
|
LocalPerformanceInfo.CcFastReadNotPossible += Prcb->CcFastReadNotPossible;
|
|
LocalPerformanceInfo.CcCopyReadNoWait += Prcb->CcCopyReadNoWait;
|
|
LocalPerformanceInfo.CcCopyReadWait += Prcb->CcCopyReadWait;
|
|
LocalPerformanceInfo.CcCopyReadNoWaitMiss += Prcb->CcCopyReadNoWaitMiss;
|
|
}
|
|
#endif
|
|
*PerformanceInfo = LocalPerformanceInfo;
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = sizeof(LocalPerformanceInfo);
|
|
}
|
|
|
|
break;
|
|
|
|
case SystemProcessorPerformanceInformation:
|
|
if (SystemInformationLength <
|
|
sizeof( SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
ProcessorPerformanceInfo =
|
|
(PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) SystemInformation;
|
|
|
|
Length = 0;
|
|
for (i = 0; i < (ULONG)KeNumberProcessors; i++) {
|
|
Prcb = KiProcessorBlock[i];
|
|
if (Prcb != NULL) {
|
|
if (SystemInformationLength < Length + sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION))
|
|
break;
|
|
|
|
Length += sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
|
|
|
|
ProcessorPerformanceInfo->UserTime.QuadPart =
|
|
UInt32x32To64(Prcb->UserTime,
|
|
KeMaximumIncrement);
|
|
|
|
ProcessorPerformanceInfo->KernelTime.QuadPart =
|
|
UInt32x32To64(Prcb->KernelTime,
|
|
KeMaximumIncrement);
|
|
|
|
ProcessorPerformanceInfo->DpcTime.QuadPart =
|
|
UInt32x32To64(Prcb->DpcTime,
|
|
KeMaximumIncrement);
|
|
|
|
ProcessorPerformanceInfo->InterruptTime.QuadPart =
|
|
UInt32x32To64(Prcb->InterruptTime,
|
|
KeMaximumIncrement);
|
|
|
|
ProcessorPerformanceInfo->IdleTime.QuadPart =
|
|
UInt32x32To64(Prcb->IdleThread->KernelTime,
|
|
KeMaximumIncrement);
|
|
|
|
ProcessorPerformanceInfo->InterruptCount = Prcb->InterruptCount;
|
|
|
|
ProcessorPerformanceInfo++;
|
|
}
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = Length;
|
|
}
|
|
|
|
break;
|
|
|
|
case SystemTimeOfDayInformation:
|
|
|
|
if (SystemInformationLength != sizeof( SYSTEM_TIMEOFDAY_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
KeQuerySystemTime(&LocalTimeOfDayInfo.CurrentTime);
|
|
LocalTimeOfDayInfo.BootTime = KeBootTime;
|
|
LocalTimeOfDayInfo.TimeZoneBias = ExpTimeZoneBias;
|
|
LocalTimeOfDayInfo.TimeZoneId = ExpCurrentTimeZoneId;
|
|
|
|
try {
|
|
*(PSYSTEM_TIMEOFDAY_INFORMATION)SystemInformation = LocalTimeOfDayInfo;
|
|
|
|
if (ARGUMENT_PRESENT(ReturnLength) ) {
|
|
*ReturnLength = sizeof(LocalTimeOfDayInfo);
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
|
|
//
|
|
// Query system time adjustment information.
|
|
//
|
|
|
|
case SystemTimeAdjustmentInformation:
|
|
if (SystemInformationLength != sizeof( SYSTEM_QUERY_TIME_ADJUST_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
TimeAdjustmentInformation =
|
|
(PSYSTEM_QUERY_TIME_ADJUST_INFORMATION)SystemInformation;
|
|
|
|
TimeAdjustmentInformation->TimeAdjustment = KeTimeAdjustment;
|
|
TimeAdjustmentInformation->TimeIncrement = KeMaximumIncrement;
|
|
TimeAdjustmentInformation->Enable = KeTimeSynchronization;
|
|
break;
|
|
|
|
case SystemSummaryMemoryInformation:
|
|
case SystemFullMemoryInformation:
|
|
|
|
if (SystemInformationLength < sizeof( SYSTEM_MEMORY_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
Status = MmMemoryUsage (SystemInformation,
|
|
SystemInformationLength,
|
|
(SystemInformationClass == SystemFullMemoryInformation) ? 0 : 1,
|
|
&Length);
|
|
|
|
if (NT_SUCCESS(Status) && ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = Length;
|
|
}
|
|
break;
|
|
|
|
case SystemPathInformation:
|
|
DbgPrint( "EX: SystemPathInformation now available via SharedUserData\n" );
|
|
DbgBreakPoint();
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case SystemProcessInformation:
|
|
if (SystemInformationLength < sizeof( SYSTEM_PROCESS_INFORMATION)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
Status = ExpGetProcessInformation (SystemInformation,
|
|
SystemInformationLength,
|
|
&Length);
|
|
|
|
if (NT_SUCCESS(Status) && ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = Length;
|
|
}
|
|
|
|
break;
|
|
|
|
case SystemCallCountInformation:
|
|
|
|
Length = sizeof(SYSTEM_CALL_COUNT_INFORMATION) +
|
|
(NUMBER_SERVICE_TABLES * sizeof(ULONG));
|
|
for ( i = 0, Table = KeServiceDescriptorTableShadow;
|
|
i < NUMBER_SERVICE_TABLES;
|
|
i++, Table++ ) {
|
|
if ( (Table->Limit != 0) && (Table->Count != NULL) ) {
|
|
Length += Table->Limit * sizeof(ULONG);
|
|
}
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = Length;
|
|
}
|
|
|
|
if (SystemInformationLength < Length) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
CallCountInformation = (PSYSTEM_CALL_COUNT_INFORMATION)SystemInformation;
|
|
CallCountInformation->Length = Length;
|
|
CallCountInformation->NumberOfTables = NUMBER_SERVICE_TABLES;
|
|
|
|
TableLimit = (PULONG)(CallCountInformation + 1);
|
|
TableCounts = TableLimit + NUMBER_SERVICE_TABLES;
|
|
for ( i = 0, Table = KeServiceDescriptorTableShadow;
|
|
i < NUMBER_SERVICE_TABLES;
|
|
i++, Table++ ) {
|
|
if ((Table->Limit == 0) || (Table->Count == NULL)) {
|
|
*TableLimit++ = 0;
|
|
} else {
|
|
*TableLimit++ = Table->Limit;
|
|
RtlMoveMemory((PVOID)TableCounts,
|
|
(PVOID)Table->Count,
|
|
Table->Limit * sizeof(ULONG));
|
|
TableCounts += Table->Limit;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case SystemDeviceInformation:
|
|
if (SystemInformationLength != sizeof( SYSTEM_DEVICE_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
ConfigInfo = IoGetConfigurationInformation();
|
|
DeviceInformation = (PSYSTEM_DEVICE_INFORMATION)SystemInformation;
|
|
DeviceInformation->NumberOfDisks = ConfigInfo->DiskCount;
|
|
DeviceInformation->NumberOfFloppies = ConfigInfo->FloppyCount;
|
|
DeviceInformation->NumberOfCdRoms = ConfigInfo->CdRomCount;
|
|
DeviceInformation->NumberOfTapes = ConfigInfo->TapeCount;
|
|
DeviceInformation->NumberOfSerialPorts = ConfigInfo->SerialCount;
|
|
DeviceInformation->NumberOfParallelPorts = ConfigInfo->ParallelCount;
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = sizeof( SYSTEM_DEVICE_INFORMATION );
|
|
}
|
|
break;
|
|
|
|
case SystemFlagsInformation:
|
|
if (SystemInformationLength != sizeof( SYSTEM_FLAGS_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
((PSYSTEM_FLAGS_INFORMATION)SystemInformation)->Flags = NtGlobalFlag;
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = sizeof( SYSTEM_FLAGS_INFORMATION );
|
|
}
|
|
break;
|
|
|
|
case SystemCallTimeInformation:
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
case SystemModuleInformation:
|
|
KeEnterCriticalRegion();
|
|
ExAcquireResourceExclusive( &PsLoadedModuleResource, TRUE );
|
|
ReleaseModuleResoure = TRUE;
|
|
Status = ExpQueryModuleInformation( &PsLoadedModuleList,
|
|
&MmLoadedUserImageList,
|
|
(PRTL_PROCESS_MODULES)SystemInformation,
|
|
SystemInformationLength,
|
|
ReturnLength
|
|
);
|
|
ExReleaseResource (&PsLoadedModuleResource);
|
|
ReleaseModuleResoure = FALSE;
|
|
KeLeaveCriticalRegion();
|
|
break;
|
|
|
|
case SystemLocksInformation:
|
|
if (SystemInformationLength < sizeof( RTL_PROCESS_LOCKS )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
Status = ExpGetLockInformation (SystemInformation,
|
|
SystemInformationLength,
|
|
&Length);
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = Length;
|
|
}
|
|
|
|
break;
|
|
|
|
case SystemStackTraceInformation:
|
|
if (SystemInformationLength < sizeof( RTL_PROCESS_BACKTRACES )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
#if i386 && !FPO
|
|
Status = ExpGetStackTraceInformation (SystemInformation,
|
|
SystemInformationLength,
|
|
&Length);
|
|
#else
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
#endif // i386 && !FPO
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = Length;
|
|
}
|
|
|
|
break;
|
|
|
|
case SystemPagedPoolInformation:
|
|
if (SystemInformationLength < sizeof( SYSTEM_POOL_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
Status = ExpGetPoolInformation( PagedPool,
|
|
SystemInformation,
|
|
SystemInformationLength,
|
|
&Length
|
|
);
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = Length;
|
|
}
|
|
break;
|
|
|
|
case SystemNonPagedPoolInformation:
|
|
if (SystemInformationLength < sizeof( SYSTEM_POOL_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
Status = ExpGetPoolInformation( NonPagedPool,
|
|
SystemInformation,
|
|
SystemInformationLength,
|
|
&Length
|
|
);
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = Length;
|
|
}
|
|
break;
|
|
|
|
case SystemHandleInformation:
|
|
if (SystemInformationLength < sizeof( SYSTEM_HANDLE_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
Status = ExpGetHandleInformation( SystemInformation,
|
|
SystemInformationLength,
|
|
&Length
|
|
);
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = Length;
|
|
}
|
|
break;
|
|
|
|
case SystemObjectInformation:
|
|
if (SystemInformationLength < sizeof( SYSTEM_OBJECTTYPE_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
Status = ExpGetObjectInformation( SystemInformation,
|
|
SystemInformationLength,
|
|
&Length
|
|
);
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = Length;
|
|
}
|
|
break;
|
|
|
|
case SystemPageFileInformation:
|
|
|
|
if (SystemInformationLength < sizeof( SYSTEM_PAGEFILE_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
Status = MmGetPageFileInformation( SystemInformation,
|
|
SystemInformationLength,
|
|
&Length
|
|
);
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = Length;
|
|
}
|
|
break;
|
|
|
|
|
|
case SystemFileCacheInformation:
|
|
|
|
//
|
|
// This structure was extended in NT 4.0 from 12 bytes.
|
|
// Use the previous size of 12 bytes for versioning info.
|
|
//
|
|
|
|
if (SystemInformationLength < 12) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
FileCache = (PSYSTEM_FILECACHE_INFORMATION)SystemInformation;
|
|
FileCache->CurrentSize = MmSystemCacheWs.WorkingSetSize << PAGE_SHIFT;
|
|
FileCache->PeakSize = MmSystemCacheWs.PeakWorkingSetSize << PAGE_SHIFT;
|
|
FileCache->PageFaultCount = MmSystemCacheWs.PageFaultCount;
|
|
|
|
i = 12;
|
|
if (SystemInformationLength >= sizeof( SYSTEM_FILECACHE_INFORMATION )) {
|
|
i = sizeof (SYSTEM_FILECACHE_INFORMATION);
|
|
FileCache->MinimumWorkingSet =
|
|
MmSystemCacheWs.MinimumWorkingSetSize;
|
|
FileCache->MaximumWorkingSet =
|
|
MmSystemCacheWs.MaximumWorkingSetSize;
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = i;
|
|
}
|
|
break;
|
|
|
|
case SystemPoolTagInformation:
|
|
|
|
#ifdef POOL_TAGGING
|
|
if (SystemInformationLength < sizeof( SYSTEM_POOLTAG_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
Status = ExpGetPoolTagInfo (SystemInformation,
|
|
SystemInformationLength,
|
|
ReturnLength);
|
|
#else
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
#endif //POOL_TAGGING
|
|
|
|
break;
|
|
|
|
case SystemVdmInstemulInformation:
|
|
#ifdef i386
|
|
if (SystemInformationLength < sizeof( SYSTEM_VDM_INSTEMUL_INFO )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
Status = ExpGetInstemulInformation(
|
|
(PSYSTEM_VDM_INSTEMUL_INFO)SystemInformation
|
|
);
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = sizeof(SYSTEM_VDM_INSTEMUL_INFO);
|
|
}
|
|
#else
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
#endif
|
|
break;
|
|
|
|
#if DBG
|
|
case SystemNextEventIdInformation:
|
|
{
|
|
PRTL_EVENT_ID_INFO UserEventId, NewEventId, OldEventId;
|
|
|
|
UserEventId = (PRTL_EVENT_ID_INFO)SystemInformation;
|
|
NewEventId = (PRTL_EVENT_ID_INFO)ExAllocatePool( PagedPool, UserEventId->Length );
|
|
RtlMoveMemory( NewEventId, UserEventId, UserEventId->Length );
|
|
OldEventId = ExDefineEventId( NewEventId );
|
|
if (OldEventId != NULL) {
|
|
UserEventId->EventId = OldEventId->EventId;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
Status = STATUS_TOO_MANY_NAMES;
|
|
}
|
|
|
|
if (OldEventId != NewEventId) {
|
|
ExFreePool( NewEventId );
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SystemEventIdsInformation:
|
|
Status = ExpQueryEventIds( (PRTL_EVENT_ID_INFO)SystemInformation,
|
|
SystemInformationLength,
|
|
ReturnLength
|
|
);
|
|
break;
|
|
#else
|
|
case SystemNextEventIdInformation:
|
|
case SystemEventIdsInformation:
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
#endif // DBG
|
|
|
|
case SystemCrashDumpInformation:
|
|
|
|
if (SystemInformationLength < sizeof( SYSTEM_CRASH_DUMP_INFORMATION)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
Status = MmGetCrashDumpInformation (
|
|
(PSYSTEM_CRASH_DUMP_INFORMATION)SystemInformation);
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = sizeof(SYSTEM_CRASH_DUMP_INFORMATION);
|
|
}
|
|
|
|
break;
|
|
|
|
//
|
|
// Get system exception information which includes the number
|
|
// of exceptions that have dispatched, the number of alignment
|
|
// fixups, and the number of floating emulations that have been
|
|
// performed.
|
|
//
|
|
|
|
case SystemExceptionInformation:
|
|
if (SystemInformationLength < sizeof( SYSTEM_EXCEPTION_INFORMATION)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = sizeof(SYSTEM_EXCEPTION_INFORMATION);
|
|
}
|
|
|
|
ExceptionInformation = (PSYSTEM_EXCEPTION_INFORMATION)SystemInformation;
|
|
|
|
//
|
|
// Ke information.
|
|
//
|
|
// These counters are kept on a per processor basis and must
|
|
// be totaled.
|
|
//
|
|
|
|
{
|
|
ULONG AlignmentFixupCount = 0;
|
|
ULONG ExceptionDispatchCount = 0;
|
|
ULONG FloatingEmulationCount = 0;
|
|
ULONG ByteWordEmulationCount = 0;
|
|
|
|
for (i = 0; i < (ULONG)KeNumberProcessors; i += 1) {
|
|
Prcb = KiProcessorBlock[i];
|
|
if (Prcb != NULL) {
|
|
AlignmentFixupCount += Prcb->KeAlignmentFixupCount;
|
|
ExceptionDispatchCount += Prcb->KeExceptionDispatchCount;
|
|
FloatingEmulationCount += Prcb->KeFloatingEmulationCount;
|
|
#if defined(_ALPHA_)
|
|
ByteWordEmulationCount += Prcb->KeByteWordEmulationCount;
|
|
#endif // defined(_ALPHA_)
|
|
}
|
|
}
|
|
|
|
ExceptionInformation->AlignmentFixupCount = AlignmentFixupCount;
|
|
ExceptionInformation->ExceptionDispatchCount = ExceptionDispatchCount;
|
|
ExceptionInformation->FloatingEmulationCount = FloatingEmulationCount;
|
|
ExceptionInformation->ByteWordEmulationCount = ByteWordEmulationCount;
|
|
}
|
|
|
|
break;
|
|
|
|
case SystemCrashDumpStateInformation:
|
|
|
|
if (SystemInformationLength < sizeof( SYSTEM_CRASH_STATE_INFORMATION)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
Status = MmGetCrashDumpStateInformation (
|
|
(PSYSTEM_CRASH_STATE_INFORMATION)SystemInformation);
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = sizeof(SYSTEM_CRASH_STATE_INFORMATION);
|
|
}
|
|
|
|
break;
|
|
|
|
case SystemKernelDebuggerInformation:
|
|
|
|
if (SystemInformationLength < sizeof( SYSTEM_KERNEL_DEBUGGER_INFORMATION)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
KernelDebuggerInformation =
|
|
(PSYSTEM_KERNEL_DEBUGGER_INFORMATION)SystemInformation;
|
|
KernelDebuggerInformation->KernelDebuggerEnabled = KdDebuggerEnabled;
|
|
KernelDebuggerInformation->KernelDebuggerNotPresent = KdDebuggerNotPresent;
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION);
|
|
}
|
|
|
|
break;
|
|
|
|
case SystemContextSwitchInformation:
|
|
|
|
if (SystemInformationLength < sizeof( SYSTEM_CONTEXT_SWITCH_INFORMATION)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
ContextSwitchInformation =
|
|
(PSYSTEM_CONTEXT_SWITCH_INFORMATION)SystemInformation;
|
|
|
|
//
|
|
// Compute the totla number of context switches and fill in the
|
|
// remainder of the context switch information.
|
|
//
|
|
|
|
ContextSwitches = 0;
|
|
for (i = 0; i < (ULONG)KeNumberProcessors; i += 1) {
|
|
Prcb = KiProcessorBlock[i];
|
|
if (Prcb != NULL) {
|
|
ContextSwitches += Prcb->KeContextSwitches;
|
|
}
|
|
|
|
}
|
|
|
|
ContextSwitchInformation->ContextSwitches = ContextSwitches;
|
|
ContextSwitchInformation->FindAny = KeThreadSwitchCounters.FindAny;
|
|
ContextSwitchInformation->FindLast = KeThreadSwitchCounters.FindLast;
|
|
ContextSwitchInformation->FindIdeal = KeThreadSwitchCounters.FindIdeal;
|
|
ContextSwitchInformation->IdleAny = KeThreadSwitchCounters.IdleAny;
|
|
ContextSwitchInformation->IdleCurrent = KeThreadSwitchCounters.IdleCurrent;
|
|
ContextSwitchInformation->IdleLast = KeThreadSwitchCounters.IdleLast;
|
|
ContextSwitchInformation->IdleIdeal = KeThreadSwitchCounters.IdleIdeal;
|
|
ContextSwitchInformation->PreemptAny = KeThreadSwitchCounters.PreemptAny;
|
|
ContextSwitchInformation->PreemptCurrent = KeThreadSwitchCounters.PreemptCurrent;
|
|
ContextSwitchInformation->PreemptLast = KeThreadSwitchCounters.PreemptLast;
|
|
ContextSwitchInformation->SwitchToIdle = KeThreadSwitchCounters.SwitchToIdle;
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = sizeof(SYSTEM_CONTEXT_SWITCH_INFORMATION);
|
|
}
|
|
|
|
break;
|
|
|
|
case SystemRegistryQuotaInformation:
|
|
|
|
if (SystemInformationLength < sizeof( SYSTEM_REGISTRY_QUOTA_INFORMATION)) {
|
|
return(STATUS_INFO_LENGTH_MISMATCH);
|
|
}
|
|
CmQueryRegistryQuotaInformation((PSYSTEM_REGISTRY_QUOTA_INFORMATION)SystemInformation);
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = sizeof(SYSTEM_REGISTRY_QUOTA_INFORMATION);
|
|
}
|
|
break;
|
|
|
|
case SystemDpcBehaviorInformation:
|
|
{
|
|
PSYSTEM_DPC_BEHAVIOR_INFORMATION DpcInfo;
|
|
//
|
|
// If the system information buffer is not the correct length,
|
|
// then return an error.
|
|
//
|
|
if (SystemInformationLength != sizeof(SYSTEM_DPC_BEHAVIOR_INFORMATION)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
DpcInfo = (PSYSTEM_DPC_BEHAVIOR_INFORMATION)SystemInformation;
|
|
|
|
//
|
|
// Exception handler for this routine will return the correct
|
|
// error if any of these accesses fail.
|
|
//
|
|
//
|
|
// Return the current DPC behavior variables
|
|
//
|
|
DpcInfo->DpcQueueDepth = KiMaximumDpcQueueDepth;
|
|
DpcInfo->MinimumDpcRate = KiMinimumDpcRate;
|
|
DpcInfo->AdjustDpcThreshold = KiAdjustDpcThreshold;
|
|
DpcInfo->IdealDpcRate = KiIdealDpcRate;
|
|
}
|
|
break;
|
|
|
|
case SystemInterruptInformation:
|
|
|
|
if (SystemInformationLength < (sizeof(SYSTEM_INTERRUPT_INFORMATION) * KeNumberProcessors)) {
|
|
return(STATUS_INFO_LENGTH_MISMATCH);
|
|
}
|
|
|
|
InterruptInformation = (PSYSTEM_INTERRUPT_INFORMATION)SystemInformation;
|
|
for (i=0; i < (ULONG)KeNumberProcessors; i++) {
|
|
Prcb = KiProcessorBlock[i];
|
|
InterruptInformation->ContextSwitches = Prcb->KeContextSwitches;
|
|
InterruptInformation->DpcCount = Prcb->DpcCount;
|
|
InterruptInformation->DpcRate = Prcb->DpcRequestRate;
|
|
InterruptInformation->TimeIncrement = KeTimeIncrement;
|
|
InterruptInformation->DpcBypassCount = Prcb->DpcBypassCount;
|
|
InterruptInformation->ApcBypassCount = Prcb->ApcBypassCount;
|
|
|
|
++InterruptInformation;
|
|
}
|
|
|
|
break;
|
|
|
|
case SystemPlugPlayBusInformation:
|
|
|
|
#ifndef _PNP_POWER_
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
#else
|
|
//
|
|
// Report the Plug and Play bus instances currently present in the system.
|
|
//
|
|
// First, acquire resource for shared (read) access.
|
|
//
|
|
KeEnterCriticalRegion();
|
|
ExAcquireResourceShared( &PpBusResource, TRUE );
|
|
ReleasePlugPlayBusListResource = TRUE;
|
|
|
|
//
|
|
// Determine the number of buses in the Plug and Play manager's list.
|
|
//
|
|
i = 0;
|
|
for ( CurrentPnPBusListEntry = PpBusListHead.Flink;
|
|
CurrentPnPBusListEntry != &PpBusListHead;
|
|
CurrentPnPBusListEntry = CurrentPnPBusListEntry->Flink ) {
|
|
|
|
CurrentPnPBusEnumerator = CONTAINING_RECORD( CurrentPnPBusListEntry,
|
|
PLUGPLAY_BUS_ENUMERATOR,
|
|
BusEnumeratorListEntry
|
|
);
|
|
|
|
for ( CurrentPnPBusInstance = CurrentPnPBusEnumerator->BusInstanceListEntry.Flink;
|
|
CurrentPnPBusInstance != &(CurrentPnPBusEnumerator->BusInstanceListEntry);
|
|
CurrentPnPBusInstance = CurrentPnPBusInstance->Flink ) {
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
Length = sizeof(SYSTEM_PLUGPLAY_BUS_INFORMATION) +
|
|
(i ? sizeof(PLUGPLAY_BUS_INSTANCE) * (i - 1) : 0);
|
|
|
|
if (ARGUMENT_PRESENT(ReturnLength)) {
|
|
*ReturnLength = Length;
|
|
}
|
|
|
|
if (SystemInformationLength < Length) {
|
|
ExReleaseResource( &PpBusResource );
|
|
KeLeaveCriticalRegion();
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
PlugPlayBusInformation = (PSYSTEM_PLUGPLAY_BUS_INFORMATION)SystemInformation;
|
|
|
|
PlugPlayBusInformation->BusCount = i;
|
|
|
|
i = 0;
|
|
for ( CurrentPnPBusListEntry = PpBusListHead.Flink;
|
|
CurrentPnPBusListEntry != &PpBusListHead;
|
|
CurrentPnPBusListEntry = CurrentPnPBusListEntry->Flink ) {
|
|
|
|
CurrentPnPBusEnumerator = CONTAINING_RECORD( CurrentPnPBusListEntry,
|
|
PLUGPLAY_BUS_ENUMERATOR,
|
|
BusEnumeratorListEntry
|
|
);
|
|
|
|
for ( CurrentPnPBusInstance = CurrentPnPBusEnumerator->BusInstanceListEntry.Flink;
|
|
CurrentPnPBusInstance != &(CurrentPnPBusEnumerator->BusInstanceListEntry);
|
|
CurrentPnPBusInstance = CurrentPnPBusInstance->Flink ) {
|
|
|
|
RtlCopyMemory( &(PlugPlayBusInformation->BusInstance[i]),
|
|
&(CONTAINING_RECORD( CurrentPnPBusInstance,
|
|
PLUGPLAY_BUS_INSTANCE_FULL_DESCRIPTOR,
|
|
BusInstanceListEntry
|
|
)->BusInstanceInformation),
|
|
sizeof(PLUGPLAY_BUS_INSTANCE)
|
|
);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
ExReleaseResource( &PpBusResource );
|
|
ReleasePlugPlayBusListResource = FALSE;
|
|
KeLeaveCriticalRegion();
|
|
break;
|
|
#endif // _PNP_POWER_
|
|
|
|
case SystemDockInformation:
|
|
|
|
#ifndef _PNP_POWER_
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
#else
|
|
//
|
|
// Report the current system docking state, as returned by HalQuerySystemInformation
|
|
// (information class HalSystemDockInformation).
|
|
//
|
|
// First, retrieve the information via HalQuerySystemInformation. Start with an initial
|
|
// guess for buffer size that accommodates a 32-bit dock ID and a 32-bit serial # (in
|
|
// character form).
|
|
//
|
|
Length = sizeof(HAL_SYSTEM_DOCK_INFORMATION) + (17 * sizeof(WCHAR));
|
|
|
|
do {
|
|
|
|
HalDockInformation = (PHAL_SYSTEM_DOCK_INFORMATION)ExAllocatePool( PagedPool, Length);
|
|
|
|
if(HalDockInformation) {
|
|
|
|
Status = HalQuerySystemInformation( HalSystemDockInformation,
|
|
Length,
|
|
HalDockInformation,
|
|
&Length
|
|
);
|
|
} else {
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if(!NT_SUCCESS( Status )) {
|
|
|
|
if(HalDockInformation) {
|
|
ExFreePool( HalDockInformation );
|
|
}
|
|
|
|
if(Status != STATUS_BUFFER_TOO_SMALL) { // Then we want to return an error.
|
|
|
|
if(Status == STATUS_INVALID_LEVEL) { // Translate HAL return code
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
} while (Status == STATUS_BUFFER_TOO_SMALL);
|
|
|
|
if (ARGUMENT_PRESENT(ReturnLength)) {
|
|
*ReturnLength = Length;
|
|
}
|
|
|
|
if (SystemInformationLength < Length) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
DockInformation = (PSYSTEM_DOCK_INFORMATION)SystemInformation;
|
|
DockInformation->DockState = HalDockInformation->DockState;
|
|
DockInformation->DeviceBusType = HalDockInformation->DeviceBusType;
|
|
DockInformation->DeviceBusNumber = HalDockInformation->DeviceBusNumber;
|
|
DockInformation->SlotNumber = HalDockInformation->SlotNumber;
|
|
|
|
ExFreePool( HalDockInformation );
|
|
|
|
//
|
|
// Reset NTSTATUS variable since we used it above.
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
|
|
break;
|
|
|
|
#endif // _PNP_POWER_
|
|
|
|
#ifdef _PNP_POWER_
|
|
case SystemPowerInformation:
|
|
if (SystemInformationLength < sizeof( SYSTEM_POWER_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
// Temporary data
|
|
|
|
PowerInformation = (PSYSTEM_POWER_INFORMATION)SystemInformation;
|
|
RtlZeroMemory (PowerInformation, sizeof (SYSTEM_POWER_INFORMATION));
|
|
|
|
Status = HalQuerySystemInformation( HalPowerInformation,
|
|
sizeof( HAL_POWER_INFORMATION ),
|
|
&Info.HalPower,
|
|
&ReturnLengthFromHal );
|
|
|
|
if(NT_SUCCESS(Status)){
|
|
PowerInformation = (PSYSTEM_POWER_INFORMATION)SystemInformation;
|
|
|
|
PowerInformation->SystemSuspendSupported = Info.HalPower.SuspendSupported;
|
|
PowerInformation->SystemHibernateSupported = Info.HalPower.SoftPowerDownSupported;
|
|
PowerInformation->ResumeTimerSupportsSuspend = Info.HalPower.ResumeTimerSupportsSuspend;
|
|
PowerInformation->ResumeTimerSupportsHibernate = Info.HalPower.ResumeTimerSupportsHibernate;
|
|
PowerInformation->LidSupported = Info.HalPower.LidPresent;
|
|
PowerInformation->TurboSettingSupported = Info.HalPower.TurboSettingSupported;
|
|
PowerInformation->TurboMode = Info.HalPower.TurboMode;
|
|
}
|
|
|
|
// BUGBUG: SpindownDrives ?????
|
|
// PowerInformation->SpindownDrives = TRUE;
|
|
PowerInformation->PowerDownDisabled = !PoEnabled;
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = sizeof( SYSTEM_POWER_INFORMATION );
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case SystemProcessorSpeedInformation:
|
|
if (SystemInformationLength < sizeof( SYSTEM_PROCESSOR_SPEED_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
ProcessorSpeedInfo =
|
|
(PSYSTEM_PROCESSOR_SPEED_INFORMATION)SystemInformation;
|
|
RtlZeroMemory (ProcessorSpeedInfo, sizeof (SYSTEM_PROCESSOR_SPEED_INFORMATION));
|
|
|
|
Status = HalQuerySystemInformation( HalProcessorSpeedInformation,
|
|
sizeof( HAL_PROCESSOR_SPEED_INFORMATION ),
|
|
&Info.HalProcessorSpeed,
|
|
&ReturnLengthFromHal );
|
|
|
|
if(NT_SUCCESS(Status)){
|
|
ProcessorSpeedInfo->MaximumProcessorSpeed = Info.HalProcessorSpeed.MaximumProcessorSpeed;
|
|
ProcessorSpeedInfo->CurrentAvailableSpeed = Info.HalProcessorSpeed.CurrentAvailableSpeed;
|
|
ProcessorSpeedInfo->ConfiguredSpeedLimit = Info.HalProcessorSpeed.ConfiguredSpeedLimit;
|
|
ProcessorSpeedInfo->PowerLimit = Info.HalProcessorSpeed.PowerLimit;
|
|
ProcessorSpeedInfo->ThermalLimit = Info.HalProcessorSpeed.ThermalLimit;
|
|
ProcessorSpeedInfo->TurboLimit = Info.HalProcessorSpeed.TurboLimit;
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = sizeof( SYSTEM_PROCESSOR_SPEED_INFORMATION );
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
#endif // _PNP_POWER_
|
|
|
|
case SystemCurrentTimeZoneInformation:
|
|
if (SystemInformationLength < sizeof( RTL_TIME_ZONE_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
RtlCopyMemory(SystemInformation,&ExpTimeZoneInformation,sizeof(ExpTimeZoneInformation));
|
|
if (ARGUMENT_PRESENT( ReturnLength )) {
|
|
*ReturnLength = sizeof( RTL_TIME_ZONE_INFORMATION );
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
//
|
|
// Query pool lookaside list and general lookaside list
|
|
// information.
|
|
//
|
|
|
|
case SystemLookasideInformation:
|
|
Status = ExpGetLookasideInformation(SystemInformation,
|
|
SystemInformationLength,
|
|
&Length);
|
|
|
|
if (ARGUMENT_PRESENT(ReturnLength)) {
|
|
*ReturnLength = Length;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// Invalid argument.
|
|
//
|
|
|
|
return STATUS_INVALID_INFO_CLASS;
|
|
}
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
if (ReleaseModuleResoure) {
|
|
ExReleaseResource (&PsLoadedModuleResource);
|
|
KeLeaveCriticalRegion();
|
|
}
|
|
|
|
#ifdef _PNP_POWER_
|
|
if (ReleasePlugPlayBusListResource) {
|
|
ExReleaseResource(&PpBusResource);
|
|
KeLeaveCriticalRegion();
|
|
}
|
|
#endif // _PNP_POWER_
|
|
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
NtSetSystemInformation (
|
|
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
|
IN PVOID SystemInformation,
|
|
IN ULONG SystemInformationLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function set information about the system.
|
|
|
|
Arguments:
|
|
|
|
SystemInformationClass - The system information class which is to
|
|
be modified.
|
|
|
|
SystemInformation - A pointer to a buffer which contains the specified
|
|
information. The format and content of the buffer depend on the
|
|
specified system information class.
|
|
|
|
|
|
SystemInformationLength - Specifies the length in bytes of the system
|
|
information buffer.
|
|
|
|
Return Value:
|
|
|
|
Returns one of the following status codes:
|
|
|
|
STATUS_SUCCESS - Normal, successful completion.
|
|
|
|
STATUS_ACCESS_VIOLATION - The specified sysgtem information buffer
|
|
is not accessible.
|
|
|
|
STATUS_INVALID_INFO_CLASS - The SystemInformationClass parameter
|
|
did not specify a valid value.
|
|
|
|
STATUS_INFO_LENGTH_MISMATCH - The value of the SystemInformationLength
|
|
parameter did not match the length required for the information
|
|
class requested by the SystemInformationClass parameter.
|
|
|
|
STATUS_PRIVILEGE_NOT_HELD is returned if the caller does not have the
|
|
privilege to set the system time.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
BOOLEAN Enable;
|
|
KPROCESSOR_MODE PreviousMode;
|
|
NTSTATUS Status;
|
|
ULONG TimeAdjustment;
|
|
PSYSTEM_SET_TIME_ADJUST_INFORMATION TimeAdjustmentInformation;
|
|
BOOLEAN InformationClassInRegistry;
|
|
#ifdef _PNP_POWER_
|
|
PSYSTEM_POWER_INFORMATION PowerInformation;
|
|
PSYSTEM_PROCESSOR_SPEED_INFORMATION ProcessorSpeedInformation;
|
|
union {
|
|
HAL_POWER_INFORMATION HalPower;
|
|
HAL_PROCESSOR_SPEED_INFORMATION HalProcessorSpeed;
|
|
} Info;
|
|
#endif // _PNP_POWER_
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Establish an exception handle in case the system information buffer
|
|
// is not accessbile.
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
InformationClassInRegistry = FALSE;
|
|
|
|
try {
|
|
|
|
//
|
|
// Get the previous processor mode and probe the input buffer for
|
|
// read access if necessary.
|
|
//
|
|
|
|
PreviousMode = KeGetPreviousMode();
|
|
if (PreviousMode != KernelMode) {
|
|
ProbeForRead((PVOID)SystemInformation,
|
|
SystemInformationLength,
|
|
sizeof(ULONG));
|
|
}
|
|
|
|
//
|
|
// Dispatch on the system information class.
|
|
//
|
|
|
|
switch (SystemInformationClass) {
|
|
case SystemFlagsInformation:
|
|
if (SystemInformationLength != sizeof( SYSTEM_FLAGS_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
if (!SeSinglePrivilegeCheck( SeDebugPrivilege, PreviousMode )) {
|
|
return STATUS_ACCESS_DENIED;
|
|
}
|
|
else {
|
|
((PSYSTEM_FLAGS_INFORMATION)SystemInformation)->Flags &= FLG_KERNELMODE_VALID_BITS;
|
|
NtGlobalFlag = ((PSYSTEM_FLAGS_INFORMATION)SystemInformation)->Flags;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Set system time adjustment information.
|
|
//
|
|
// N.B. The caller must have the SeSystemTime privilege.
|
|
//
|
|
|
|
case SystemTimeAdjustmentInformation:
|
|
|
|
//
|
|
// If the system information buffer is not the correct length,
|
|
// then return an error.
|
|
//
|
|
|
|
if (SystemInformationLength != sizeof( SYSTEM_SET_TIME_ADJUST_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
//
|
|
// If the current thread does not have the privilege to set the
|
|
// time adjustment variables, then return an error.
|
|
//
|
|
|
|
if ((PreviousMode != KernelMode) &&
|
|
(SeSinglePrivilegeCheck(SeSystemtimePrivilege, PreviousMode) == FALSE)) {
|
|
return STATUS_PRIVILEGE_NOT_HELD;
|
|
}
|
|
|
|
//
|
|
// Set system time adjustment parameters.
|
|
//
|
|
|
|
TimeAdjustmentInformation =
|
|
(PSYSTEM_SET_TIME_ADJUST_INFORMATION)SystemInformation;
|
|
|
|
Enable = TimeAdjustmentInformation->Enable;
|
|
TimeAdjustment = TimeAdjustmentInformation->TimeAdjustment;
|
|
if (Enable == TRUE) {
|
|
KeTimeAdjustment = KeMaximumIncrement;
|
|
|
|
} else {
|
|
KeTimeAdjustment = TimeAdjustment;
|
|
}
|
|
|
|
KeTimeSynchronization = Enable;
|
|
break;
|
|
|
|
//
|
|
// Set registry quota limit.
|
|
//
|
|
// N.B. The caller must have SeIncreaseQuotaPrivilege
|
|
//
|
|
case SystemRegistryQuotaInformation:
|
|
|
|
//
|
|
// If the system information buffer is not the correct length,
|
|
// then return an error.
|
|
//
|
|
|
|
if (SystemInformationLength != sizeof( SYSTEM_REGISTRY_QUOTA_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
//
|
|
// If the current thread does not have the privilege to create
|
|
// a pagefile, then return an error.
|
|
//
|
|
|
|
if ((PreviousMode != KernelMode) &&
|
|
(SeSinglePrivilegeCheck(SeIncreaseQuotaPrivilege, PreviousMode) == FALSE)) {
|
|
return STATUS_PRIVILEGE_NOT_HELD;
|
|
}
|
|
|
|
//
|
|
// Set registry quota parameters.
|
|
//
|
|
CmSetRegistryQuotaInformation((PSYSTEM_REGISTRY_QUOTA_INFORMATION)SystemInformation);
|
|
|
|
break;
|
|
|
|
case SystemPrioritySeperation:
|
|
{
|
|
ULONG PrioritySeperation;
|
|
|
|
//
|
|
// If the system information buffer is not the correct length,
|
|
// then return an error.
|
|
//
|
|
|
|
if (SystemInformationLength != sizeof( ULONG )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
try {
|
|
PrioritySeperation = *(PULONG)SystemInformation;
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
return GetExceptionCode();
|
|
}
|
|
|
|
if ( PrioritySeperation > 2 ) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else {
|
|
PsPrioritySeperation = PrioritySeperation;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SystemExtendServiceTableInformation:
|
|
{
|
|
|
|
UNICODE_STRING Image;
|
|
PWSTR Buffer;
|
|
PVOID ImageBaseAddress;
|
|
ULONG EntryPoint;
|
|
PVOID SectionPointer;
|
|
PIMAGE_NT_HEADERS NtHeaders;
|
|
PDRIVER_INITIALIZE InitRoutine;
|
|
|
|
//
|
|
// If the system information buffer is not the correct length,
|
|
// then return an error.
|
|
//
|
|
|
|
if (SystemInformationLength != sizeof( UNICODE_STRING ) ) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
if (PreviousMode != KernelMode) {
|
|
|
|
//
|
|
// The caller's access mode is not kernel so check to ensure that
|
|
// the caller has the privilege to load a driver.
|
|
//
|
|
|
|
if (!SeSinglePrivilegeCheck( SeLoadDriverPrivilege, PreviousMode )) {
|
|
return STATUS_PRIVILEGE_NOT_HELD;
|
|
}
|
|
|
|
try {
|
|
Buffer = NULL;
|
|
Image = *(PUNICODE_STRING)SystemInformation;
|
|
Buffer = ExAllocatePool(PagedPool,Image.Length);
|
|
if ( !Buffer ) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
RtlCopyMemory(Buffer,Image.Buffer,Image.Length);
|
|
Image.Buffer = Buffer;
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
if ( Buffer ) {
|
|
ExFreePool(Buffer);
|
|
}
|
|
return GetExceptionCode();
|
|
}
|
|
|
|
//
|
|
// MmLoadSystemImage is always called with previous mode
|
|
// of kernel. I will keep this alive...
|
|
//
|
|
|
|
Status = ZwSetSystemInformation(
|
|
SystemExtendServiceTableInformation,
|
|
(PVOID)&Image,
|
|
sizeof(Image)
|
|
);
|
|
|
|
ExFreePool(Buffer);
|
|
|
|
return Status;
|
|
|
|
}
|
|
else {
|
|
Image = *(PUNICODE_STRING)SystemInformation;
|
|
}
|
|
|
|
//
|
|
// We are in kernelmode now, so load the driver
|
|
//
|
|
|
|
Status = MmLoadSystemImage(
|
|
&Image,
|
|
&SectionPointer,
|
|
(PVOID *) &ImageBaseAddress
|
|
);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
return Status;
|
|
}
|
|
|
|
NtHeaders = RtlImageNtHeader( ImageBaseAddress );
|
|
EntryPoint = NtHeaders->OptionalHeader.AddressOfEntryPoint;
|
|
EntryPoint += (ULONG) ImageBaseAddress;
|
|
InitRoutine = (PDRIVER_INITIALIZE) EntryPoint;
|
|
|
|
Status = (InitRoutine)(NULL,NULL);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
MmUnloadSystemImage( SectionPointer );
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
|
|
case SystemUnloadGdiDriverInformation:
|
|
{
|
|
|
|
if (SystemInformationLength != sizeof( PVOID ) ) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
if (PreviousMode != KernelMode) {
|
|
|
|
//
|
|
// The caller's access mode is not kernel so fail.
|
|
// Only GDI from the kernel can call this.
|
|
//
|
|
|
|
return STATUS_PRIVILEGE_NOT_HELD;
|
|
|
|
}
|
|
|
|
MmUnloadSystemImage( *((PVOID *)SystemInformation) );
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
}
|
|
break;
|
|
|
|
|
|
case SystemLoadGdiDriverInformation:
|
|
{
|
|
|
|
UNICODE_STRING Image;
|
|
PVOID ImageBaseAddress;
|
|
ULONG EntryPoint;
|
|
PVOID SectionPointer;
|
|
|
|
PIMAGE_NT_HEADERS NtHeaders;
|
|
|
|
//
|
|
// If the system information buffer is not the correct length,
|
|
// then return an error.
|
|
//
|
|
|
|
if (SystemInformationLength != sizeof( SYSTEM_GDI_DRIVER_INFORMATION ) ) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
if (PreviousMode != KernelMode) {
|
|
|
|
//
|
|
// The caller's access mode is not kernel so fail.
|
|
// Only GDI from the kernel can call this.
|
|
//
|
|
|
|
return STATUS_PRIVILEGE_NOT_HELD;
|
|
|
|
}
|
|
|
|
Image = ((PSYSTEM_GDI_DRIVER_INFORMATION)SystemInformation)->DriverName;
|
|
|
|
//
|
|
// We are in kernelmode now, so load the driver
|
|
//
|
|
|
|
Status = MmLoadSystemImage(
|
|
&Image,
|
|
&SectionPointer,
|
|
(PVOID *) &ImageBaseAddress
|
|
);
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
|
|
PSYSTEM_GDI_DRIVER_INFORMATION GdiDriverInfo =
|
|
(PSYSTEM_GDI_DRIVER_INFORMATION) SystemInformation;
|
|
|
|
ULONG Size;
|
|
PVOID BaseAddress;
|
|
|
|
GdiDriverInfo->ExportSectionPointer =
|
|
RtlImageDirectoryEntryToData(ImageBaseAddress,
|
|
TRUE,
|
|
IMAGE_DIRECTORY_ENTRY_EXPORT,
|
|
&Size);
|
|
|
|
//
|
|
// Get the entry point - at this time we may or may not
|
|
// use it.
|
|
//
|
|
|
|
NtHeaders = RtlImageNtHeader( ImageBaseAddress );
|
|
EntryPoint = NtHeaders->OptionalHeader.AddressOfEntryPoint;
|
|
EntryPoint += (ULONG) ImageBaseAddress;
|
|
|
|
GdiDriverInfo->ImageAddress = (PVOID) ImageBaseAddress;
|
|
GdiDriverInfo->SectionPointer = SectionPointer;
|
|
GdiDriverInfo->EntryPoint = (PVOID) EntryPoint;
|
|
|
|
//
|
|
// GDI drivers can be entirely paged - especially
|
|
// printer drivers !
|
|
//
|
|
|
|
BaseAddress = MmPageEntireDriver((PVOID)ImageBaseAddress);
|
|
|
|
ASSERT(BaseAddress == ImageBaseAddress);
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SystemFileCacheInformation:
|
|
|
|
if (SystemInformationLength < sizeof( SYSTEM_FILECACHE_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
return MmAdjustWorkingSetSize (
|
|
((PSYSTEM_FILECACHE_INFORMATION)SystemInformation)->MinimumWorkingSet,
|
|
((PSYSTEM_FILECACHE_INFORMATION)SystemInformation)->MaximumWorkingSet,
|
|
TRUE);
|
|
|
|
break;
|
|
|
|
case SystemDpcBehaviorInformation:
|
|
{
|
|
SYSTEM_DPC_BEHAVIOR_INFORMATION DpcInfo;
|
|
//
|
|
// If the system information buffer is not the correct length,
|
|
// then return an error.
|
|
//
|
|
if (SystemInformationLength != sizeof(SYSTEM_DPC_BEHAVIOR_INFORMATION)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
if (PreviousMode != KernelMode) {
|
|
//
|
|
// The caller's access mode is not kernel so check to ensure that
|
|
// the caller has the privilege to load a driver.
|
|
//
|
|
|
|
if (!SeSinglePrivilegeCheck( SeLoadDriverPrivilege, PreviousMode )) {
|
|
return STATUS_PRIVILEGE_NOT_HELD;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Exception handler for this routine will return the correct
|
|
// error if this access fails.
|
|
//
|
|
DpcInfo = *(PSYSTEM_DPC_BEHAVIOR_INFORMATION)SystemInformation;
|
|
|
|
//
|
|
// Set the new DPC behavior variables
|
|
//
|
|
KiMaximumDpcQueueDepth = DpcInfo.DpcQueueDepth;
|
|
KiMinimumDpcRate = DpcInfo.MinimumDpcRate;
|
|
KiAdjustDpcThreshold = DpcInfo.AdjustDpcThreshold;
|
|
KiIdealDpcRate = DpcInfo.IdealDpcRate;
|
|
}
|
|
break;
|
|
#ifdef _PNP_POWER_
|
|
case SystemPowerInformation:
|
|
|
|
//
|
|
// This information level is available in the registry
|
|
//
|
|
|
|
InformationClassInRegistry = TRUE;
|
|
|
|
//
|
|
// If the current thread does not have the privilege to set the
|
|
// time adjustment variables, then return an error.
|
|
//
|
|
|
|
if ((PreviousMode != KernelMode) &&
|
|
(SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode) == FALSE)) {
|
|
return STATUS_PRIVILEGE_NOT_HELD;
|
|
}
|
|
|
|
//
|
|
// If the system information buffer is not the correct length,
|
|
// then return an error.
|
|
//
|
|
|
|
if (SystemInformationLength != sizeof( SYSTEM_POWER_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
PowerInformation = (PSYSTEM_POWER_INFORMATION)SystemInformation;
|
|
Info.HalPower.SuspendSupported = PowerInformation->SystemSuspendSupported;
|
|
Info.HalPower.SoftPowerDownSupported = PowerInformation->SystemHibernateSupported;
|
|
Info.HalPower.ResumeTimerSupportsSuspend = PowerInformation->ResumeTimerSupportsSuspend;
|
|
Info.HalPower.ResumeTimerSupportsHibernate = PowerInformation->ResumeTimerSupportsHibernate;
|
|
Info.HalPower.LidPresent = PowerInformation->LidSupported;
|
|
Info.HalPower.TurboSettingSupported = PowerInformation->TurboSettingSupported;
|
|
Info.HalPower.TurboMode = PowerInformation->TurboMode;
|
|
|
|
// BUGBUG: SpindownDrivers
|
|
|
|
|
|
Status = HalSetSystemInformation(
|
|
HalPowerInformation,
|
|
sizeof( HAL_POWER_INFORMATION ),
|
|
&Info.HalPower
|
|
);
|
|
|
|
if (NT_SUCCESS (Status)) {
|
|
PoSetPowerManagementEnable ((BOOLEAN) !PowerInformation->PowerDownDisabled);
|
|
}
|
|
break;
|
|
|
|
case SystemProcessorSpeedInformation:
|
|
|
|
//
|
|
// This information level is available in the registry
|
|
//
|
|
|
|
InformationClassInRegistry = TRUE;
|
|
|
|
//
|
|
// If the system information buffer is not the correct length,
|
|
// then return an error.
|
|
//
|
|
|
|
if (SystemInformationLength != sizeof( SYSTEM_PROCESSOR_SPEED_INFORMATION )) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
ProcessorSpeedInformation = (PSYSTEM_PROCESSOR_SPEED_INFORMATION)SystemInformation;
|
|
Info.HalProcessorSpeed.MaximumProcessorSpeed = ProcessorSpeedInformation->MaximumProcessorSpeed;
|
|
Info.HalProcessorSpeed.CurrentAvailableSpeed = ProcessorSpeedInformation->CurrentAvailableSpeed;
|
|
Info.HalProcessorSpeed.ConfiguredSpeedLimit = ProcessorSpeedInformation->ConfiguredSpeedLimit;
|
|
Info.HalProcessorSpeed.PowerLimit = ProcessorSpeedInformation->PowerLimit;
|
|
Info.HalProcessorSpeed.ThermalLimit = ProcessorSpeedInformation->ThermalLimit;
|
|
Info.HalProcessorSpeed.TurboLimit = ProcessorSpeedInformation->TurboLimit;
|
|
|
|
Status = HalSetSystemInformation(
|
|
HalProcessorSpeedInformation,
|
|
sizeof( HAL_POWER_INFORMATION ),
|
|
&Info.HalProcessorSpeed
|
|
);
|
|
|
|
break;
|
|
#endif // _PNP_POWER_
|
|
|
|
default:
|
|
//KeBugCheckEx(SystemInformationClass,KdPitchDebugger,0,0,0);
|
|
Status = STATUS_INVALID_INFO_CLASS;
|
|
break;
|
|
}
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
#ifdef _PNP_POWER_
|
|
//
|
|
// If successful perform notification
|
|
//
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
if (InformationClassInRegistry) {
|
|
|
|
//
|
|
// This inforamtion class is in the registry, check
|
|
// to see if the registry needs updated (callback will
|
|
// be done by this check)
|
|
//
|
|
|
|
ExpCheckSystemInformation (
|
|
NULL,
|
|
(PVOID) SystemInformationClass,
|
|
NULL
|
|
);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Notify callback that this information level was set
|
|
//
|
|
|
|
ExNotifyCallback (
|
|
ExCbSetSystemInformation,
|
|
(PVOID) SystemInformationClass,
|
|
(PVOID) NULL
|
|
);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
return Status;
|
|
}
|
|
|
|
PVOID
|
|
ExLockUserBuffer(
|
|
IN PVOID Buffer,
|
|
IN ULONG Length,
|
|
OUT PVOID *LockVariable
|
|
)
|
|
|
|
{
|
|
PMDL Mdl;
|
|
PVOID Address;
|
|
|
|
//
|
|
// Allocate an MDL to map the request.
|
|
//
|
|
|
|
Mdl = ExAllocatePoolWithQuota (NonPagedPool,
|
|
sizeof(MDL) + sizeof(ULONG) +
|
|
BYTES_TO_PAGES (Length) * sizeof(ULONG));
|
|
if (Mdl == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Initialize MDL for request.
|
|
//
|
|
|
|
MmInitializeMdl(Mdl, Buffer, Length);
|
|
|
|
try {
|
|
|
|
MmProbeAndLockPages (Mdl, KeGetPreviousMode(), IoWriteAccess);
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
ExFreePool (Mdl);
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
Mdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;
|
|
Address = MmGetSystemAddressForMdl (Mdl);
|
|
*LockVariable = Mdl;
|
|
if (Address == NULL) {
|
|
ExUnlockUserBuffer (Mdl);
|
|
*LockVariable = NULL;
|
|
}
|
|
|
|
return Address;
|
|
}
|
|
|
|
|
|
VOID
|
|
ExUnlockUserBuffer(
|
|
IN PVOID LockVariable
|
|
)
|
|
|
|
{
|
|
MmUnlockPages ((PMDL)LockVariable);
|
|
ExFreePool ((PMDL)LockVariable);
|
|
return;
|
|
}
|
|
|
|
extern FAST_MUTEX PspActiveProcessMutex;
|
|
NTSTATUS
|
|
ExpGetProcessInformation (
|
|
OUT PVOID SystemInformation,
|
|
IN ULONG SystemInformationLength,
|
|
OUT PULONG Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns information about all the processes and
|
|
threads in the system.
|
|
|
|
Arguments:
|
|
|
|
SystemInformation - A pointer to a buffer which receives the specified
|
|
information.
|
|
|
|
SystemInformationLength - Specifies the length in bytes of the system
|
|
information buffer.
|
|
|
|
Length - An optional pointer which, if specified, receives the
|
|
number of bytes placed in the system information buffer.
|
|
|
|
|
|
Return Value:
|
|
|
|
Returns one of the following status codes:
|
|
|
|
STATUS_SUCCESS - normal, successful completion.
|
|
|
|
STATUS_INVALID_INFO_CLASS - The SystemInformationClass parameter
|
|
did not specify a valid value.
|
|
|
|
STATUS_INFO_LENGTH_MISMATCH - The value of the SystemInformationLength
|
|
parameter did not match the length required for the information
|
|
class requested by the SystemInformationClass parameter.
|
|
|
|
STATUS_ACCESS_VIOLATION - Either the SystemInformation buffer pointer
|
|
or the Length pointer value specified an invalid address.
|
|
|
|
STATUS_WORKING_SET_QUOTA - The process does not have sufficient
|
|
working set to lock the specified output structure in memory.
|
|
|
|
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources exist
|
|
for this request to complete.
|
|
|
|
--*/
|
|
|
|
{
|
|
KEVENT Event;
|
|
PEPROCESS Process;
|
|
PETHREAD Thread;
|
|
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
|
|
PSYSTEM_THREAD_INFORMATION ThreadInfo;
|
|
PLIST_ENTRY NextProcess;
|
|
PLIST_ENTRY NextThread;
|
|
PVOID MappedAddress;
|
|
PVOID LockVariable;
|
|
ULONG TotalSize;
|
|
ULONG NextEntryOffset;
|
|
PUCHAR Src;
|
|
PWSTR Dst;
|
|
ULONG n;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
*Length = 0;
|
|
|
|
MappedAddress = ExLockUserBuffer( SystemInformation,
|
|
SystemInformationLength,
|
|
&LockVariable
|
|
);
|
|
if (MappedAddress == NULL) {
|
|
return( STATUS_ACCESS_VIOLATION );
|
|
}
|
|
MmLockPagableSectionByHandle (ExPageLockHandle);
|
|
ExAcquireFastMutex(&PspActiveProcessMutex);
|
|
|
|
//
|
|
// Initialize an event object and then set the event with the wait
|
|
// parameter TRUE. This causes the event to be set and control is
|
|
// returned with the dispatcher database locked at dispatch IRQL.
|
|
//
|
|
|
|
KeInitializeEvent (&Event, NotificationEvent, FALSE);
|
|
try {
|
|
|
|
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)MappedAddress;
|
|
|
|
|
|
NextEntryOffset = sizeof(SYSTEM_PROCESS_INFORMATION);
|
|
TotalSize = sizeof(SYSTEM_PROCESS_INFORMATION);
|
|
|
|
ExpCopyProcessInfo (ProcessInfo, PsIdleProcess);
|
|
|
|
//
|
|
// Since Idle process and system process share the same
|
|
// object table, zero out idle processes handle count to
|
|
// reduce confusion
|
|
//
|
|
|
|
ProcessInfo->HandleCount = 0;
|
|
|
|
//
|
|
// Set the event with the wait
|
|
// parameter TRUE. This causes the event to be set and control is
|
|
// returned with the dispatcher database locked at dispatch IRQL.
|
|
//
|
|
// WARNING - The following code assumes that the process structure
|
|
// uses kernel objects to synchronize access to the thread and
|
|
// process lists.
|
|
//
|
|
|
|
KeSetEvent (&Event, 0, TRUE);
|
|
|
|
//
|
|
// WARNING - The following code runs with the kernel dispatch database
|
|
// locked. EXTREME caution should be taken when modifying this
|
|
// code. Extended execution will ADVERSELY affect system operation
|
|
// and integrity.
|
|
//
|
|
// Get info for idle process's threads
|
|
//
|
|
//
|
|
// Get information for each thread.
|
|
//
|
|
|
|
ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
|
|
ProcessInfo->NumberOfThreads = 0;
|
|
NextThread = PsIdleProcess->Pcb.ThreadListHead.Flink;
|
|
while (NextThread != &PsIdleProcess->Pcb.ThreadListHead) {
|
|
NextEntryOffset += sizeof(SYSTEM_THREAD_INFORMATION);
|
|
TotalSize += sizeof(SYSTEM_THREAD_INFORMATION);
|
|
|
|
if (TotalSize > SystemInformationLength) {
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|
KeWaitForSingleObject (&Event, Executive, KernelMode, FALSE, NULL);
|
|
goto Failed;
|
|
}
|
|
Thread = (PETHREAD)(CONTAINING_RECORD(NextThread,
|
|
KTHREAD,
|
|
ThreadListEntry));
|
|
ExpCopyThreadInfo (ThreadInfo,Thread);
|
|
|
|
ProcessInfo->NumberOfThreads += 1;
|
|
NextThread = NextThread->Flink;
|
|
ThreadInfo += 1;
|
|
}
|
|
|
|
//
|
|
// Unlock the dispatch database by waiting on the event that was
|
|
// previously set with the wait parameter TRUE.
|
|
//
|
|
|
|
KeWaitForSingleObject (&Event, Executive, KernelMode, FALSE, NULL);
|
|
|
|
ProcessInfo->ImageName.Buffer = NULL;
|
|
ProcessInfo->ImageName.Length = 0;
|
|
ProcessInfo->NextEntryOffset = NextEntryOffset;
|
|
|
|
NextProcess = PsActiveProcessHead.Flink;
|
|
|
|
while (NextProcess != &PsActiveProcessHead) {
|
|
Process = CONTAINING_RECORD(NextProcess,
|
|
EPROCESS,
|
|
ActiveProcessLinks);
|
|
|
|
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)
|
|
((PUCHAR)MappedAddress + TotalSize);
|
|
|
|
NextEntryOffset = sizeof(SYSTEM_PROCESS_INFORMATION);
|
|
TotalSize += sizeof(SYSTEM_PROCESS_INFORMATION);
|
|
if (TotalSize > SystemInformationLength) {
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|
goto Failed;
|
|
}
|
|
|
|
//
|
|
// Get information for each process.
|
|
//
|
|
|
|
ExpCopyProcessInfo (ProcessInfo, Process);
|
|
|
|
//
|
|
// Set the event with the wait
|
|
// parameter TRUE. This causes the event to be set and control is
|
|
// returned with the dispatcher database locked at dispatch IRQL.
|
|
//
|
|
// WARNING - The following code assumes that the process structure
|
|
// uses kernel objects to synchronize access to the thread and
|
|
// process lists.
|
|
//
|
|
|
|
KeSetEvent (&Event, 0, TRUE);
|
|
|
|
//
|
|
// WARNING - The following code runs with the kernel dispatch database
|
|
// locked. EXTREME caution should be taken when modifying this
|
|
// code. Extended execution will ADVERSELY affect system operation
|
|
// and integrity.
|
|
//
|
|
|
|
//
|
|
// Get information for each thread.
|
|
//
|
|
|
|
ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
|
|
ProcessInfo->NumberOfThreads = 0;
|
|
NextThread = Process->Pcb.ThreadListHead.Flink;
|
|
while (NextThread != &Process->Pcb.ThreadListHead) {
|
|
NextEntryOffset += sizeof(SYSTEM_THREAD_INFORMATION);
|
|
TotalSize += sizeof(SYSTEM_THREAD_INFORMATION);
|
|
|
|
if (TotalSize > SystemInformationLength) {
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|
KeWaitForSingleObject (&Event, Executive, KernelMode, FALSE, NULL);
|
|
goto Failed;
|
|
}
|
|
Thread = (PETHREAD)(CONTAINING_RECORD(NextThread,
|
|
KTHREAD,
|
|
ThreadListEntry));
|
|
ExpCopyThreadInfo (ThreadInfo,Thread);
|
|
|
|
ProcessInfo->NumberOfThreads += 1;
|
|
NextThread = NextThread->Flink;
|
|
ThreadInfo += 1;
|
|
}
|
|
|
|
//
|
|
// Unlock the dispatch database by waiting on the event that was
|
|
// previously set with the wait parameter TRUE.
|
|
//
|
|
|
|
KeWaitForSingleObject (&Event, Executive, KernelMode, FALSE, NULL);
|
|
|
|
//
|
|
// Get the image name.
|
|
//
|
|
|
|
ProcessInfo->ImageName.Buffer = NULL;
|
|
ProcessInfo->ImageName.Length = 0;
|
|
ProcessInfo->ImageName.MaximumLength = 0;
|
|
|
|
if ((n = strlen( Src = Process->ImageFileName ))) {
|
|
n = ROUND_UP( ((n + 1) * sizeof( WCHAR )), sizeof(LARGE_INTEGER) );
|
|
TotalSize += n;
|
|
NextEntryOffset += n;
|
|
if (TotalSize > SystemInformationLength) {
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|
} else {
|
|
Dst = (PWSTR)(ThreadInfo);
|
|
while (*Dst++ = (WCHAR)*Src++) {
|
|
;
|
|
}
|
|
ProcessInfo->ImageName.Length = (USHORT)((PCHAR)Dst - (PCHAR)ThreadInfo - sizeof( UNICODE_NULL ));
|
|
ProcessInfo->ImageName.MaximumLength = (USHORT)n;
|
|
|
|
//
|
|
// Set the image name to point into the user's memory.
|
|
//
|
|
|
|
ProcessInfo->ImageName.Buffer = (PWSTR)
|
|
((PCHAR)SystemInformation +
|
|
((PCHAR)(ThreadInfo) - (PCHAR)MappedAddress));
|
|
}
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
goto Failed;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Point to next process.
|
|
//
|
|
|
|
ProcessInfo->NextEntryOffset = NextEntryOffset;
|
|
NextProcess = NextProcess->Flink;
|
|
}
|
|
|
|
ProcessInfo->NextEntryOffset = 0;
|
|
status = STATUS_SUCCESS;
|
|
*Length = TotalSize;
|
|
|
|
Failed:
|
|
;
|
|
|
|
} finally {
|
|
ExReleaseFastMutex(&PspActiveProcessMutex);
|
|
MmUnlockPagableImageSection(ExPageLockHandle);
|
|
ExUnlockUserBuffer( LockVariable );
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
VOID
|
|
ExpCopyProcessInfo (
|
|
IN PSYSTEM_PROCESS_INFORMATION ProcessInfo,
|
|
IN PEPROCESS Process
|
|
)
|
|
|
|
{
|
|
PHANDLE_TABLE Ht;
|
|
|
|
PAGED_CODE();
|
|
|
|
Ht = (PHANDLE_TABLE)Process->ObjectTable;
|
|
if ( Ht ) {
|
|
ProcessInfo->HandleCount = Ht->HandleCount;
|
|
}
|
|
else {
|
|
ProcessInfo->HandleCount = 0;
|
|
}
|
|
ProcessInfo->CreateTime = Process->CreateTime;
|
|
ProcessInfo->UserTime.QuadPart = UInt32x32To64(Process->Pcb.UserTime,
|
|
KeMaximumIncrement);
|
|
|
|
ProcessInfo->KernelTime.QuadPart = UInt32x32To64(Process->Pcb.KernelTime,
|
|
KeMaximumIncrement);
|
|
|
|
ProcessInfo->BasePriority = Process->Pcb.BasePriority;
|
|
ProcessInfo->UniqueProcessId = Process->UniqueProcessId;
|
|
ProcessInfo->InheritedFromUniqueProcessId = Process->InheritedFromUniqueProcessId;
|
|
ProcessInfo->PeakVirtualSize = Process->PeakVirtualSize;
|
|
ProcessInfo->VirtualSize = Process->VirtualSize;
|
|
ProcessInfo->PageFaultCount = Process->Vm.PageFaultCount;
|
|
ProcessInfo->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize << PAGE_SHIFT;
|
|
ProcessInfo->WorkingSetSize = Process->Vm.WorkingSetSize << PAGE_SHIFT;
|
|
ProcessInfo->QuotaPeakPagedPoolUsage =
|
|
Process->QuotaPeakPoolUsage[PagedPool];
|
|
ProcessInfo->QuotaPagedPoolUsage = Process->QuotaPoolUsage[PagedPool];
|
|
ProcessInfo->QuotaPeakNonPagedPoolUsage =
|
|
Process->QuotaPeakPoolUsage[NonPagedPool];
|
|
ProcessInfo->QuotaNonPagedPoolUsage =
|
|
Process->QuotaPoolUsage[NonPagedPool];
|
|
ProcessInfo->PagefileUsage = Process->PagefileUsage << PAGE_SHIFT;
|
|
ProcessInfo->PeakPagefileUsage = Process->PeakPagefileUsage << PAGE_SHIFT;
|
|
ProcessInfo->PrivatePageCount = Process->CommitCharge << PAGE_SHIFT;
|
|
}
|
|
|
|
VOID
|
|
ExpCopyThreadInfo (
|
|
IN PSYSTEM_THREAD_INFORMATION ThreadInfo,
|
|
IN PETHREAD Thread
|
|
)
|
|
|
|
{
|
|
|
|
ThreadInfo->KernelTime.QuadPart = UInt32x32To64(Thread->Tcb.KernelTime,
|
|
KeMaximumIncrement);
|
|
|
|
ThreadInfo->UserTime.QuadPart = UInt32x32To64(Thread->Tcb.UserTime,
|
|
KeMaximumIncrement);
|
|
|
|
ThreadInfo->CreateTime = Thread->CreateTime;
|
|
ThreadInfo->WaitTime = Thread->Tcb.WaitTime;
|
|
ThreadInfo->ClientId = Thread->Cid;
|
|
ThreadInfo->ThreadState = Thread->Tcb.State;
|
|
ThreadInfo->WaitReason = Thread->Tcb.WaitReason;
|
|
ThreadInfo->Priority = Thread->Tcb.Priority;
|
|
ThreadInfo->BasePriority = Thread->Tcb.BasePriority;
|
|
ThreadInfo->ContextSwitches = Thread->Tcb.ContextSwitches;
|
|
ThreadInfo->StartAddress = Thread->StartAddress;
|
|
}
|
|
|
|
#ifdef i386
|
|
extern ULONG ExVdmOpcodeDispatchCounts[256];
|
|
extern ULONG VdmBopCount;
|
|
extern ULONG ExVdmSegmentNotPresent;
|
|
|
|
#if defined(ALLOC_PRAGMA)
|
|
#pragma alloc_text(PAGE, ExpGetInstemulInformation)
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
ExpGetInstemulInformation(
|
|
OUT PSYSTEM_VDM_INSTEMUL_INFO Info
|
|
)
|
|
{
|
|
SYSTEM_VDM_INSTEMUL_INFO LocalInfo;
|
|
|
|
LocalInfo.VdmOpcode0F = ExVdmOpcodeDispatchCounts[VDM_INDEX_0F];
|
|
LocalInfo.OpcodeESPrefix = ExVdmOpcodeDispatchCounts[VDM_INDEX_ESPrefix];
|
|
LocalInfo.OpcodeCSPrefix = ExVdmOpcodeDispatchCounts[VDM_INDEX_CSPrefix];
|
|
LocalInfo.OpcodeSSPrefix = ExVdmOpcodeDispatchCounts[VDM_INDEX_SSPrefix];
|
|
LocalInfo.OpcodeDSPrefix = ExVdmOpcodeDispatchCounts[VDM_INDEX_DSPrefix];
|
|
LocalInfo.OpcodeFSPrefix = ExVdmOpcodeDispatchCounts[VDM_INDEX_FSPrefix];
|
|
LocalInfo.OpcodeGSPrefix = ExVdmOpcodeDispatchCounts[VDM_INDEX_GSPrefix];
|
|
LocalInfo.OpcodeOPER32Prefix= ExVdmOpcodeDispatchCounts[VDM_INDEX_OPER32Prefix];
|
|
LocalInfo.OpcodeADDR32Prefix= ExVdmOpcodeDispatchCounts[VDM_INDEX_ADDR32Prefix];
|
|
LocalInfo.OpcodeINSB = ExVdmOpcodeDispatchCounts[VDM_INDEX_INSB];
|
|
LocalInfo.OpcodeINSW = ExVdmOpcodeDispatchCounts[VDM_INDEX_INSW];
|
|
LocalInfo.OpcodeOUTSB = ExVdmOpcodeDispatchCounts[VDM_INDEX_OUTSB];
|
|
LocalInfo.OpcodeOUTSW = ExVdmOpcodeDispatchCounts[VDM_INDEX_OUTSW];
|
|
LocalInfo.OpcodePUSHF = ExVdmOpcodeDispatchCounts[VDM_INDEX_PUSHF];
|
|
LocalInfo.OpcodePOPF = ExVdmOpcodeDispatchCounts[VDM_INDEX_POPF];
|
|
LocalInfo.OpcodeINTnn = ExVdmOpcodeDispatchCounts[VDM_INDEX_INTnn];
|
|
LocalInfo.OpcodeINTO = ExVdmOpcodeDispatchCounts[VDM_INDEX_INTO];
|
|
LocalInfo.OpcodeIRET = ExVdmOpcodeDispatchCounts[VDM_INDEX_IRET];
|
|
LocalInfo.OpcodeINBimm = ExVdmOpcodeDispatchCounts[VDM_INDEX_INBimm];
|
|
LocalInfo.OpcodeINWimm = ExVdmOpcodeDispatchCounts[VDM_INDEX_INWimm];
|
|
LocalInfo.OpcodeOUTBimm = ExVdmOpcodeDispatchCounts[VDM_INDEX_OUTBimm];
|
|
LocalInfo.OpcodeOUTWimm = ExVdmOpcodeDispatchCounts[VDM_INDEX_OUTWimm];
|
|
LocalInfo.OpcodeINB = ExVdmOpcodeDispatchCounts[VDM_INDEX_INB];
|
|
LocalInfo.OpcodeINW = ExVdmOpcodeDispatchCounts[VDM_INDEX_INW];
|
|
LocalInfo.OpcodeOUTB = ExVdmOpcodeDispatchCounts[VDM_INDEX_OUTB];
|
|
LocalInfo.OpcodeOUTW = ExVdmOpcodeDispatchCounts[VDM_INDEX_OUTW];
|
|
LocalInfo.OpcodeLOCKPrefix = ExVdmOpcodeDispatchCounts[VDM_INDEX_LOCKPrefix];
|
|
LocalInfo.OpcodeREPNEPrefix = ExVdmOpcodeDispatchCounts[VDM_INDEX_REPNEPrefix];
|
|
LocalInfo.OpcodeREPPrefix = ExVdmOpcodeDispatchCounts[VDM_INDEX_REPPrefix];
|
|
LocalInfo.OpcodeHLT = ExVdmOpcodeDispatchCounts[VDM_INDEX_HLT];
|
|
LocalInfo.OpcodeCLI = ExVdmOpcodeDispatchCounts[VDM_INDEX_CLI];
|
|
LocalInfo.OpcodeSTI = ExVdmOpcodeDispatchCounts[VDM_INDEX_STI];
|
|
LocalInfo.BopCount = VdmBopCount;
|
|
LocalInfo.SegmentNotPresent = ExVdmSegmentNotPresent;
|
|
|
|
RtlMoveMemory(Info,&LocalInfo,sizeof(LocalInfo));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
#if i386 && !FPO
|
|
NTSTATUS
|
|
ExpGetStackTraceInformation (
|
|
OUT PVOID SystemInformation,
|
|
IN ULONG SystemInformationLength,
|
|
OUT PULONG ReturnLength OPTIONAL
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PRTL_PROCESS_BACKTRACES BackTraceInformation = (PRTL_PROCESS_BACKTRACES)SystemInformation;
|
|
PRTL_PROCESS_BACKTRACE_INFORMATION BackTraceInfo;
|
|
PSTACK_TRACE_DATABASE DataBase;
|
|
PRTL_STACK_TRACE_ENTRY p, *pp;
|
|
ULONG RequiredLength, n;
|
|
|
|
DataBase = RtlpAcquireStackTraceDataBase();
|
|
if (DataBase == NULL) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
DataBase->DumpInProgress = TRUE;
|
|
RtlpReleaseStackTraceDataBase();
|
|
try {
|
|
RequiredLength = FIELD_OFFSET( RTL_PROCESS_BACKTRACES, BackTraces );
|
|
if (SystemInformationLength < RequiredLength) {
|
|
Status = STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
else {
|
|
BackTraceInformation->CommittedMemory =
|
|
(ULONG)DataBase->CurrentUpperCommitLimit - (ULONG)DataBase->CommitBase;
|
|
BackTraceInformation->ReservedMemory =
|
|
(ULONG)DataBase->EntryIndexArray - (ULONG)DataBase->CommitBase;
|
|
BackTraceInformation->NumberOfBackTraceLookups = DataBase->NumberOfEntriesLookedUp;
|
|
n = DataBase->NumberOfEntriesAdded;
|
|
BackTraceInformation->NumberOfBackTraces = n;
|
|
}
|
|
|
|
RequiredLength += (sizeof( *BackTraceInfo ) * n);
|
|
if (SystemInformationLength < RequiredLength) {
|
|
Status = STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
else {
|
|
Status = STATUS_SUCCESS;
|
|
BackTraceInfo = &BackTraceInformation->BackTraces[ 0 ];
|
|
pp = DataBase->EntryIndexArray;
|
|
while (n--) {
|
|
p = *--pp;
|
|
BackTraceInfo->SymbolicBackTrace = NULL;
|
|
BackTraceInfo->TraceCount = p->TraceCount;
|
|
BackTraceInfo->Index = p->Index;
|
|
BackTraceInfo->Depth = p->Depth;
|
|
RtlMoveMemory( BackTraceInfo->BackTrace,
|
|
p->BackTrace,
|
|
p->Depth * sizeof( PVOID )
|
|
);
|
|
BackTraceInfo++;
|
|
}
|
|
}
|
|
}
|
|
finally {
|
|
DataBase->DumpInProgress = FALSE;
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT(ReturnLength)) {
|
|
*ReturnLength = RequiredLength;
|
|
}
|
|
return Status;
|
|
}
|
|
#endif // i386 && !FPO
|
|
|
|
NTSTATUS
|
|
ExpGetLockInformation (
|
|
OUT PVOID SystemInformation,
|
|
IN ULONG SystemInformationLength,
|
|
OUT PULONG Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns information about all the ERESOURCE locks
|
|
in the system.
|
|
|
|
Arguments:
|
|
|
|
SystemInformation - A pointer to a buffer which receives the specified
|
|
information.
|
|
|
|
SystemInformationLength - Specifies the length in bytes of the system
|
|
information buffer.
|
|
|
|
Length - An optional pointer which, if specified, receives the
|
|
number of bytes placed in the system information buffer.
|
|
|
|
|
|
Return Value:
|
|
|
|
Returns one of the following status codes:
|
|
|
|
STATUS_SUCCESS - normal, successful completion.
|
|
|
|
STATUS_INVALID_INFO_CLASS - The SystemInformationClass parameter
|
|
did not specify a valid value.
|
|
|
|
STATUS_INFO_LENGTH_MISMATCH - The value of the SystemInformationLength
|
|
parameter did not match the length required for the information
|
|
class requested by the SystemInformationClass parameter.
|
|
|
|
STATUS_ACCESS_VIOLATION - Either the SystemInformation buffer pointer
|
|
or the Length pointer value specified an invalid address.
|
|
|
|
STATUS_WORKING_SET_QUOTA - The process does not have sufficient
|
|
working set to lock the specified output structure in memory.
|
|
|
|
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources exist
|
|
for this request to complete.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRTL_PROCESS_LOCKS LockInfo;
|
|
PVOID LockVariable;
|
|
NTSTATUS Status;
|
|
|
|
|
|
*Length = 0;
|
|
|
|
LockInfo = (PRTL_PROCESS_LOCKS)
|
|
ExLockUserBuffer( SystemInformation,
|
|
SystemInformationLength,
|
|
&LockVariable
|
|
);
|
|
if (LockInfo == NULL) {
|
|
return( STATUS_ACCESS_VIOLATION );
|
|
}
|
|
|
|
MmLockPagableSectionByHandle (ExPageLockHandle);
|
|
try {
|
|
|
|
Status = ExQuerySystemLockInformation( LockInfo,
|
|
SystemInformationLength,
|
|
Length
|
|
);
|
|
}
|
|
finally {
|
|
ExUnlockUserBuffer( LockVariable );
|
|
MmUnlockPagableImageSection(ExPageLockHandle);
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
NTSTATUS
|
|
ExpGetLookasideInformation (
|
|
OUT PVOID Buffer,
|
|
IN ULONG BufferLength,
|
|
OUT PULONG Length
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns pool lookaside list and and general lookaside
|
|
list information.
|
|
|
|
Arguments:
|
|
|
|
Buffer - Supplies a pointer to the buffer which receives the lookaside
|
|
list information.
|
|
|
|
BufferLength - Supplies the length of the information buffer in bytes.
|
|
|
|
Length - Supplies a pointer to a variable that receives the length of
|
|
lookaside information returned.
|
|
|
|
Return Value:
|
|
|
|
Returns one of the following status codes:
|
|
|
|
STATUS_SUCCESS - Normal, successful completion.
|
|
|
|
STATUS_ACCESS_VIOLATION - The buffer could not be locked in memory.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PVOID BufferLock;
|
|
PLIST_ENTRY Entry;
|
|
ULONG Index;
|
|
KIRQL OldIrql;
|
|
ULONG Limit;
|
|
PSYSTEM_LOOKASIDE_INFORMATION Lookaside;
|
|
ULONG Number;
|
|
PNPAGED_LOOKASIDE_LIST NPagedLookaside;
|
|
PPAGED_LOOKASIDE_LIST PagedLookaside;
|
|
PSMALL_POOL_LOOKASIDE PoolLookaside;
|
|
PKSPIN_LOCK SpinLock;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Compute the number of lookaside entries and set the return status to
|
|
// success.
|
|
//
|
|
|
|
Limit = BufferLength / sizeof(SYSTEM_LOOKASIDE_INFORMATION);
|
|
Number = 0;
|
|
Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// If the number of lookaside entries to return is not zero, then collect
|
|
// the lookaside information.
|
|
//
|
|
|
|
if (Limit != 0) {
|
|
if ((Lookaside =
|
|
(PSYSTEM_LOOKASIDE_INFORMATION)ExLockUserBuffer(Buffer,
|
|
BufferLength,
|
|
&BufferLock)) == NULL) {
|
|
Status = STATUS_ACCESS_VIOLATION;
|
|
|
|
} else {
|
|
MmLockPagableSectionByHandle(ExPageLockHandle);
|
|
|
|
//
|
|
// Copy nonpaged pool lookaside information to information buffer.
|
|
//
|
|
|
|
Index = 0;
|
|
PoolLookaside = &ExpSmallNPagedPoolLookasideLists[0];
|
|
do {
|
|
Lookaside->CurrentDepth = PoolLookaside->SListHead.Depth;
|
|
Lookaside->MaximumDepth = PoolLookaside->Depth;
|
|
Lookaside->TotalAllocates = PoolLookaside->TotalAllocates;
|
|
Lookaside->AllocateMisses =
|
|
PoolLookaside->TotalAllocates - PoolLookaside->AllocateHits;
|
|
|
|
Lookaside->TotalFrees = PoolLookaside->TotalFrees;
|
|
Lookaside->FreeMisses =
|
|
PoolLookaside->TotalFrees - PoolLookaside->FreeHits;
|
|
|
|
Lookaside->Type = 0;
|
|
Lookaside->Tag = 'looP';
|
|
Lookaside->Size = (Index + 1) * 32;
|
|
Number += 1;
|
|
if (Number == Limit) {
|
|
goto Finish2;
|
|
}
|
|
|
|
Index += 1;
|
|
Lookaside += 1;
|
|
PoolLookaside += 1;
|
|
} while (Index < POOL_SMALL_LISTS);
|
|
|
|
//
|
|
// Copy paged pool lookaside information to information buffer.
|
|
//
|
|
|
|
#if !defined(_PPC_)
|
|
|
|
Index = 0;
|
|
PoolLookaside = &ExpSmallPagedPoolLookasideLists[0];
|
|
do {
|
|
Lookaside->CurrentDepth = PoolLookaside->SListHead.Depth;
|
|
Lookaside->MaximumDepth = PoolLookaside->Depth;
|
|
Lookaside->TotalAllocates = PoolLookaside->TotalAllocates;
|
|
Lookaside->AllocateMisses =
|
|
PoolLookaside->TotalAllocates - PoolLookaside->AllocateHits;
|
|
|
|
Lookaside->TotalFrees = PoolLookaside->TotalFrees;
|
|
Lookaside->FreeMisses =
|
|
PoolLookaside->TotalFrees - PoolLookaside->FreeHits;
|
|
|
|
Lookaside->Type = 1;
|
|
Lookaside->Tag = 'looP';
|
|
Lookaside->Size = (Index + 1) * 32;
|
|
Number += 1;
|
|
if (Number == Limit) {
|
|
goto Finish2;
|
|
}
|
|
|
|
Index += 1;
|
|
Lookaside += 1;
|
|
PoolLookaside += 1;
|
|
} while (Index < POOL_SMALL_LISTS);
|
|
|
|
#endif
|
|
|
|
//
|
|
// Copy nonpaged general lookaside information to buffer.
|
|
//
|
|
|
|
SpinLock = &ExNPagedLookasideLock;
|
|
ExAcquireSpinLock(SpinLock, &OldIrql);
|
|
Entry = ExNPagedLookasideListHead.Flink;
|
|
while (Entry != &ExNPagedLookasideListHead) {
|
|
NPagedLookaside = CONTAINING_RECORD(Entry,
|
|
NPAGED_LOOKASIDE_LIST,
|
|
L.ListEntry);
|
|
|
|
Lookaside->CurrentDepth = NPagedLookaside->L.ListHead.Depth;
|
|
Lookaside->MaximumDepth = NPagedLookaside->L.Depth;
|
|
Lookaside->TotalAllocates = NPagedLookaside->L.TotalAllocates;
|
|
Lookaside->AllocateMisses = NPagedLookaside->L.AllocateMisses;
|
|
Lookaside->TotalFrees = NPagedLookaside->L.TotalFrees;
|
|
Lookaside->FreeMisses = NPagedLookaside->L.FreeMisses;
|
|
Lookaside->Type = 0;
|
|
Lookaside->Tag = NPagedLookaside->L.Tag;
|
|
Lookaside->Size = NPagedLookaside->L.Size;
|
|
Number += 1;
|
|
if (Number == Limit) {
|
|
goto Finish1;
|
|
}
|
|
|
|
Entry = Entry->Flink;
|
|
Lookaside += 1;
|
|
}
|
|
|
|
ExReleaseSpinLock(SpinLock, OldIrql);
|
|
|
|
//
|
|
// Copy paged general lookaside information to buffer.
|
|
//
|
|
|
|
SpinLock = &ExPagedLookasideLock;
|
|
ExAcquireSpinLock(SpinLock, &OldIrql);
|
|
Entry = ExPagedLookasideListHead.Flink;
|
|
while (Entry != &ExPagedLookasideListHead) {
|
|
PagedLookaside = CONTAINING_RECORD(Entry,
|
|
PAGED_LOOKASIDE_LIST,
|
|
L.ListEntry);
|
|
|
|
Lookaside->CurrentDepth = PagedLookaside->L.ListHead.Depth;
|
|
Lookaside->MaximumDepth = PagedLookaside->L.Depth;
|
|
Lookaside->TotalAllocates = PagedLookaside->L.TotalAllocates;
|
|
Lookaside->AllocateMisses = PagedLookaside->L.AllocateMisses;
|
|
Lookaside->TotalFrees = PagedLookaside->L.TotalFrees;
|
|
Lookaside->FreeMisses = PagedLookaside->L.FreeMisses;
|
|
Lookaside->Type = 1;
|
|
Lookaside->Tag = PagedLookaside->L.Tag;
|
|
Lookaside->Size = PagedLookaside->L.Size;
|
|
Number += 1;
|
|
if (Number == Limit) {
|
|
goto Finish1;
|
|
}
|
|
|
|
Entry = Entry->Flink;
|
|
Lookaside += 1;
|
|
}
|
|
|
|
Finish1:
|
|
ExReleaseSpinLock(SpinLock, OldIrql);
|
|
|
|
//
|
|
// Unlock user buffer and page lock image section.
|
|
//
|
|
|
|
Finish2:
|
|
MmUnlockPagableImageSection(ExPageLockHandle);
|
|
ExUnlockUserBuffer(BufferLock);
|
|
}
|
|
}
|
|
|
|
*Length = Number * sizeof(SYSTEM_LOOKASIDE_INFORMATION);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ExpGetPoolInformation(
|
|
IN POOL_TYPE PoolType,
|
|
OUT PVOID SystemInformation,
|
|
IN ULONG SystemInformationLength,
|
|
OUT PULONG Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns information about the specified type of pool memory.
|
|
|
|
Arguments:
|
|
|
|
SystemInformation - A pointer to a buffer which receives the specified
|
|
information.
|
|
|
|
SystemInformationLength - Specifies the length in bytes of the system
|
|
information buffer.
|
|
|
|
Length - An optional pointer which, if specified, receives the
|
|
number of bytes placed in the system information buffer.
|
|
|
|
|
|
Return Value:
|
|
|
|
Returns one of the following status codes:
|
|
|
|
STATUS_SUCCESS - normal, successful completion.
|
|
|
|
STATUS_INVALID_INFO_CLASS - The SystemInformationClass parameter
|
|
did not specify a valid value.
|
|
|
|
STATUS_INFO_LENGTH_MISMATCH - The value of the SystemInformationLength
|
|
parameter did not match the length required for the information
|
|
class requested by the SystemInformationClass parameter.
|
|
|
|
STATUS_ACCESS_VIOLATION - Either the SystemInformation buffer pointer
|
|
or the Length pointer value specified an invalid address.
|
|
|
|
STATUS_WORKING_SET_QUOTA - The process does not have sufficient
|
|
working set to lock the specified output structure in memory.
|
|
|
|
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources exist
|
|
for this request to complete.
|
|
|
|
--*/
|
|
|
|
{
|
|
#if DBG || (i386 && !FPO)
|
|
|
|
//
|
|
// Only works on checked builds or free x86 builds with FPO turned off
|
|
// See comment in mm\allocpag.c
|
|
//
|
|
|
|
PSYSTEM_POOL_INFORMATION PoolInfo;
|
|
PVOID LockVariable;
|
|
NTSTATUS Status;
|
|
|
|
|
|
*Length = 0;
|
|
|
|
PoolInfo = (PSYSTEM_POOL_INFORMATION)
|
|
ExLockUserBuffer( SystemInformation,
|
|
SystemInformationLength,
|
|
&LockVariable
|
|
);
|
|
if (PoolInfo == NULL) {
|
|
return( STATUS_ACCESS_VIOLATION );
|
|
}
|
|
|
|
MmLockPagableSectionByHandle (ExPageLockHandle);
|
|
try {
|
|
Status = ExSnapShotPool( PoolType,
|
|
PoolInfo,
|
|
SystemInformationLength,
|
|
Length
|
|
);
|
|
|
|
}
|
|
finally {
|
|
ExUnlockUserBuffer( LockVariable );
|
|
MmUnlockPagableImageSection(ExPageLockHandle);
|
|
}
|
|
|
|
return( Status );
|
|
#else
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
#endif // DBG || (i386 && !FPO)
|
|
}
|
|
|
|
NTSTATUS
|
|
ExpGetHandleInformation(
|
|
OUT PVOID SystemInformation,
|
|
IN ULONG SystemInformationLength,
|
|
OUT PULONG Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns information about the open handles in the system.
|
|
|
|
Arguments:
|
|
|
|
SystemInformation - A pointer to a buffer which receives the specified
|
|
information.
|
|
|
|
SystemInformationLength - Specifies the length in bytes of the system
|
|
information buffer.
|
|
|
|
Length - An optional pointer which, if specified, receives the
|
|
number of bytes placed in the system information buffer.
|
|
|
|
|
|
Return Value:
|
|
|
|
Returns one of the following status codes:
|
|
|
|
STATUS_SUCCESS - normal, successful completion.
|
|
|
|
STATUS_INVALID_INFO_CLASS - The SystemInformationClass parameter
|
|
did not specify a valid value.
|
|
|
|
STATUS_INFO_LENGTH_MISMATCH - The value of the SystemInformationLength
|
|
parameter did not match the length required for the information
|
|
class requested by the SystemInformationClass parameter.
|
|
|
|
STATUS_ACCESS_VIOLATION - Either the SystemInformation buffer pointer
|
|
or the Length pointer value specified an invalid address.
|
|
|
|
STATUS_WORKING_SET_QUOTA - The process does not have sufficient
|
|
working set to lock the specified output structure in memory.
|
|
|
|
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources exist
|
|
for this request to complete.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSYSTEM_HANDLE_INFORMATION HandleInfo;
|
|
PVOID LockVariable;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
*Length = 0;
|
|
|
|
HandleInfo = (PSYSTEM_HANDLE_INFORMATION)
|
|
ExLockUserBuffer( SystemInformation,
|
|
SystemInformationLength,
|
|
&LockVariable
|
|
);
|
|
if (HandleInfo == NULL) {
|
|
return( STATUS_ACCESS_VIOLATION );
|
|
}
|
|
|
|
try {
|
|
Status = ObGetHandleInformation( HandleInfo,
|
|
SystemInformationLength,
|
|
Length
|
|
);
|
|
|
|
}
|
|
finally {
|
|
ExUnlockUserBuffer( LockVariable );
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
NTSTATUS
|
|
ExpGetObjectInformation(
|
|
OUT PVOID SystemInformation,
|
|
IN ULONG SystemInformationLength,
|
|
OUT PULONG Length
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns information about the objects in the system.
|
|
|
|
Arguments:
|
|
|
|
SystemInformation - A pointer to a buffer which receives the specified
|
|
information.
|
|
|
|
SystemInformationLength - Specifies the length in bytes of the system
|
|
information buffer.
|
|
|
|
Length - An optional pointer which, if specified, receives the
|
|
number of bytes placed in the system information buffer.
|
|
|
|
|
|
Return Value:
|
|
|
|
Returns one of the following status codes:
|
|
|
|
STATUS_SUCCESS - normal, successful completion.
|
|
|
|
STATUS_INVALID_INFO_CLASS - The SystemInformationClass parameter
|
|
did not specify a valid value.
|
|
|
|
STATUS_INFO_LENGTH_MISMATCH - The value of the SystemInformationLength
|
|
parameter did not match the length required for the information
|
|
class requested by the SystemInformationClass parameter.
|
|
|
|
STATUS_ACCESS_VIOLATION - Either the SystemInformation buffer pointer
|
|
or the Length pointer value specified an invalid address.
|
|
|
|
STATUS_WORKING_SET_QUOTA - The process does not have sufficient
|
|
working set to lock the specified output structure in memory.
|
|
|
|
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources exist
|
|
for this request to complete.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSYSTEM_OBJECTTYPE_INFORMATION ObjectInfo;
|
|
PVOID LockVariable;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
*Length = 0;
|
|
|
|
ObjectInfo = (PSYSTEM_OBJECTTYPE_INFORMATION)
|
|
ExLockUserBuffer( SystemInformation,
|
|
SystemInformationLength,
|
|
&LockVariable
|
|
);
|
|
if (ObjectInfo == NULL) {
|
|
return( STATUS_ACCESS_VIOLATION );
|
|
}
|
|
|
|
try {
|
|
Status = ObGetObjectInformation( SystemInformation,
|
|
ObjectInfo,
|
|
SystemInformationLength,
|
|
Length
|
|
);
|
|
|
|
}
|
|
finally {
|
|
ExUnlockUserBuffer( LockVariable );
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ExpGetPoolTagInfo (
|
|
IN PVOID SystemInformation,
|
|
IN ULONG SystemInformationLength,
|
|
IN OUT PULONG ReturnLength OPTIONAL
|
|
)
|
|
|
|
{
|
|
ULONG totalBytes = 0;
|
|
ULONG i;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PSYSTEM_POOLTAG_INFORMATION taginfo;
|
|
PSYSTEM_POOLTAG poolTag;
|
|
|
|
PAGED_CODE();
|
|
if (!PoolTrackTable) {
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
taginfo = (PSYSTEM_POOLTAG_INFORMATION)SystemInformation;
|
|
poolTag = &taginfo->TagInfo[0];
|
|
totalBytes = FIELD_OFFSET(SYSTEM_POOLTAG_INFORMATION, TagInfo);
|
|
taginfo->Count = 0;
|
|
for (i = 0; i < MAX_TRACKER_TABLE; i++) {
|
|
if (PoolTrackTable[i].Key != 0) {
|
|
taginfo->Count += 1;
|
|
totalBytes += sizeof (SYSTEM_POOLTAG);
|
|
if (SystemInformationLength < totalBytes) {
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|
} else {
|
|
poolTag->TagUlong = PoolTrackTable[i].Key;
|
|
poolTag->PagedAllocs = PoolTrackTable[i].PagedAllocs;
|
|
poolTag->PagedFrees = PoolTrackTable[i].PagedFrees;
|
|
poolTag->PagedUsed = PoolTrackTable[i].PagedBytes;
|
|
poolTag->NonPagedAllocs = PoolTrackTable[i].NonPagedAllocs;
|
|
poolTag->NonPagedFrees = PoolTrackTable[i].NonPagedFrees;
|
|
poolTag->NonPagedUsed = PoolTrackTable[i].NonPagedBytes;
|
|
poolTag += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT(ReturnLength)) {
|
|
*ReturnLength = totalBytes;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ExpQueryModuleInformation(
|
|
IN PLIST_ENTRY LoadOrderListHead,
|
|
IN PLIST_ENTRY UserModeLoadOrderListHead,
|
|
OUT PRTL_PROCESS_MODULES ModuleInformation,
|
|
IN ULONG ModuleInformationLength,
|
|
OUT PULONG ReturnLength OPTIONAL
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG RequiredLength;
|
|
PLIST_ENTRY Next;
|
|
PLIST_ENTRY Next1;
|
|
PRTL_PROCESS_MODULE_INFORMATION ModuleInfo;
|
|
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
|
|
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry1;
|
|
ANSI_STRING AnsiString;
|
|
PUCHAR s;
|
|
|
|
RequiredLength = FIELD_OFFSET( RTL_PROCESS_MODULES, Modules );
|
|
if (ModuleInformationLength < RequiredLength) {
|
|
Status = STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
else {
|
|
ModuleInformation->NumberOfModules = 0;
|
|
ModuleInfo = &ModuleInformation->Modules[ 0 ];
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
Next = LoadOrderListHead->Flink;
|
|
while ( Next != LoadOrderListHead ) {
|
|
LdrDataTableEntry = CONTAINING_RECORD( Next,
|
|
LDR_DATA_TABLE_ENTRY,
|
|
InLoadOrderLinks
|
|
);
|
|
|
|
RequiredLength += sizeof( RTL_PROCESS_MODULE_INFORMATION );
|
|
if (ModuleInformationLength < RequiredLength) {
|
|
Status = STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
else {
|
|
|
|
ModuleInfo->MappedBase = NULL;
|
|
ModuleInfo->ImageBase = LdrDataTableEntry->DllBase;
|
|
ModuleInfo->ImageSize = LdrDataTableEntry->SizeOfImage;
|
|
ModuleInfo->Flags = LdrDataTableEntry->Flags;
|
|
ModuleInfo->LoadCount = LdrDataTableEntry->LoadCount;
|
|
|
|
ModuleInfo->LoadOrderIndex = (USHORT)(ModuleInformation->NumberOfModules);
|
|
ModuleInfo->InitOrderIndex = 0;
|
|
AnsiString.Buffer = ModuleInfo->FullPathName;
|
|
AnsiString.Length = 0;
|
|
AnsiString.MaximumLength = sizeof( ModuleInfo->FullPathName );
|
|
RtlUnicodeStringToAnsiString( &AnsiString,
|
|
&LdrDataTableEntry->FullDllName,
|
|
FALSE
|
|
);
|
|
s = AnsiString.Buffer + AnsiString.Length;
|
|
while (s > AnsiString.Buffer && *--s) {
|
|
if (*s == (UCHAR)OBJ_NAME_PATH_SEPARATOR) {
|
|
s++;
|
|
break;
|
|
}
|
|
}
|
|
ModuleInfo->OffsetToFileName = (USHORT)(s - AnsiString.Buffer);
|
|
|
|
ModuleInfo++;
|
|
}
|
|
|
|
ModuleInformation->NumberOfModules++;
|
|
Next = Next->Flink;
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT( UserModeLoadOrderListHead )) {
|
|
Next = UserModeLoadOrderListHead->Flink;
|
|
while ( Next != UserModeLoadOrderListHead ) {
|
|
LdrDataTableEntry = CONTAINING_RECORD( Next,
|
|
LDR_DATA_TABLE_ENTRY,
|
|
InLoadOrderLinks
|
|
);
|
|
|
|
RequiredLength += sizeof( RTL_PROCESS_MODULE_INFORMATION );
|
|
if (ModuleInformationLength < RequiredLength) {
|
|
Status = STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
else {
|
|
ModuleInfo->MappedBase = NULL;
|
|
ModuleInfo->ImageBase = LdrDataTableEntry->DllBase;
|
|
ModuleInfo->ImageSize = LdrDataTableEntry->SizeOfImage;
|
|
ModuleInfo->Flags = LdrDataTableEntry->Flags;
|
|
ModuleInfo->LoadCount = LdrDataTableEntry->LoadCount;
|
|
|
|
ModuleInfo->LoadOrderIndex = (USHORT)(ModuleInformation->NumberOfModules);
|
|
|
|
ModuleInfo->InitOrderIndex = ModuleInfo->LoadOrderIndex;
|
|
|
|
AnsiString.Buffer = ModuleInfo->FullPathName;
|
|
AnsiString.Length = 0;
|
|
AnsiString.MaximumLength = sizeof( ModuleInfo->FullPathName );
|
|
RtlUnicodeStringToAnsiString( &AnsiString,
|
|
&LdrDataTableEntry->FullDllName,
|
|
FALSE
|
|
);
|
|
s = AnsiString.Buffer + AnsiString.Length;
|
|
while (s > AnsiString.Buffer && *--s) {
|
|
if (*s == (UCHAR)OBJ_NAME_PATH_SEPARATOR) {
|
|
s++;
|
|
break;
|
|
}
|
|
}
|
|
ModuleInfo->OffsetToFileName = (USHORT)(s - AnsiString.Buffer);
|
|
|
|
ModuleInfo++;
|
|
}
|
|
|
|
ModuleInformation->NumberOfModules++;
|
|
Next = Next->Flink;
|
|
}
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT(ReturnLength)) {
|
|
*ReturnLength = RequiredLength;
|
|
}
|
|
return( Status );
|
|
}
|
|
|
|
BOOLEAN
|
|
ExIsProcessorFeaturePresent(
|
|
ULONG ProcessorFeature
|
|
)
|
|
{
|
|
BOOLEAN rv;
|
|
|
|
if ( ProcessorFeature < PROCESSOR_FEATURE_MAX ) {
|
|
rv = SharedUserData->ProcessorFeatures[ProcessorFeature];
|
|
}
|
|
else {
|
|
rv = FALSE;
|
|
}
|
|
return rv;
|
|
}
|