Counter Strike : Global Offensive Source Code
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.

665 lines
20 KiB

  1. //===== Copyright � 2010, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: Virtual memory sections management!
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "pch_tier0.h"
  8. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  9. //#include <malloc.h>
  10. #include <string.h>
  11. #include "tier0/dbg.h"
  12. #include "tier0/stacktools.h"
  13. #include "tier0/memalloc.h"
  14. #include "tier0/memvirt.h"
  15. #include "tier0/fasttimer.h"
  16. #include "mem_helpers.h"
  17. #ifdef PLATFORM_WINDOWS_PC
  18. #undef WIN32_LEAN_AND_MEAN
  19. #include <windows.h>
  20. #include <crtdbg.h>
  21. #endif
  22. #ifdef OSX
  23. #include <malloc/malloc.h>
  24. #include <stdlib.h>
  25. #endif
  26. #include <map>
  27. #include <set>
  28. #include <limits.h>
  29. #include "tier0/threadtools.h"
  30. #ifdef _X360
  31. #include "xbox/xbox_console.h"
  32. #endif
  33. #ifdef _PS3
  34. #include "tls_ps3.h"
  35. #include "memoverride_ps3.h"
  36. #include "sys/memory.h"
  37. #include "sys/mempool.h"
  38. #include "sys/process.h"
  39. #include "sys/vm.h"
  40. #endif
  41. CInterlockedInt VmmMsgFlag = 0; // Prevents re-entrancy within VmmMsg (printf allocates a large buffer!)
  42. #ifdef _DEBUG
  43. #ifdef _PS3 // _DEBUG
  44. #define VmmMsg( mutex, ... ) ( (VmmMsgFlag|mutex.GetOwnerId()) ? 0 : ( ++VmmMsgFlag, Msg( __VA_ARGS__ ), VmmMsgFlag-- ) )
  45. #else
  46. #define VmmMsg( mutex, ... ) ( (VmmMsgFlag|mutex.GetOwnerId()) ? 0 : ( ++VmmMsgFlag, DevMsg( __VA_ARGS__ ), VmmMsgFlag-- ) )
  47. #endif
  48. #else
  49. #define VmmMsg( mutex, ... ) ((void)0)
  50. #endif
  51. #if 0
  52. #define TRACE_CALL( ... ) do { FILE *fPs3Trace = fopen( "/app_home/tracevmm.txt", "a+" ); if( fPs3Trace ) { fprintf( fPs3Trace, __VA_ARGS__ ); fclose( fPs3Trace ); } } while( 0 )
  53. #else
  54. #define TRACE_CALL( ... ) ((void)0)
  55. #endif
  56. #ifdef _PS3
  57. #define VIRTUAL_MEMORY_MANAGER_SUPPORTED
  58. #define VMM_SYSTEM_PAGE_POLICY SYS_MEMORY_PAGE_SIZE_64K
  59. #define VMM_SYSTEM_PAGE_ALLOCFLAGS SYS_MEMORY_GRANULARITY_64K
  60. #define VMM_POLICY_SYS_VM 0 // sys_vm_* system is really buggy and console sometimes hardlocks or crashes in OS
  61. #define VMM_POLICY_SYS_MMAPPER 1 // sys_mmapper_* seems fairly stable
  62. #define VMM_POLICY_SYS_VM_NO_RETURN 1 // looks like returning memory under sys_vm_* is the main reason for hardlocks
  63. #if !(VMM_POLICY_SYS_VM) == !(VMM_POLICY_SYS_MMAPPER)
  64. #error
  65. #endif
  66. class CVirtualMemoryManager
  67. {
  68. public:
  69. CVirtualMemoryManager();
  70. ~CVirtualMemoryManager() { Shutdown(); }
  71. void Shutdown();
  72. IVirtualMemorySection * AllocateVirtualMemorySection( size_t numMaxBytes );
  73. IVirtualMemorySection * NewSection( byte *pBase, size_t numMaxBytes );
  74. IVirtualMemorySection * GetMemorySectionForAddress( void *pAddress );
  75. void GetStats( size_t &nReserved, size_t &nReservedMax, size_t &nCommitted, size_t &nCommittedMax );
  76. public:
  77. byte *m_pBase; // base address of the virtual address space
  78. size_t m_nPhysicalSize; // physical memory committed
  79. size_t m_nPhysicalSizeMax; // physical memory committed (max since startup)
  80. size_t m_nVirtualSize; // virtual memory reserved
  81. size_t m_nVirtualSizeMax; // virtual memory reserved (max since startup)
  82. #if VMM_POLICY_SYS_VM
  83. size_t m_nSparePhysicalSize; // physical memory that has been decommitted, but hasn't been returned
  84. #endif
  85. #if VMM_POLICY_SYS_MMAPPER
  86. sys_memory_t m_sysMemPages[ VMM_VIRTUAL_SIZE / VMM_PAGE_SIZE ];
  87. #endif
  88. IVirtualMemorySection *m_uiVirtualMap[ VMM_VIRTUAL_SIZE / VMM_PAGE_SIZE ]; // map of pages to sections
  89. uint32 m_uiCommitMask[ VMM_VIRTUAL_SIZE / ( VMM_PAGE_SIZE * 32 ) ]; // mask of committed pages
  90. inline bool CommitTest( int iPage ) const
  91. {
  92. const uint32 mask = 1u << ( iPage % 32 ), &word = m_uiCommitMask[ iPage / 32 ];
  93. return !!( word & mask );
  94. }
  95. inline void CommitSet( int iPage, bool bSet )
  96. {
  97. uint32 mask = 1u << ( iPage % 32 ), &word = m_uiCommitMask[ iPage / 32 ];
  98. word = ( word & ~mask ) | ( bSet ? mask : 0 );
  99. }
  100. inline size_t CountReservedPages()
  101. {
  102. size_t uResult = 0;
  103. for ( int k = 0; k < VMM_VIRTUAL_SIZE / VMM_PAGE_SIZE; ++ k )
  104. uResult += m_uiVirtualMap[k] ? 1 : 0;
  105. return uResult;
  106. }
  107. inline size_t CountCommittedPages() const
  108. {
  109. size_t uResult = 0;
  110. for ( int k = 0; k < VMM_VIRTUAL_SIZE / VMM_PAGE_SIZE; ++ k )
  111. uResult += CommitTest(k) ? 1 : 0;
  112. return uResult;
  113. }
  114. public:
  115. bool CommitPage( byte *pbAddress );
  116. bool DecommitPage( byte *pbAddress );
  117. public:
  118. CThreadFastMutex m_Mutex;
  119. };
  120. static CVirtualMemoryManager& GetVirtualMemoryManager()
  121. {
  122. static CVirtualMemoryManager s_VirtualMemoryManager;
  123. return s_VirtualMemoryManager;
  124. }
  125. CVirtualMemoryManager::CVirtualMemoryManager() :
  126. m_pBase( NULL ),
  127. #if VMM_POLICY_SYS_VM
  128. m_nSparePhysicalSize( 0 ),
  129. #endif
  130. m_nPhysicalSize( 0 ),
  131. m_nPhysicalSizeMax( 0 ),
  132. m_nVirtualSize( 0 ),
  133. m_nVirtualSizeMax( 0 )
  134. {
  135. memset( m_uiVirtualMap, 0, sizeof( m_uiVirtualMap ) );
  136. memset( m_uiCommitMask, 0, sizeof( m_uiCommitMask ) );
  137. #if VMM_POLICY_SYS_VM
  138. TRACE_CALL( "sys_vm_memory_map( 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X ) ... ",
  139. VMM_VIRTUAL_SIZE,
  140. VMM_PAGE_SIZE,
  141. SYS_MEMORY_CONTAINER_ID_INVALID,
  142. VMM_SYSTEM_PAGE_POLICY,
  143. SYS_VM_POLICY_AUTO_RECOMMENDED,
  144. reinterpret_cast<sys_addr_t*>( &m_pBase ) );
  145. int retval = sys_vm_memory_map(
  146. VMM_VIRTUAL_SIZE,
  147. VMM_PAGE_SIZE,
  148. SYS_MEMORY_CONTAINER_ID_INVALID,
  149. VMM_SYSTEM_PAGE_POLICY,
  150. SYS_VM_POLICY_AUTO_RECOMMENDED,
  151. reinterpret_cast<sys_addr_t*>( &m_pBase ) );
  152. TRACE_CALL( "ret = 0x%08X, base = 0x%08X\n",
  153. retval, m_pBase );
  154. if ( retval < CELL_OK || !m_pBase )
  155. {
  156. Error( "sys_vm_memory_map failed( size=%dKB, page=%dKB ), error=0x%08X\n", VMM_VIRTUAL_SIZE / VMM_KB, VMM_PAGE_SIZE / VMM_KB, retval );
  157. Assert( 0 );
  158. m_pBase = NULL;
  159. return;
  160. }
  161. #endif
  162. #if VMM_POLICY_SYS_MMAPPER
  163. memset( m_sysMemPages, 0, sizeof( m_sysMemPages ) );
  164. TRACE_CALL( "sys_mmapper_allocate_address( 0x%08X, 0x%08X, 0x%08X, 0x%08X ) ... ",
  165. VMM_VIRTUAL_SIZE,
  166. VMM_SYSTEM_PAGE_POLICY,
  167. VMM_VIRTUAL_SIZE,
  168. reinterpret_cast<sys_addr_t*>( &m_pBase ) );
  169. int retval = sys_mmapper_allocate_address(
  170. VMM_VIRTUAL_SIZE,
  171. VMM_SYSTEM_PAGE_POLICY,
  172. VMM_VIRTUAL_SIZE,
  173. reinterpret_cast<sys_addr_t*>( &m_pBase ) );
  174. TRACE_CALL( "ret = 0x%08X, base = 0x%08X\n",
  175. retval, m_pBase );
  176. if ( retval < CELL_OK || !m_pBase )
  177. {
  178. Error( "sys_mmapper_allocate_address failed( size=%dKB, page=%dKB ), error=0x%08X\n", VMM_VIRTUAL_SIZE / VMM_KB, VMM_PAGE_SIZE / VMM_KB, retval );
  179. Assert( 0 );
  180. m_pBase = NULL;
  181. return;
  182. }
  183. #endif
  184. VmmMsg( m_Mutex, "Virtual Memory Manager: reserved %uKB block at address 0x%08X.\n", VMM_VIRTUAL_SIZE / VMM_KB, m_pBase );
  185. }
  186. void CVirtualMemoryManager::Shutdown()
  187. {
  188. if ( !m_pBase )
  189. return;
  190. if ( m_nPhysicalSize )
  191. {
  192. VmmMsg( m_Mutex, "Virtual Memory Manager: shutting down with %uKB allocated!\n", m_nPhysicalSize / VMM_KB );
  193. }
  194. #if VMM_POLICY_SYS_VM
  195. TRACE_CALL( "sys_vm_unmap( 0x%08X ) ... ", (sys_addr_t) m_pBase );
  196. int retval = sys_vm_unmap( (sys_addr_t) m_pBase );
  197. TRACE_CALL( "ret = 0x%08X\n", retval );
  198. #endif
  199. #if VMM_POLICY_SYS_MMAPPER
  200. TRACE_CALL( "sys_mmapper_free_address( 0x%08X ) ... ", (sys_addr_t) m_pBase );
  201. int retval = sys_mmapper_free_address( (sys_addr_t) m_pBase );
  202. TRACE_CALL( "ret = 0x%08X\n", retval );
  203. #endif
  204. VmmMsg( m_Mutex, "Virtual Memory Manager: unmapped %uKB block at address 0x%08X (result=0x%08X).\n", VMM_VIRTUAL_SIZE / VMM_KB, m_pBase, retval );
  205. m_pBase = NULL;
  206. }
  207. IVirtualMemorySection * CVirtualMemoryManager::GetMemorySectionForAddress( void *pAddress )
  208. {
  209. Assert( ( pAddress >= m_pBase ) && ( pAddress < ( m_pBase + VMM_VIRTUAL_SIZE ) ) );
  210. int iPage = ( (byte*)pAddress - m_pBase ) / VMM_PAGE_SIZE;
  211. return m_uiVirtualMap[ iPage ];
  212. }
  213. IVirtualMemorySection * CVirtualMemoryManager::AllocateVirtualMemorySection( size_t numMaxBytes )
  214. {
  215. Assert( m_pBase );
  216. if ( !m_pBase )
  217. return NULL;
  218. // Find the smallest free block with size >= numMaxBytes
  219. IVirtualMemorySection *pResult = NULL;
  220. int iGoodPage = -1;
  221. int iGoodSize = 0;
  222. size_t numPages = numMaxBytes / VMM_PAGE_SIZE;
  223. if ( !numPages )
  224. return NULL;
  225. {
  226. AUTO_LOCK( m_Mutex );
  227. // TODO: fill the address range with reserved/free sections (so we iterate 50 sections rather than 8000 pages!)
  228. for ( int iTryPage = 0; iTryPage < VMM_VIRTUAL_SIZE / VMM_PAGE_SIZE; ++ iTryPage )
  229. {
  230. if ( m_uiVirtualMap[ iTryPage ] )
  231. continue; // page is taken
  232. int iTryPageStart = iTryPage;
  233. int iTryPageStride = 1;
  234. for ( ++ iTryPage; iTryPage < VMM_VIRTUAL_SIZE / VMM_PAGE_SIZE; ++ iTryPage, ++ iTryPageStride )
  235. if ( m_uiVirtualMap[ iTryPage ] )
  236. break;
  237. if ( iTryPageStride < numPages )
  238. continue;
  239. if ( ( iGoodPage < 0 ) || ( iTryPageStride < iGoodSize ) )
  240. {
  241. iGoodPage = iTryPageStart;
  242. iGoodSize = iTryPageStride;
  243. }
  244. }
  245. if ( iGoodPage >= 0 )
  246. {
  247. byte *pbAddress = m_pBase + iGoodPage * VMM_PAGE_SIZE;
  248. pResult = NewSection( pbAddress, numMaxBytes );
  249. m_nVirtualSize += numPages*VMM_PAGE_SIZE;
  250. m_nVirtualSizeMax = MAX( m_nVirtualSize, m_nVirtualSizeMax );
  251. // Mark pages used
  252. for ( int k = 0; k < numPages; ++ k )
  253. m_uiVirtualMap[ iGoodPage + k ] = pResult;
  254. }
  255. }
  256. if ( pResult )
  257. {
  258. // NOTE: don't spew while the mutex is held!
  259. VmmMsg( m_Mutex, "Virtual Memory Manager [ reserved %uKB, committed %uKB ]: new reservation %uKB @ 0x%08X\n",
  260. CountReservedPages()*VMM_PAGE_SIZE / VMM_KB,
  261. CountCommittedPages()*VMM_PAGE_SIZE / VMM_KB,
  262. numMaxBytes / VMM_KB, pResult->GetBaseAddress() );
  263. return pResult;
  264. }
  265. Error( "CVirtualMemoryManager::AllocateVirtualMemorySection has no memory for %u bytes!\n", numMaxBytes );
  266. Assert( 0 );
  267. return NULL;
  268. }
  269. bool CVirtualMemoryManager::CommitPage( byte *pbAddress )
  270. {
  271. Assert( m_pBase );
  272. int iPage = ( pbAddress - m_pBase ) / VMM_PAGE_SIZE;
  273. if ( CommitTest( iPage ) )
  274. return true;
  275. CommitSet( iPage, true );
  276. #if VMM_POLICY_SYS_VM
  277. if ( m_nPhysicalSize )
  278. {
  279. if ( m_nSparePhysicalSize > 0 )
  280. {
  281. m_nSparePhysicalSize -= VMM_PAGE_SIZE;
  282. }
  283. else
  284. {
  285. TRACE_CALL( "sys_vm_append_memory( 0x%08X, 0x%08X ) ... ", (sys_addr_t) m_pBase, VMM_PAGE_SIZE );
  286. int retval = sys_vm_append_memory( (sys_addr_t) m_pBase, VMM_PAGE_SIZE );
  287. TRACE_CALL( "ret = 0x%08X\n", retval );
  288. if ( retval < CELL_OK )
  289. {
  290. VmmMsg( m_Mutex, "Virtual Memory Manager: CommitPage: sys_vm_append_memory failed (result=0x%08X), %uKB committed so far.\n", retval, m_nPhysicalSize / VMM_KB );
  291. return false;
  292. }
  293. }
  294. }
  295. m_nPhysicalSize += VMM_PAGE_SIZE;
  296. m_nPhysicalSizeMax = MAX( m_nPhysicalSize, m_nPhysicalSizeMax );
  297. TRACE_CALL( "sys_vm_touch( 0x%08X, 0x%08X ) ... ", (sys_addr_t) pbAddress, VMM_PAGE_SIZE );
  298. int retval = sys_vm_touch( (sys_addr_t) pbAddress, VMM_PAGE_SIZE );
  299. TRACE_CALL( "ret = 0x%08X\n", retval );
  300. if ( retval < CELL_OK )
  301. {
  302. VmmMsg( m_Mutex, "Virtual Memory Manager: CommitPage: sys_vm_touch failed (result=0x%08X), %uKB committed so far.\n", retval, m_nPhysicalSize / VMM_KB );
  303. return false;
  304. }
  305. #endif
  306. #if VMM_POLICY_SYS_MMAPPER
  307. TRACE_CALL( "sys_mmapper_allocate_memory( 0x%08X, 0x%08X, page=%d ) ... ", VMM_PAGE_SIZE, VMM_SYSTEM_PAGE_ALLOCFLAGS, iPage );
  308. int retval = sys_mmapper_allocate_memory( VMM_PAGE_SIZE, VMM_SYSTEM_PAGE_ALLOCFLAGS, &m_sysMemPages[iPage] );
  309. TRACE_CALL( "ret = 0x%08X, mem = 0x%08X\n", retval, m_sysMemPages[iPage] );
  310. if ( retval < CELL_OK )
  311. {
  312. VmmMsg( m_Mutex, "Virtual Memory Manager: CommitPage: sys_mmapper_allocate_memory failed (result=0x%08X), %uKB committed so far.\n", retval, m_nPhysicalSize / VMM_KB );
  313. return false;
  314. }
  315. m_nPhysicalSize += VMM_PAGE_SIZE;
  316. m_nPhysicalSizeMax = MAX( m_nPhysicalSize, m_nPhysicalSizeMax );
  317. TRACE_CALL( "sys_mmapper_map_memory( 0x%08X, 0x%08X, 0x%08X, page=%d ) ... ", (sys_addr_t) pbAddress, m_sysMemPages[iPage], SYS_MEMORY_PROT_READ_WRITE, iPage );
  318. retval = sys_mmapper_map_memory( (sys_addr_t) pbAddress, m_sysMemPages[iPage], SYS_MEMORY_PROT_READ_WRITE );
  319. TRACE_CALL( "ret = 0x%08X\n", retval );
  320. if ( retval < CELL_OK )
  321. {
  322. VmmMsg( m_Mutex, "Virtual Memory Manager: CommitPage: sys_mmapper_map_memory failed (result=0x%08X), %uKB committed so far.\n", retval, m_nPhysicalSize / VMM_KB );
  323. return false;
  324. }
  325. #endif
  326. return true;
  327. }
  328. bool CVirtualMemoryManager::DecommitPage( byte *pbAddress )
  329. {
  330. Assert( m_pBase );
  331. int iPage = ( pbAddress - m_pBase ) / VMM_PAGE_SIZE;
  332. if ( !CommitTest( iPage ) )
  333. return false;
  334. CommitSet( iPage, false );
  335. #if VMM_POLICY_SYS_VM
  336. TRACE_CALL( "sys_vm_invalidate( 0x%08X, 0x%08X ) ... ", (sys_addr_t) pbAddress, VMM_PAGE_SIZE );
  337. int retval = sys_vm_invalidate( (sys_addr_t) pbAddress, VMM_PAGE_SIZE );
  338. TRACE_CALL( "ret = 0x%08X\n", retval );
  339. if ( retval < CELL_OK )
  340. {
  341. VmmMsg( m_Mutex, "Virtual Memory Manager: DecommitPage: sys_vm_invalidate failed (result=0x%08X), %uKB committed so far.\n", retval, m_nPhysicalSize / VMM_KB );
  342. return false;
  343. }
  344. m_nPhysicalSize -= VMM_PAGE_SIZE;
  345. #if VMM_POLICY_SYS_VM_NO_RETURN
  346. m_nSparePhysicalSize += VMM_PAGE_SIZE;
  347. return false;
  348. #else
  349. return m_nPhysicalSize >= VMM_PAGE_SIZE;
  350. #endif
  351. #endif
  352. #if VMM_POLICY_SYS_MMAPPER
  353. TRACE_CALL( "sys_mmapper_unmap_memory( 0x%08X, 0x%08X, page=%d ) ... ", (sys_addr_t) pbAddress, m_sysMemPages[iPage], iPage );
  354. int retval = sys_mmapper_unmap_memory( (sys_addr_t) pbAddress, &m_sysMemPages[iPage] );
  355. TRACE_CALL( "ret = 0x%08X, mem = 0x%08X\n", retval, m_sysMemPages[iPage] );
  356. if ( retval < CELL_OK )
  357. {
  358. VmmMsg( m_Mutex, "Virtual Memory Manager: DecommitPage: sys_mmapper_unmap_memory failed (result=0x%08X), %uKB committed so far.\n", retval, m_nPhysicalSize / VMM_KB );
  359. return false;
  360. }
  361. TRACE_CALL( "sys_mmapper_free_memory( 0x%08X, page=%d ) ... ", m_sysMemPages[iPage], iPage );
  362. retval = sys_mmapper_free_memory( m_sysMemPages[iPage] );
  363. TRACE_CALL( "ret = 0x%08X\n", retval );
  364. m_sysMemPages[iPage] = 0;
  365. if ( retval < CELL_OK )
  366. {
  367. VmmMsg( m_Mutex, "Virtual Memory Manager: DecommitPage: sys_mmapper_free_memory failed (result=0x%08X), %uKB committed so far.\n", retval, m_nPhysicalSize / VMM_KB );
  368. return false;
  369. }
  370. m_nPhysicalSize -= VMM_PAGE_SIZE;
  371. return true;
  372. #endif
  373. }
  374. void CVirtualMemoryManager::GetStats( size_t &nReserved, size_t &nReservedMax, size_t &nCommitted, size_t &nCommittedMax )
  375. {
  376. AUTO_LOCK( m_Mutex );
  377. nReserved = m_nVirtualSize;
  378. nReservedMax = m_nVirtualSizeMax;
  379. nCommitted = m_nPhysicalSize;
  380. nCommittedMax = m_nPhysicalSizeMax;
  381. }
  382. class CVirtualMemorySectionImpl : public IVirtualMemorySection
  383. {
  384. public:
  385. CVirtualMemorySectionImpl( byte *pbAddress, size_t numMaxBytes ) :
  386. m_pBase( pbAddress ),
  387. m_numMaxBytes( numMaxBytes ),
  388. m_numPhysical( 0 )
  389. {
  390. }
  391. // Information about memory section
  392. virtual void * GetBaseAddress() { return m_pBase; }
  393. virtual size_t GetPageSize() { return VMM_PAGE_SIZE; }
  394. virtual size_t GetTotalSize() { return m_numMaxBytes; }
  395. // Functions to manage physical memory mapped to virtual memory
  396. virtual bool CommitPages( void *pvBase, size_t numBytes );
  397. virtual void DecommitPages( void *pvBase, size_t numBytes );
  398. bool CommitPages_Inner( void *pvBase, size_t numBytes );
  399. // Release the physical memory and associated virtual address space
  400. virtual void Release();
  401. byte *m_pBase;
  402. size_t m_numMaxBytes;
  403. size_t m_numPhysical;
  404. };
  405. bool CVirtualMemorySectionImpl::CommitPages_Inner( void *pvBase, size_t numBytes )
  406. {
  407. Assert( pvBase >= m_pBase );
  408. Assert( ( (byte*)pvBase ) + numBytes <= m_pBase + m_numMaxBytes );
  409. {
  410. AUTO_LOCK( GetVirtualMemoryManager().m_Mutex );
  411. int startPage = ( ( (byte*)pvBase ) - m_pBase ) / VMM_PAGE_SIZE;
  412. int endPage = ( ( (byte*)pvBase ) + numBytes + ( VMM_PAGE_SIZE - 1 ) - m_pBase ) / VMM_PAGE_SIZE;
  413. for ( int k = startPage; k < endPage; k++ )
  414. {
  415. if ( !GetVirtualMemoryManager().CommitPage( m_pBase + k * VMM_PAGE_SIZE ) )
  416. {
  417. // Failure! Decommit the pages we have committed so far:
  418. for ( k = k - 1; k >= startPage; k-- )
  419. {
  420. GetVirtualMemoryManager().DecommitPage( m_pBase + k * VMM_PAGE_SIZE );
  421. }
  422. return false;
  423. }
  424. }
  425. #if VMM_POLICY_SYS_VM
  426. TRACE_CALL( "sys_vm_sync( 0x%08X, 0x%08X ) ... ", (sys_addr_t) pvBase, numBytes );
  427. int retval = sys_vm_sync( (sys_addr_t) pvBase, numBytes );
  428. TRACE_CALL( "ret = 0x%08X\n", retval );
  429. if ( retval < CELL_OK )
  430. {
  431. VmmMsg( GetVirtualMemoryManager().m_Mutex, "Virtual Memory Manager: CommitPages: sys_vm_sync failed (result=0x%08X).\n", retval );
  432. return false;
  433. }
  434. #endif
  435. }
  436. // NOTE: we don't spew while the mutex is held!
  437. VmmMsg( GetVirtualMemoryManager().m_Mutex, "Virtual Memory Manager [ reserved %uKB, committed %uKB ]: committed %uKB @ 0x%08X\n",
  438. GetVirtualMemoryManager().CountReservedPages() * VMM_PAGE_SIZE / VMM_KB,
  439. GetVirtualMemoryManager().CountCommittedPages() * VMM_PAGE_SIZE / VMM_KB,
  440. numBytes / VMM_KB, pvBase );
  441. return true;
  442. }
  443. bool CVirtualMemorySectionImpl::CommitPages( void *pvBase, size_t numBytes )
  444. {
  445. if ( CommitPages_Inner( pvBase, numBytes ) )
  446. return true;
  447. // On failure, compact the heap and try one last time:
  448. Msg( "\n\nVirtual Memory Manager: COMMIT FAILED! (%d) Last-ditch effort: compacting the heap and re-trying...\n", numBytes );
  449. g_pMemAllocInternalPS3->CompactHeap();
  450. bool success = CommitPages_Inner( pvBase, numBytes );
  451. if ( !success )
  452. {
  453. Msg( "Virtual Memory Manager: COMMIT FAILED! (%d) Fatal error.\n\n\n", numBytes );
  454. g_pMemAllocInternalPS3->OutOfMemory( numBytes );
  455. }
  456. Msg("\n\n");
  457. return success;
  458. }
  459. void CVirtualMemorySectionImpl::DecommitPages( void *pvBase, size_t numBytes )
  460. {
  461. Assert( pvBase >= m_pBase );
  462. Assert( ( (byte*)pvBase ) + numBytes <= m_pBase + m_numMaxBytes );
  463. {
  464. AUTO_LOCK( GetVirtualMemoryManager().m_Mutex );
  465. int numPagesDecommitted = 0;
  466. for ( int k = ( ( (byte*)pvBase ) - m_pBase ) / VMM_PAGE_SIZE;
  467. m_pBase + k * VMM_PAGE_SIZE < ( (byte*)pvBase ) + numBytes; ++ k )
  468. {
  469. numPagesDecommitted += !!GetVirtualMemoryManager().DecommitPage( m_pBase + k * VMM_PAGE_SIZE );
  470. }
  471. #if VMM_POLICY_SYS_VM
  472. TRACE_CALL( "sys_vm_sync( 0x%08X, 0x%08X ) ... ", (sys_addr_t) pvBase, numBytes );
  473. int retval = sys_vm_sync( (sys_addr_t) pvBase, numBytes );
  474. TRACE_CALL( "ret = 0x%08X\n", retval );
  475. if ( retval < CELL_OK )
  476. {
  477. VmmMsg( GetVirtualMemoryManager().m_Mutex, "Virtual Memory Manager: DecommitPages: sys_vm_sync failed (result=0x%08X).\n", retval );
  478. }
  479. if ( numPagesDecommitted > 0 )
  480. {
  481. TRACE_CALL( "sys_vm_return_memory( 0x%08X, 0x%08X ) ... ", (sys_addr_t) GetVirtualMemoryManager().m_pBase, numPagesDecommitted * VMM_PAGE_SIZE );
  482. retval = sys_vm_return_memory( (sys_addr_t) GetVirtualMemoryManager().m_pBase, numPagesDecommitted * VMM_PAGE_SIZE );
  483. TRACE_CALL( "ret = 0x%08X\n", retval );
  484. if ( retval < CELL_OK )
  485. {
  486. VmmMsg( GetVirtualMemoryManager().m_Mutex, "Virtual Memory Manager: DecommitPages: sys_vm_return_memory failed (result=0x%08X).\n", retval );
  487. }
  488. }
  489. #endif
  490. }
  491. // NOTE: we don't spew while the mutex is held!
  492. VmmMsg( GetVirtualMemoryManager().m_Mutex, "Virtual Memory Manager [ reserved %uKB, committed %uKB ]: decommitted %uKB @ 0x%08X\n",
  493. GetVirtualMemoryManager().CountReservedPages() * VMM_PAGE_SIZE / VMM_KB,
  494. GetVirtualMemoryManager().CountCommittedPages() * VMM_PAGE_SIZE / VMM_KB,
  495. numBytes / VMM_KB, pvBase );
  496. }
  497. void CVirtualMemorySectionImpl::Release()
  498. {
  499. DecommitPages( m_pBase, m_numMaxBytes );
  500. {
  501. AUTO_LOCK( GetVirtualMemoryManager().m_Mutex );
  502. int iPageStart = ( m_pBase - GetVirtualMemoryManager().m_pBase ) / VMM_PAGE_SIZE;
  503. for ( int k = 0; m_pBase + k * VMM_PAGE_SIZE < m_pBase + m_numMaxBytes; ++ k )
  504. {
  505. Assert( GetVirtualMemoryManager().m_uiVirtualMap[ iPageStart + k ] == this );
  506. GetVirtualMemoryManager().m_uiVirtualMap[ iPageStart + k ] = NULL;
  507. GetVirtualMemoryManager().m_nVirtualSize -= VMM_PAGE_SIZE;
  508. }
  509. }
  510. // NOTE: we don't spew while the mutex is held!
  511. VmmMsg( GetVirtualMemoryManager().m_Mutex, "Virtual Memory Manager [ reserved %uKB, committed %uKB ]: released %uKB @ 0x%08X\n",
  512. GetVirtualMemoryManager().CountReservedPages() * VMM_PAGE_SIZE / VMM_KB,
  513. GetVirtualMemoryManager().CountCommittedPages() * VMM_PAGE_SIZE / VMM_KB,
  514. m_numMaxBytes / VMM_KB, m_pBase );
  515. delete this;
  516. }
  517. IVirtualMemorySection * CVirtualMemoryManager::NewSection( byte *pBase, size_t numMaxBytes )
  518. {
  519. return new CVirtualMemorySectionImpl( pBase, numMaxBytes );
  520. }
  521. #endif
  522. #ifdef VIRTUAL_MEMORY_MANAGER_SUPPORTED
  523. IVirtualMemorySection * VirtualMemoryManager_AllocateVirtualMemorySection( size_t numMaxBytes )
  524. {
  525. return GetVirtualMemoryManager().AllocateVirtualMemorySection( numMaxBytes );
  526. }
  527. void VirtualMemoryManager_Shutdown()
  528. {
  529. GetVirtualMemoryManager().Shutdown();
  530. }
  531. IVirtualMemorySection *GetMemorySectionForAddress( void *pAddress )
  532. {
  533. return GetVirtualMemoryManager().GetMemorySectionForAddress( pAddress );
  534. }
  535. void VirtualMemoryManager_GetStats( size_t &nReserved, size_t &nReservedMax, size_t &nCommitted, size_t &nCommittedMax )
  536. {
  537. GetVirtualMemoryManager().GetStats( nReserved, nReservedMax, nCommitted, nCommittedMax );
  538. }
  539. #else
  540. IVirtualMemorySection * VirtualMemoryManager_AllocateVirtualMemorySection( size_t numMaxBytes )
  541. {
  542. return NULL;
  543. }
  544. void VirtualMemoryManager_Shutdown()
  545. {
  546. }
  547. IVirtualMemorySection *GetMemorySectionForAddress( void *pAddress )
  548. {
  549. return NULL;
  550. }
  551. #endif
  552. #endif // !STEAM && !NO_MALLOC_OVERRIDE