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
5 years ago
|
//========= 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
|