/*++ 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 #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; iDataLength; 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; }