//========= 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 #include #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