diff options
Diffstat (limited to 'tier0/systeminformation.cpp')
| -rw-r--r-- | tier0/systeminformation.cpp | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/tier0/systeminformation.cpp b/tier0/systeminformation.cpp new file mode 100644 index 0000000..c26a2d1 --- /dev/null +++ b/tier0/systeminformation.cpp @@ -0,0 +1,310 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "pch_tier0.h" +#include "tier0/platform.h" +#include "tier0/systeminformation.h" + +#ifdef IS_WINDOWS_PC +#include <windows.h> +#include <tchar.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define PrivateType( xxx ) ValvePrivateType_##xxx + + typedef enum { SystemPerformanceInformation = 2 } + PrivateType( SYSTEM_INFORMATION_CLASS ); + + typedef LONG PrivateType( NTSTATUS ); + + typedef PrivateType( NTSTATUS ) ( WINAPI * PrivateType( NtQuerySystemInformation ) ) + ( + /*IN*/ PrivateType( SYSTEM_INFORMATION_CLASS ) SystemInformationClass, + /*OUT*/ PVOID SystemInformation, + /*IN*/ ULONG SystemInformationLength, + /*OUT*/ PULONG ReturnLength /*OPTIONAL*/ + ); + + typedef struct + { + LARGE_INTEGER IdleProcessTime; + LARGE_INTEGER IoTransferCount[3]; + ULONG IoOperationCount[3]; + ULONG AvailablePages; + ULONG CommittedPages; + ULONG CommitLimit; + ULONG u00683; + ULONG u00684; + ULONG u00685; + ULONG u00686; + ULONG u00687; + ULONG u00688; + ULONG u00689; + ULONG u00690; + ULONG u00691; + ULONG u00692; + ULONG u00693; + ULONG u00694; + ULONG u00695; + ULONG u00696; + ULONG PagedPoolPages; + ULONG NonPagedPoolPages; + ULONG PagedPoolAllocs; + ULONG PagedPoolFrees; + ULONG NonPagedPoolAllocs; + ULONG NonPagedPoolFrees; + ULONG FreeSystemPtes; + ULONG u00704; + ULONG u00705; + ULONG u00706; + ULONG NonPagedPoolLookasideHits; + ULONG PagedPoolLookasideHits; + ULONG FreePagedPoolPages; + ULONG u00710; + ULONG u00711; + ULONG u00712; + ULONG uCounters[34]; + } + PrivateType( SYSTEM_PERFORMANCE_INFORMATION ); + +#ifdef __cplusplus +} +#endif + +// +// Cached information about a dll proc +// +class CSysCallCacheEntry +{ +public: + CSysCallCacheEntry(); + ~CSysCallCacheEntry(); + +public: + bool IsInitialized() const; + SYSTEM_CALL_RESULT_t CallResult() const; + + SYSTEM_CALL_RESULT_t InitializeLoadModule( _TCHAR *pszModule, char *pszFunction ); + SYSTEM_CALL_RESULT_t InitializeFindModule( _TCHAR *pszModule, char *pszFunction ); + SYSTEM_CALL_RESULT_t InitializeFindProc( HMODULE hModule, char *pszFunction ); + + void SetFailed( SYSTEM_CALL_RESULT_t eResult ); + void Reset(); + + template < typename FN > + FN GetFunction() const; + +protected: + SYSTEM_CALL_RESULT_t m_eResult; + FARPROC m_pfnSysCall; + HMODULE m_hModule; + bool m_bInitialized; + bool m_bFreeModule; +}; + +struct CSysCallCacheEntry_LoadModule : public CSysCallCacheEntry +{ + CSysCallCacheEntry_LoadModule( _TCHAR *pszModule, char *pszFunction ) { InitializeLoadModule( pszModule, pszFunction ); } +}; +struct CSysCallCacheEntry_FindModule : public CSysCallCacheEntry +{ + CSysCallCacheEntry_FindModule( _TCHAR *pszModule, char *pszFunction ) { InitializeFindModule( pszModule, pszFunction ); } +}; +struct CSysCallCacheEntry_FindProc : public CSysCallCacheEntry +{ + CSysCallCacheEntry_FindProc( HMODULE hModule, char *pszFunction ) { InitializeFindProc( hModule, pszFunction ); } +}; + + + +CSysCallCacheEntry::CSysCallCacheEntry() : + m_eResult( SYSCALL_SUCCESS ), + m_pfnSysCall( NULL ), + m_hModule( NULL ), + m_bInitialized( false ), + m_bFreeModule( false ) +{ +} + +CSysCallCacheEntry::~CSysCallCacheEntry() +{ + Reset(); +} + +bool CSysCallCacheEntry::IsInitialized() const +{ + return m_bInitialized; +} + +SYSTEM_CALL_RESULT_t CSysCallCacheEntry::CallResult() const +{ + return m_eResult; +} + +SYSTEM_CALL_RESULT_t CSysCallCacheEntry::InitializeLoadModule( _TCHAR *pszModule, char *pszFunction ) +{ + m_bInitialized = true; + + m_hModule = ::LoadLibrary( pszModule ); + m_bFreeModule = true; + if ( !m_hModule ) + return m_eResult = SYSCALL_NODLL; + + return InitializeFindProc( m_hModule, pszFunction ); +} + +SYSTEM_CALL_RESULT_t CSysCallCacheEntry::InitializeFindModule( _TCHAR *pszModule, char *pszFunction ) +{ + m_bInitialized = true; + + m_hModule = ::GetModuleHandle( pszModule ); + m_bFreeModule = false; + if ( !m_hModule ) + return m_eResult = SYSCALL_NODLL; + + return InitializeFindProc( m_hModule, pszFunction ); +} + +SYSTEM_CALL_RESULT_t CSysCallCacheEntry::InitializeFindProc( HMODULE hModule, char *pszFunction ) +{ + m_bInitialized = true; + + m_pfnSysCall = GetProcAddress( hModule, pszFunction ); + if ( !m_pfnSysCall ) + return m_eResult = SYSCALL_NOPROC; + + return m_eResult = SYSCALL_SUCCESS; +} + +void CSysCallCacheEntry::Reset() +{ + if ( m_bInitialized ) + { + if ( m_bFreeModule && m_hModule ) + ::FreeLibrary( m_hModule ); + m_eResult = SYSCALL_SUCCESS; + m_hModule = NULL; + m_pfnSysCall = NULL; + m_bFreeModule = false; + m_bInitialized = false; + } +} + +void CSysCallCacheEntry::SetFailed( SYSTEM_CALL_RESULT_t eResult ) +{ + m_eResult = eResult; +} + +template < typename FN > +FN CSysCallCacheEntry::GetFunction() const +{ + return reinterpret_cast< FN >( m_pfnSysCall ); +} + + + +// +// Plat_GetMemPageSize +// Returns the size of a memory page in bytes. +// +unsigned long Plat_GetMemPageSize() +{ + return 4; // On 32-bit systems memory page size is 4 Kb +} + +// +// Plat_GetPagedPoolInfo +// Fills in the paged pool info structure if successful. +// +SYSTEM_CALL_RESULT_t Plat_GetPagedPoolInfo( PAGED_POOL_INFO_t *pPPI ) +{ + memset( pPPI, 0, sizeof( *pPPI ) ); + + static CSysCallCacheEntry_FindModule qsi( _T( "ntdll.dll" ), "NtQuerySystemInformation" ); + + if ( qsi.CallResult() != SYSCALL_SUCCESS ) + return qsi.CallResult(); + + static bool s_bOsVersionValid = false; + if ( !s_bOsVersionValid ) + { + s_bOsVersionValid = true; + OSVERSIONINFO osver; + memset( &osver, 0, sizeof( osver ) ); + osver.dwOSVersionInfoSize = sizeof( osver ); + GetVersionEx( &osver ); + + // We should run it only on Windows XP or Windows 2003 +#define MAKEVER( high, low ) DWORD( MAKELONG( low, high ) ) + DWORD dwOsVer = MAKEVER( osver.dwMajorVersion, osver.dwMinorVersion ); + if ( dwOsVer < MAKEVER( 5, 1 ) || // Earlier than WinXP + dwOsVer > MAKEVER( 5, 2 ) ) // Later than Win2003 (or 64-bit) + { + qsi.SetFailed( SYSCALL_UNSUPPORTED ); + } + + // Don't care for 64-bit Windows + CSysCallCacheEntry_FindModule wow64( _T( "kernel32.dll" ), "IsWow64Process" ); + if ( wow64.CallResult() == SYSCALL_SUCCESS ) + { + typedef BOOL ( WINAPI * PFNWOW64 )( HANDLE, PBOOL ); + BOOL b64 = FALSE; + if ( ( wow64.GetFunction< PFNWOW64 >() )( GetCurrentProcess(), &b64 ) && + b64 ) + { + qsi.SetFailed( SYSCALL_UNSUPPORTED ); + } + } + + if ( qsi.CallResult() != SYSCALL_SUCCESS ) + return qsi.CallResult(); + } + + // Invoke proc + PrivateType( SYSTEM_PERFORMANCE_INFORMATION ) spi = {}; + ULONG ulLength = sizeof( spi ); + PrivateType( NTSTATUS ) lResult = + ( qsi.GetFunction< PrivateType( NtQuerySystemInformation ) >() ) + ( SystemPerformanceInformation, &spi, ulLength, &ulLength ); + if ( lResult ) + return SYSCALL_FAILED; + + // Return the result + pPPI->numPagesUsed = spi.PagedPoolPages; + pPPI->numPagesFree = spi.FreePagedPoolPages; + return SYSCALL_SUCCESS; +} + + +#else + + +// +// Plat_GetMemPageSize +// Returns the size of a memory page in bytes. +// +unsigned long Plat_GetMemPageSize() +{ + return 4; // Assume unknown page size is 4 Kb +} + +// +// Plat_GetPagedPoolInfo +// Fills in the paged pool info structure if successful. +// +SYSTEM_CALL_RESULT_t Plat_GetPagedPoolInfo( PAGED_POOL_INFO_t *pPPI ) +{ + memset( pPPI, 0, sizeof( *pPPI ) ); + return SYSCALL_UNSUPPORTED; +} + + +#endif
\ No newline at end of file |