Team Fortress 2 Source Code as on 22/4/2020
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.

309 lines
7.1 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "pch_tier0.h"
  9. #include "tier0/platform.h"
  10. #include "tier0/systeminformation.h"
  11. #ifdef IS_WINDOWS_PC
  12. #include <windows.h>
  13. #include <tchar.h>
  14. #ifdef __cplusplus
  15. extern "C" {
  16. #endif
  17. #define PrivateType( xxx ) ValvePrivateType_##xxx
  18. typedef enum { SystemPerformanceInformation = 2 }
  19. PrivateType( SYSTEM_INFORMATION_CLASS );
  20. typedef LONG PrivateType( NTSTATUS );
  21. typedef PrivateType( NTSTATUS ) ( WINAPI * PrivateType( NtQuerySystemInformation ) )
  22. (
  23. /*IN*/ PrivateType( SYSTEM_INFORMATION_CLASS ) SystemInformationClass,
  24. /*OUT*/ PVOID SystemInformation,
  25. /*IN*/ ULONG SystemInformationLength,
  26. /*OUT*/ PULONG ReturnLength /*OPTIONAL*/
  27. );
  28. typedef struct
  29. {
  30. LARGE_INTEGER IdleProcessTime;
  31. LARGE_INTEGER IoTransferCount[3];
  32. ULONG IoOperationCount[3];
  33. ULONG AvailablePages;
  34. ULONG CommittedPages;
  35. ULONG CommitLimit;
  36. ULONG u00683;
  37. ULONG u00684;
  38. ULONG u00685;
  39. ULONG u00686;
  40. ULONG u00687;
  41. ULONG u00688;
  42. ULONG u00689;
  43. ULONG u00690;
  44. ULONG u00691;
  45. ULONG u00692;
  46. ULONG u00693;
  47. ULONG u00694;
  48. ULONG u00695;
  49. ULONG u00696;
  50. ULONG PagedPoolPages;
  51. ULONG NonPagedPoolPages;
  52. ULONG PagedPoolAllocs;
  53. ULONG PagedPoolFrees;
  54. ULONG NonPagedPoolAllocs;
  55. ULONG NonPagedPoolFrees;
  56. ULONG FreeSystemPtes;
  57. ULONG u00704;
  58. ULONG u00705;
  59. ULONG u00706;
  60. ULONG NonPagedPoolLookasideHits;
  61. ULONG PagedPoolLookasideHits;
  62. ULONG FreePagedPoolPages;
  63. ULONG u00710;
  64. ULONG u00711;
  65. ULONG u00712;
  66. ULONG uCounters[34];
  67. }
  68. PrivateType( SYSTEM_PERFORMANCE_INFORMATION );
  69. #ifdef __cplusplus
  70. }
  71. #endif
  72. //
  73. // Cached information about a dll proc
  74. //
  75. class CSysCallCacheEntry
  76. {
  77. public:
  78. CSysCallCacheEntry();
  79. ~CSysCallCacheEntry();
  80. public:
  81. bool IsInitialized() const;
  82. SYSTEM_CALL_RESULT_t CallResult() const;
  83. SYSTEM_CALL_RESULT_t InitializeLoadModule( _TCHAR *pszModule, char *pszFunction );
  84. SYSTEM_CALL_RESULT_t InitializeFindModule( _TCHAR *pszModule, char *pszFunction );
  85. SYSTEM_CALL_RESULT_t InitializeFindProc( HMODULE hModule, char *pszFunction );
  86. void SetFailed( SYSTEM_CALL_RESULT_t eResult );
  87. void Reset();
  88. template < typename FN >
  89. FN GetFunction() const;
  90. protected:
  91. SYSTEM_CALL_RESULT_t m_eResult;
  92. FARPROC m_pfnSysCall;
  93. HMODULE m_hModule;
  94. bool m_bInitialized;
  95. bool m_bFreeModule;
  96. };
  97. struct CSysCallCacheEntry_LoadModule : public CSysCallCacheEntry
  98. {
  99. CSysCallCacheEntry_LoadModule( _TCHAR *pszModule, char *pszFunction ) { InitializeLoadModule( pszModule, pszFunction ); }
  100. };
  101. struct CSysCallCacheEntry_FindModule : public CSysCallCacheEntry
  102. {
  103. CSysCallCacheEntry_FindModule( _TCHAR *pszModule, char *pszFunction ) { InitializeFindModule( pszModule, pszFunction ); }
  104. };
  105. struct CSysCallCacheEntry_FindProc : public CSysCallCacheEntry
  106. {
  107. CSysCallCacheEntry_FindProc( HMODULE hModule, char *pszFunction ) { InitializeFindProc( hModule, pszFunction ); }
  108. };
  109. CSysCallCacheEntry::CSysCallCacheEntry() :
  110. m_eResult( SYSCALL_SUCCESS ),
  111. m_pfnSysCall( NULL ),
  112. m_hModule( NULL ),
  113. m_bInitialized( false ),
  114. m_bFreeModule( false )
  115. {
  116. }
  117. CSysCallCacheEntry::~CSysCallCacheEntry()
  118. {
  119. Reset();
  120. }
  121. bool CSysCallCacheEntry::IsInitialized() const
  122. {
  123. return m_bInitialized;
  124. }
  125. SYSTEM_CALL_RESULT_t CSysCallCacheEntry::CallResult() const
  126. {
  127. return m_eResult;
  128. }
  129. SYSTEM_CALL_RESULT_t CSysCallCacheEntry::InitializeLoadModule( _TCHAR *pszModule, char *pszFunction )
  130. {
  131. m_bInitialized = true;
  132. m_hModule = ::LoadLibrary( pszModule );
  133. m_bFreeModule = true;
  134. if ( !m_hModule )
  135. return m_eResult = SYSCALL_NODLL;
  136. return InitializeFindProc( m_hModule, pszFunction );
  137. }
  138. SYSTEM_CALL_RESULT_t CSysCallCacheEntry::InitializeFindModule( _TCHAR *pszModule, char *pszFunction )
  139. {
  140. m_bInitialized = true;
  141. m_hModule = ::GetModuleHandle( pszModule );
  142. m_bFreeModule = false;
  143. if ( !m_hModule )
  144. return m_eResult = SYSCALL_NODLL;
  145. return InitializeFindProc( m_hModule, pszFunction );
  146. }
  147. SYSTEM_CALL_RESULT_t CSysCallCacheEntry::InitializeFindProc( HMODULE hModule, char *pszFunction )
  148. {
  149. m_bInitialized = true;
  150. m_pfnSysCall = GetProcAddress( hModule, pszFunction );
  151. if ( !m_pfnSysCall )
  152. return m_eResult = SYSCALL_NOPROC;
  153. return m_eResult = SYSCALL_SUCCESS;
  154. }
  155. void CSysCallCacheEntry::Reset()
  156. {
  157. if ( m_bInitialized )
  158. {
  159. if ( m_bFreeModule && m_hModule )
  160. ::FreeLibrary( m_hModule );
  161. m_eResult = SYSCALL_SUCCESS;
  162. m_hModule = NULL;
  163. m_pfnSysCall = NULL;
  164. m_bFreeModule = false;
  165. m_bInitialized = false;
  166. }
  167. }
  168. void CSysCallCacheEntry::SetFailed( SYSTEM_CALL_RESULT_t eResult )
  169. {
  170. m_eResult = eResult;
  171. }
  172. template < typename FN >
  173. FN CSysCallCacheEntry::GetFunction() const
  174. {
  175. return reinterpret_cast< FN >( m_pfnSysCall );
  176. }
  177. //
  178. // Plat_GetMemPageSize
  179. // Returns the size of a memory page in bytes.
  180. //
  181. unsigned long Plat_GetMemPageSize()
  182. {
  183. return 4; // On 32-bit systems memory page size is 4 Kb
  184. }
  185. //
  186. // Plat_GetPagedPoolInfo
  187. // Fills in the paged pool info structure if successful.
  188. //
  189. SYSTEM_CALL_RESULT_t Plat_GetPagedPoolInfo( PAGED_POOL_INFO_t *pPPI )
  190. {
  191. memset( pPPI, 0, sizeof( *pPPI ) );
  192. static CSysCallCacheEntry_FindModule qsi( _T( "ntdll.dll" ), "NtQuerySystemInformation" );
  193. if ( qsi.CallResult() != SYSCALL_SUCCESS )
  194. return qsi.CallResult();
  195. static bool s_bOsVersionValid = false;
  196. if ( !s_bOsVersionValid )
  197. {
  198. s_bOsVersionValid = true;
  199. OSVERSIONINFO osver;
  200. memset( &osver, 0, sizeof( osver ) );
  201. osver.dwOSVersionInfoSize = sizeof( osver );
  202. GetVersionEx( &osver );
  203. // We should run it only on Windows XP or Windows 2003
  204. #define MAKEVER( high, low ) DWORD( MAKELONG( low, high ) )
  205. DWORD dwOsVer = MAKEVER( osver.dwMajorVersion, osver.dwMinorVersion );
  206. if ( dwOsVer < MAKEVER( 5, 1 ) || // Earlier than WinXP
  207. dwOsVer > MAKEVER( 5, 2 ) ) // Later than Win2003 (or 64-bit)
  208. {
  209. qsi.SetFailed( SYSCALL_UNSUPPORTED );
  210. }
  211. // Don't care for 64-bit Windows
  212. CSysCallCacheEntry_FindModule wow64( _T( "kernel32.dll" ), "IsWow64Process" );
  213. if ( wow64.CallResult() == SYSCALL_SUCCESS )
  214. {
  215. typedef BOOL ( WINAPI * PFNWOW64 )( HANDLE, PBOOL );
  216. BOOL b64 = FALSE;
  217. if ( ( wow64.GetFunction< PFNWOW64 >() )( GetCurrentProcess(), &b64 ) &&
  218. b64 )
  219. {
  220. qsi.SetFailed( SYSCALL_UNSUPPORTED );
  221. }
  222. }
  223. if ( qsi.CallResult() != SYSCALL_SUCCESS )
  224. return qsi.CallResult();
  225. }
  226. // Invoke proc
  227. PrivateType( SYSTEM_PERFORMANCE_INFORMATION ) spi = {};
  228. ULONG ulLength = sizeof( spi );
  229. PrivateType( NTSTATUS ) lResult =
  230. ( qsi.GetFunction< PrivateType( NtQuerySystemInformation ) >() )
  231. ( SystemPerformanceInformation, &spi, ulLength, &ulLength );
  232. if ( lResult )
  233. return SYSCALL_FAILED;
  234. // Return the result
  235. pPPI->numPagesUsed = spi.PagedPoolPages;
  236. pPPI->numPagesFree = spi.FreePagedPoolPages;
  237. return SYSCALL_SUCCESS;
  238. }
  239. #else
  240. //
  241. // Plat_GetMemPageSize
  242. // Returns the size of a memory page in bytes.
  243. //
  244. unsigned long Plat_GetMemPageSize()
  245. {
  246. return 4; // Assume unknown page size is 4 Kb
  247. }
  248. //
  249. // Plat_GetPagedPoolInfo
  250. // Fills in the paged pool info structure if successful.
  251. //
  252. SYSTEM_CALL_RESULT_t Plat_GetPagedPoolInfo( PAGED_POOL_INFO_t *pPPI )
  253. {
  254. memset( pPPI, 0, sizeof( *pPPI ) );
  255. return SYSCALL_UNSUPPORTED;
  256. }
  257. #endif