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.

628 lines
15 KiB

  1. //================ Copyright (c) Valve Corporation. All Rights Reserved. ===========================
  2. //
  3. //
  4. //
  5. //==================================================================================================
  6. //--------------------------------------------------------------------------------------------------
  7. // Headers
  8. //--------------------------------------------------------------------------------------------------
  9. #include "sys/memory.h"
  10. #include "sysutil/sysutil_sysparam.h"
  11. #include "cell/sysmodule.h"
  12. #include "tier0/platform.h"
  13. #include "tier0/dbg.h"
  14. #include "tier1/utlbuffer.h"
  15. #include <sys/timer.h>
  16. #include <sys/spu_image.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <cell/cell_fs.h>
  20. #include <cell/atomic.h>
  21. #include <string.h>
  22. #include "ps3_pathinfo.h"
  23. #include <cell/spurs/control.h>
  24. #include "SpuMgr_ppu.h"
  25. #include "memdbgon.h"
  26. typedef uint32_t uint32;
  27. #define ASSERT Assert
  28. //--------------------------------------------------------------------------------------------------
  29. // Defines
  30. //--------------------------------------------------------------------------------------------------
  31. // Spu Mailbox Status Register
  32. // Described in CBE architecture chapter 8.6.3 SPU Mailbox Status Register (SPU_Mbox_Stat)
  33. #define SPU_IN_MBOX_COUNT_SHIFT (8)
  34. #define SPU_IN_MBOX_COUNT (0xFF << SPU_IN_MBOX_COUNT_SHIFT)
  35. #define SPU_OUT_MBOX_COUNT (0xFF)
  36. #define SPU_OUT_INTR_MBOX_COUNT_SHIFT (16)
  37. #define SPU_OUT_INTR_MBOX_COUNT (0xFF << SPU_OUT_INTR_MBOX_COUNT_SHIFT)
  38. //--------------------------------------------------------------------------------------------------
  39. // Globals
  40. //--------------------------------------------------------------------------------------------------
  41. // SPU manager instance
  42. SpuMgr gSpuMgr;
  43. //--------------------------------------------------------------------------------------------------
  44. // DmaCheckAlignment
  45. // Checks restrictions specified in SpuMgr::DmaGet
  46. //--------------------------------------------------------------------------------------------------
  47. int DmaCheckAlignment(uint32_t src, uint32_t dest, uint32_t size)
  48. {
  49. #if !defined( _CERT )
  50. uint32_t align = size;
  51. bool error = false;
  52. if (size >= 16 && ((size & 0xf) == 0))
  53. {
  54. align = 16;
  55. }
  56. else if (size == 8 || size == 4 || size == 2 || size == 1)
  57. {
  58. error = ((src & 0xF) != (dest & 0xF));
  59. }
  60. else
  61. {
  62. error = true; // bad size
  63. }
  64. return (!error && src && dest &&
  65. SPUMGR_IS_ALIGNED(src, align) &&
  66. SPUMGR_IS_ALIGNED(dest, align));
  67. #else //!_CERT
  68. return 1;
  69. #endif //!_CERT
  70. }
  71. //--------------------------------------------------------------------------------------------------
  72. // Internal functions
  73. //--------------------------------------------------------------------------------------------------
  74. //--------------------------------------------------------------------------------------------------
  75. // handle_syscall
  76. //
  77. // interrupt handler to handle SPU interrupts
  78. // see Handle SPU Interrupts Lv2-Uders_manual_e P34
  79. //--------------------------------------------------------------------------------------------------
  80. void handle_syscall (uint64_t arg)
  81. {
  82. sys_raw_spu_t id = arg;
  83. uint64_t stat;
  84. int ret;
  85. #ifndef _CERT
  86. g_snRawSPULockHandler();
  87. #endif
  88. // Create a tag to handle class 2 interrupt, SPU halts fall in
  89. // this category
  90. ret = sys_raw_spu_get_int_stat(id, 2, &stat);
  91. if (ret)
  92. {
  93. #ifndef _CERT
  94. g_snRawSPUUnlockHandler();
  95. #endif
  96. sys_interrupt_thread_eoi();
  97. }
  98. //
  99. // SPU Stop-and-Signal Instruction Trap
  100. // This interrupt occurs when the SPU executes a stop-and-signal
  101. // instruction.
  102. //
  103. if (stat & INTR_STOP_MASK) //stop
  104. {
  105. //We've hit a stop, so what kind of value is it?
  106. uint32_t signalVal = GetStopSignal( id );
  107. switch ( signalVal )
  108. {
  109. case 0x3:
  110. // it was a stop that is in the SPU code to signal to the PPU
  111. // do any processing for the user defined stop here
  112. // if we do not restart the SPU then we need to call g_snRawSPUNotifySPUStopped(id)
  113. // to inform the debugger that SPU has stopped
  114. //restart the SPU
  115. sys_raw_spu_mmio_write( id, SPU_RunCntl, 0x1 );
  116. break;
  117. default:
  118. #ifndef _CERT
  119. g_snRawSPUNotifySPUStopped(id);
  120. #endif
  121. break;
  122. }
  123. }
  124. else if (stat & INTR_HALT_MASK) // halt
  125. {
  126. #ifndef _CERT
  127. g_snRawSPUNotifySPUStopped(id);
  128. #endif
  129. }
  130. // Other class 2 interrupts could be handled here
  131. // ...
  132. //
  133. // Must reset interrupt status bit of those not handled.
  134. //
  135. ret = sys_raw_spu_set_int_stat(id, 2, stat);
  136. if (ret)
  137. {
  138. #ifndef _CERT
  139. g_snRawSPUUnlockHandler();
  140. #endif
  141. sys_interrupt_thread_eoi();
  142. }
  143. //
  144. // End of interrupt
  145. //
  146. #ifndef _CERT
  147. g_snRawSPUUnlockHandler();
  148. #endif
  149. sys_interrupt_thread_eoi();
  150. }
  151. int CreateDefaultInterruptHandler(SpuTaskHandle *pTask)
  152. {
  153. int res = 0;
  154. //
  155. // Create a SPU interrupt handler thread, an interrupt tag,
  156. // and associate it with the thread
  157. //
  158. // create thread
  159. if (sys_ppu_thread_create(&pTask->m_ppuThread, handle_syscall,
  160. 0, INTR_HANDLER_THREAD_PRIORITY, INTR_HANDLER_THREAD_STACK_SIZE,
  161. SYS_PPU_THREAD_CREATE_INTERRUPT, "Interrupt PPU Thread"))
  162. {
  163. res = 1;
  164. goto xit;
  165. }
  166. // create interrupt tag for handling class 2 interrupts from this spu
  167. if (sys_raw_spu_create_interrupt_tag(pTask->m_spuId, 2, SYS_HW_THREAD_ANY, &pTask->m_intrTag))
  168. {
  169. res = 1;
  170. goto xit;
  171. }
  172. // associate interrupt tag with thread
  173. if (sys_interrupt_thread_establish(&pTask->m_interruptThread, pTask->m_intrTag,
  174. pTask->m_ppuThread, pTask->m_spuId))
  175. {
  176. res = 1;
  177. goto xit;
  178. }
  179. // Set interrupt mask - enable Halt, Stop-and-Signal interrupts
  180. if (sys_raw_spu_set_int_mask(pTask->m_spuId, 2, INTR_STOP_MASK | INTR_HALT_MASK))
  181. {
  182. res = 1;
  183. goto xit;
  184. }
  185. xit:
  186. return res;
  187. }
  188. //--------------------------------------------------------------------------------------------------
  189. // Class Methods
  190. //--------------------------------------------------------------------------------------------------
  191. int SpuMgr::Init(int numRawSpu)
  192. {
  193. // Need at least 2 SPUs for SPURS instances
  194. ASSERT(numRawSpu < 5);
  195. // Run SPURS on all SPUs that are not in raw mode
  196. // Creating two SPURS instances. One with a thread group of 5 - numRawSpu threads and one
  197. // with a thread group of 1 thread.
  198. // The instance with a single thread is designed to be singled out as the preemption victim
  199. // when the OS needs to use an SPU. We ensure this by giving it a lower priority than the
  200. // dedicated SPURS instance.
  201. // Init dedicated SPUs SPURS instance
  202. // CellSpursAttribute attr;
  203. // int32 ret = cellSpursAttributeInitialize(&attr, 5 - numRawSpu, 99, 2, false);
  204. // ASSERT(ret == CELL_OK);
  205. // ret = cellSpursAttributeEnableSpuPrintfIfAvailable(&attr);
  206. // ASSERT(ret == CELL_OK);
  207. // ret = cellSpursAttributeSetNamePrefix(&attr, "gameSpusSpurs", std::strlen("gameSpusSpurs"));
  208. // ASSERT(ret == CELL_OK);
  209. // ret = cellSpursInitializeWithAttribute2(&m_exclusiveSpusSpurs, &attr);
  210. // ASSERT(ret == CELL_OK);
  211. // Init pre-emption SPU SPURS instance
  212. // ret = cellSpursAttributeInitialize(&attr, 1, 100, 2, false);
  213. // ASSERT(ret == CELL_OK);
  214. // ret = cellSpursAttributeEnableSpuPrintfIfAvailable(&attr);
  215. // ASSERT(ret == CELL_OK);
  216. // ret = cellSpursAttributeSetNamePrefix(&attr, "sharedSpuSpurs", std::strlen("sharedSpuSpurs"));
  217. // ASSERT(ret == CELL_OK);
  218. // ret = cellSpursInitializeWithAttribute2(&m_preemptedSpuSpurs, &attr);
  219. // ASSERT(ret == CELL_OK);
  220. int res = 0;
  221. // set up members
  222. m_numSpus = 0;
  223. // Initialize SPUs
  224. if (sys_spu_initialize(6, numRawSpu) != SUCCEEDED)
  225. {
  226. res = 1;
  227. goto xit;
  228. }
  229. // Create raw spus
  230. for (; m_numSpus < (uint32)numRawSpu; m_numSpus++)
  231. {
  232. if (sys_raw_spu_create(&m_spuIds[m_numSpus], NULL) != SUCCEEDED)
  233. {
  234. Error("Unable to create saw spu\n");
  235. res = 1;
  236. goto xit;
  237. }
  238. #ifndef _CERT
  239. g_snRawSPUNotifyCreation(m_spuIds[m_numSpus]);
  240. #endif
  241. m_spuInUse[m_numSpus] = 0;
  242. }
  243. xit:
  244. return res;
  245. }
  246. void SpuMgr::Term()
  247. {
  248. uint32 spu;
  249. // destroy raw spus
  250. for (spu = 0; spu < m_numSpus; spu++)
  251. {
  252. sys_raw_spu_destroy(m_spuIds[spu]);
  253. }
  254. // destroy the SPURS instances
  255. // int ret;
  256. // ret = cellSpursfinalize(&m_exclusiveSpusSpurs);
  257. // ASSERT(ret == CELL_OK);
  258. //
  259. // ret = cellSpursfinalize(&m_preemptedSpuSpurs);
  260. // ASSERT(ret == CELL_OK);
  261. m_numSpus = 0;
  262. }
  263. //--------------------------------------------------------------------------------------------------
  264. //
  265. //--------------------------------------------------------------------------------------------------
  266. uint32_t spumgr_mmio_read(uint32_t spu, uint32_t regoffset)
  267. {
  268. uint64_t addr = get_reg_addr(spu,regoffset);
  269. addr &= 0xffffffffUL;
  270. volatile uint32_t * pAddr = (uint32_t*) addr;
  271. return *pAddr;
  272. }
  273. void spumgr_mmio_write(int spu, int regoffset, uint32_t value)
  274. {
  275. uint64_t addr = get_reg_addr(spu,regoffset);
  276. addr &= 0xffffffffUL;
  277. volatile uint32_t * pAddr = (uint32_t*) addr;
  278. *pAddr = value;
  279. }
  280. //--------------------------------------------------------------------------------------------------
  281. // Create Spu task from file based image
  282. //--------------------------------------------------------------------------------------------------
  283. static char modPath[MAX_PATH];
  284. int SpuMgr::CreateSpuTask(const char *path, SpuTaskHandle *pTask,
  285. CreateSPUTaskCallback *pfnCallback /* = NULL */)
  286. {
  287. int res = 0;
  288. int ret;
  289. uint32 spu;
  290. register uint32 spuid;
  291. uint32 entry;
  292. FILE* fp;
  293. void* pSpuProg = NULL;
  294. sys_spu_image_t img;
  295. pTask->m_spuId = -1;
  296. pTask->m_ppuThread = NULL;
  297. pTask->m_intrTag = NULL;
  298. pTask->m_interruptThread = NULL;
  299. // find free raw spu
  300. for (spu = 0; spu < m_numSpus; spu++)
  301. {
  302. if (!m_spuInUse[spu])
  303. {
  304. break;
  305. }
  306. }
  307. // check we found free spu
  308. if (spu == m_numSpus)
  309. {
  310. res = 1;
  311. goto xit;
  312. }
  313. // Loading an SPU program to the Raw SPU.
  314. //if (sys_raw_spu_load(m_spuIds[spu], path, &entry) != SUCCEEDED)
  315. sprintf(modPath, "%s/%s", g_pPS3PathInfo->PrxPath(), path);
  316. path = modPath;
  317. if(strstr(path,".self"))
  318. {
  319. ret = sys_spu_image_open(&img, path);
  320. if(ret != CELL_OK)
  321. {
  322. // (Running on Main Thread)
  323. Error("Failed to open SPU program: %s\n", path);
  324. }
  325. }
  326. else
  327. {
  328. // Allocate mem for SPU prog
  329. CellFsStat stat;
  330. cellFsStat(path,&stat);
  331. pSpuProg = memalign(4096,((uint32)stat.st_size + 0x7f)&0xffffff80);
  332. fp = fopen(path, "rb");
  333. fread(pSpuProg, 1, stat.st_size, fp );
  334. fclose(fp);
  335. ret = sys_spu_image_import(&img, pSpuProg, SYS_SPU_IMAGE_PROTECT);
  336. if (ret != CELL_OK)
  337. {
  338. res = 1;
  339. goto xit;
  340. }
  341. }
  342. ret = sys_raw_spu_image_load(m_spuIds[spu], &img);
  343. spuid = m_spuIds[spu];
  344. if (ret == CELL_OK)
  345. {
  346. // successfully loaded - mark spu as used and fill in o/p
  347. m_spuInUse[spu] = 1;
  348. pTask->m_spuId = spuid;
  349. }
  350. else
  351. {
  352. res = 1;
  353. goto xit;
  354. }
  355. //Free PPU resources used to load image
  356. if(pSpuProg)
  357. {
  358. free(pSpuProg);
  359. }
  360. sys_spu_image_close(&img);
  361. entry = sys_raw_spu_mmio_read((uint32_t)spuid, (uint32_t)SPU_NPC);
  362. #ifndef _CERT
  363. g_snRawSPUNotifyElfLoad(spuid, entry, path);
  364. #endif
  365. // call callback or create default interrupt handler
  366. if (!pfnCallback)
  367. {
  368. res = CreateDefaultInterruptHandler(pTask);
  369. }
  370. else
  371. {
  372. res = pfnCallback(pTask);
  373. }
  374. if (res)
  375. {
  376. goto xit;
  377. }
  378. // Run the Raw SPU
  379. #ifndef _CERT
  380. g_snRawSPUNotifySPUStarted(m_spuIds[spu]);
  381. #endif
  382. sys_raw_spu_mmio_write(spuid, SPU_NPC, entry);
  383. sys_raw_spu_mmio_write(spuid, SPU_RunCntl, 0x1);
  384. __asm("eieio");
  385. // Once the SPU has started, write a mailbox with the effective address of the
  386. // SPU lock.
  387. WriteMailbox( pTask, (uint32) &pTask->m_lock );
  388. WriteMailbox( pTask, (uint32) &pTask->m_memcpyLock );
  389. xit:
  390. if(res)
  391. {
  392. // Error("Error: CreateSpuTask error attempting to load and run %s on SPU\n", path);
  393. }
  394. return res;
  395. }
  396. //--------------------------------------------------------------------------------------------------
  397. //
  398. //--------------------------------------------------------------------------------------------------
  399. void SpuMgr::DestroySpuTask(SpuTaskHandle *pTask)
  400. {
  401. if (pTask->m_spuId != -1)
  402. {
  403. // Stop the Raw spu
  404. #ifndef _CERT
  405. g_snRawSPUNotifySPUStopped(pTask->m_spuId);
  406. #endif
  407. sys_raw_spu_mmio_write(pTask->m_spuId, SPU_RunCntl, 0x0);
  408. __asm("eieio");
  409. // Cleanup interrupt handling mechanism
  410. if (pTask->m_interruptThread)
  411. {
  412. sys_interrupt_thread_disestablish(pTask->m_interruptThread); // also kills the thread
  413. }
  414. if (pTask->m_intrTag)
  415. {
  416. sys_interrupt_tag_destroy(pTask->m_intrTag);
  417. }
  418. }
  419. }
  420. //--------------------------------------------------------------------------------------------------
  421. //
  422. //--------------------------------------------------------------------------------------------------
  423. int SpuMgr::WriteMailbox(SpuTaskHandle *pTask, uint32 val, bool bBlocking /* =true */)
  424. {
  425. uint32 mboxAvailable;
  426. do
  427. {
  428. // Check the SPU Mailbox Status Register
  429. mboxAvailable = sys_raw_spu_mmio_read(pTask->m_spuId, SPU_MBox_Status) & SPU_IN_MBOX_COUNT;
  430. } while (bBlocking && !mboxAvailable);
  431. if (mboxAvailable)
  432. sys_raw_spu_mmio_write(pTask->m_spuId, SPU_In_MBox, (std::uint32_t)val);
  433. return !mboxAvailable;
  434. }
  435. //--------------------------------------------------------------------------------------------------
  436. //
  437. //--------------------------------------------------------------------------------------------------
  438. int SpuMgr::ReadMailbox(SpuTaskHandle *pTask, uint32 *pVal, bool bBlocking /* = true */)
  439. {
  440. uint32 mailAvailable;
  441. do
  442. {
  443. // Check the SPU Mailbox Status Register
  444. mailAvailable = sys_raw_spu_mmio_read(pTask->m_spuId, SPU_MBox_Status) & SPU_OUT_MBOX_COUNT;
  445. } while (bBlocking && !mailAvailable);
  446. if (mailAvailable)
  447. {
  448. // Read the SPU Outbound Mailbox Register
  449. *pVal = sys_raw_spu_mmio_read(pTask->m_spuId, SPU_Out_MBox);
  450. }
  451. return !mailAvailable;
  452. }
  453. //--------------------------------------------------------------------------------------------------
  454. //
  455. //--------------------------------------------------------------------------------------------------
  456. int SpuMgr::ReadIntrMailbox(SpuTaskHandle *pTask, uint32 *pVal, bool bBlocking /* = true */)
  457. {
  458. uint32 mailAvailable;
  459. do
  460. {
  461. // Check the SPU Mailbox Status Register
  462. mailAvailable = sys_raw_spu_mmio_read(pTask->m_spuId, SPU_MBox_Status) & SPU_OUT_INTR_MBOX_COUNT;
  463. } while (bBlocking && !mailAvailable);
  464. if (mailAvailable)
  465. {
  466. // Read the SPU Outbound Mailbox Register
  467. sys_raw_spu_read_puint_mb(pTask->m_spuId, pVal);
  468. }
  469. return !mailAvailable;
  470. }
  471. //--------------------------------------------------------------------------------------------------
  472. //
  473. //--------------------------------------------------------------------------------------------------
  474. bool SpuMgr::Lock( SpuTaskHandle *pTask )
  475. {
  476. return cellAtomicCompareAndSwap32( &pTask->m_lock, 0, 1 ) == 0;
  477. }
  478. //--------------------------------------------------------------------------------------------------
  479. //
  480. //--------------------------------------------------------------------------------------------------
  481. void SpuMgr::Unlock( SpuTaskHandle *pTask )
  482. {
  483. cellAtomicCompareAndSwap32( &pTask->m_lock, 1, 0 );
  484. }
  485. //--------------------------------------------------------------------------------------------------
  486. //
  487. //--------------------------------------------------------------------------------------------------
  488. bool SpuMgr::MemcpyLock( SpuTaskHandle *pTask )
  489. {
  490. return cellAtomicCompareAndSwap32( &pTask->m_memcpyLock, 0, 1 ) == 0;
  491. }
  492. //--------------------------------------------------------------------------------------------------
  493. //
  494. //--------------------------------------------------------------------------------------------------
  495. void SpuMgr::MemcpyUnlock( SpuTaskHandle *pTask )
  496. {
  497. cellAtomicCompareAndSwap32( &pTask->m_memcpyLock, 1, 0 );
  498. }