source-engine/tier0/systeminformation.cpp
FluorescentCIAAfricanAmerican 3bf9df6b27 1
2020-04-22 12:56:21 -04:00

310 lines
7.1 KiB
C++

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