You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
310 lines
7.1 KiB
310 lines
7.1 KiB
//========= 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 |