#ifndef __PS3_HELPERS__ #define __PS3_HELPERS__ #ifndef SN_TARGET_PS3 #error #endif #include #include #include #include #include #include #include "ppu_intrinsics.h" #include #include // Forward declarations #ifndef _CERT #define PS3PRXLOADDIAGNOSTIC printf #else #define PS3PRXLOADDIAGNOSTIC( ... ) ((void)0) #endif struct TLSGlobals; // PS3 PRX load parameters structures struct PS3_PrxLoadParametersBase_t { int32_t cbSize; sys_prx_id_t sysPrxId; uint64_t uiFlags; uint64_t reserved[7]; }; struct PS3_PrxModuleEntry_t { PS3_PrxModuleEntry_t *pNextModule; char chName[256]; uint32_t uiRefCount; PS3_PrxLoadParametersBase_t prxParams[0]; }; extern "C" PS3_PrxModuleEntry_t ** PS3_PrxGetModulesList(); struct PS3_GcmSharedData; // exported from tier0 extern "C" PS3_GcmSharedData *g_pGcmSharedData; struct PS3_GcmSharedData { void *m_pIoMemory; uint32_t m_nIoMemorySize; PS3_GcmSharedData() { memset(this, 0, sizeof(PS3_GcmSharedData)); } // Thread for the QMS and Server (when host_thread_mode) // Thread wakes up on a semaphore and when it does so it checks for // sv_runflag and then qms runFlag and does the right thing // This is hand coded because the PS3 scheduler sometimes (regardless of priorities) // pushes out the main thread to run the server if the server is it's own job. // So we create a single thread, one which we have the ability to explicitly // run the server and the qms // The semaphore is there so that we can sleep instead of exiting the job // Otherwise the run flags actually control if we run locklessly // CheckForServerRequest() is called eregularly on the QMS and so allows the // server to interrupt the QMS and run pretty much where we need to to. // sys_ppu_thread_t m_thread; sys_semaphore_t m_semaphore; // Server volatile int m_svRunFlag; volatile int m_svDoneFlag; volatile int m_numTicks; void (*m_pfnAsyncServer)(int numTicks); // QMS volatile int m_qmsRunFlag; volatile int m_qmsDoneFlag; volatile void* m_cmat; volatile void* m_ptr; void (*m_func)(void*, void*); // Audio volatile int m_audioRunFlag; volatile int m_audioDoneFlag; void (*m_AudioFunc)(void); // Endframe Defrag volatile int m_bDeFrag; // Create semaphore & thread void Init() { // Create Semaphore sys_semaphore_attribute_t attr; sys_semaphore_attribute_initialize(attr); int ret = sys_semaphore_create(&m_semaphore, &attr, 0, 2); // No point in allowing > 2 posts if(ret != CELL_OK) { printf("Unable to create QMS sem\n"); } } void RunServer(void (*pfn)(int), int numticks) { // Set global data m_pfnAsyncServer = pfn; m_numTicks = numticks; __lwsync(); m_svRunFlag = 1; // Post semaphore incase trhead sleeps sys_semaphore_post(m_semaphore, 1); } void RunQMS(void (*func)(void* cmat, void* ptr), void* cmat, void* ptr ) { m_func = func; m_cmat = cmat; m_ptr = ptr; __lwsync(); m_qmsRunFlag = 1; // Post semaphore incase trhead sleeps sys_semaphore_post(m_semaphore, 1); } void WaitForServer() { while (!m_svDoneFlag) sys_timer_usleep(60); m_svDoneFlag = 0; } void WaitForQMS() { while (!m_qmsDoneFlag) sys_timer_usleep(60); m_qmsDoneFlag = 0; } void CheckForServerRequest() { if (m_svRunFlag) { m_svRunFlag = 0; m_pfnAsyncServer(m_numTicks); m_svDoneFlag = 1; } } // Audio void RunAudio(void (*pfn)(void)) { // Set global data m_AudioFunc = pfn; __lwsync(); m_audioRunFlag = 1; // Post semaphore incase trhead sleeps sys_semaphore_post(m_semaphore, 1); } void WaitForAudio() { while (!m_audioDoneFlag) sys_timer_usleep(60); m_audioDoneFlag = 0; } void CheckForAudioRequest() { if (g_pGcmSharedData->m_audioRunFlag) { g_pGcmSharedData->m_audioRunFlag = 0; g_pGcmSharedData->m_AudioFunc(); g_pGcmSharedData->m_audioDoneFlag = 1; } } }; class CPs3ContentPathInfo; struct PS3_LoadTier0_Parameters_t : public PS3_PrxLoadParametersBase_t { typedef TLSGlobals * ( *PFNGETTLSGLOBALS )(); PFNGETTLSGLOBALS pfnGetTlsGlobals; // [IN] [ from launcher_main to tier0 ] PS3_PrxModuleEntry_t **ppPrxModulesList; // [IN] [ from launcher_main: head of the list of loaded PRX modules ] CPs3ContentPathInfo *pPS3PathInfo; // [IN] [ from launcher_main to tier0 ] uint64_t fiosLaunchTime; // [IN] [ from launcher_main: the time when the launcher was launched, the baseline time ] uint32_t nCLNumber; // [IN] [ from launcher_main to tier0: the changelist number for this image (0 if unknown) ] void(*pfnPushMarker)( const char * pName ); void(*pfnPopMarker)(); void(*pfnSwapBufferMarker)(); // Raw SPU libSN functions void (*snRawSPULockHandler) (void); void (*snRawSPUUnlockHandler) (void); void (*snRawSPUNotifyCreation) (unsigned int uID); void (*snRawSPUNotifyDestruction) (unsigned int uID); void (*snRawSPUNotifyElfLoad) (unsigned int uID, unsigned int uEntry, const char *pFileName); void (*snRawSPUNotifyElfLoadNoWait) (unsigned int uID, unsigned int uEntry, const char *pFileName); void (*snRawSPUNotifyElfLoadAbs) (unsigned int uID, unsigned int uEntry, const char *pFileName); void (*snRawSPUNotifyElfLoadAbsNoWait) (unsigned int uID, unsigned int uEntry, const char *pFileName); void (*snRawSPUNotifySPUStopped) (unsigned int uID); void (*snRawSPUNotifySPUStarted) (unsigned int uID); struct PS3_GcmSharedData *m_pGcmSharedData; typedef void ( *PFNSHUTDOWN )(); PFNSHUTDOWN pfnTier0Shutdown; // [OUT] [ tier0 shutdown procedure to be invoked ] }; struct PS3_LoadLauncher_Parameters_t : public PS3_PrxLoadParametersBase_t { typedef int ( *PFNLAUNCHERMAIN )( int argc, char **argv ); PFNLAUNCHERMAIN pfnLauncherMain; // [OUT] [ launcher entry point ] typedef void ( *PFNSHUTDOWN )(); PFNSHUTDOWN pfnLauncherShutdown; // [OUT] [ launcher shutdown procedure to be invoked ] }; struct PS3_LoadAppSystemInterface_Parameters_t : public PS3_PrxLoadParametersBase_t { typedef void* ( *PFNCREATEINTERFACE )( const char *pName, int *pReturnCode ); PFNCREATEINTERFACE pfnCreateInterface; // [OUT] [ app system module create interface entry point ] uint64_t reserved[8]; }; inline int PS3_PrxLoad( const char *path, PS3_PrxLoadParametersBase_t *params ) { #define NP_POOL_SIZE (128*1024) static uint8_t np_pool[NP_POOL_SIZE]; int res; int modres; sys_prx_id_t id; if ( !params ) return -1; PS3_PrxModuleEntry_t ** ppPrxModulesList = PS3_PrxGetModulesList(); // // Walk the loaded list // for ( PS3_PrxModuleEntry_t *pEntry = *ppPrxModulesList; pEntry; pEntry = pEntry->pNextModule ) { if ( strcmp( pEntry->chName, path ) ) continue; ++ pEntry->uiRefCount; memcpy( params, pEntry->prxParams, ( pEntry->prxParams->cbSize <= params->cbSize ) ? pEntry->prxParams->cbSize : params->cbSize ); PS3PRXLOADDIAGNOSTIC("PRX MODULE ADDREF: %s [0x%08X] (refs=%u)\n", path, params->sysPrxId, pEntry->uiRefCount); return 0; } // // Load a new instance of PRX // params->sysPrxId = -1; // If sceNp wasn't already initalised then we need to un-init it after we're done here. If Steam is loaded // after this and it finds NP is already intialised it won't like it int npInit = sceNpInit( NP_POOL_SIZE, np_pool ); SceNpDrmKey key = { 0x2B, 0x8E, 0xD3, 0xE4, 0xDF, 0xF1, 0x43, 0xA2, 0xA5, 0xD7, 0x4D, 0x8D, 0x89, 0x29, 0xC5, 0xF4 }; sceNpDrmIsAvailable( &key, path ); id = sys_prx_load_module(path, 0, NULL); if (id < CELL_OK) { PS3PRXLOADDIAGNOSTIC("sys_prx_load_module failed: %s [0x%08x]\n", path, id); return id; } PS3PRXLOADDIAGNOSTIC("PRX MODULE LOADED: %s [0x%08X]\n", path, id); if ( npInit != SCE_NP_ERROR_ALREADY_INITIALIZED ) { sceNpTerm(); } params->sysPrxId = id; res = sys_prx_start_module(id, params->cbSize, params, &modres, 0, NULL); if (res < CELL_OK) { PS3PRXLOADDIAGNOSTIC("sys_prx_start_module failed: %s [0x%08x]\n", path, res); return res; } PS3PRXLOADDIAGNOSTIC("PRX MODULE STARTED: %s [0x%08X 0x%08X]\n", path, id, res); // // Add to the loaded list // if ( void *pvEntry = malloc( sizeof( PS3_PrxModuleEntry_t ) + params->cbSize ) ) { PS3_PrxModuleEntry_t *pPrxEntry = ( PS3_PrxModuleEntry_t * ) pvEntry; pPrxEntry->pNextModule = *ppPrxModulesList; *ppPrxModulesList = pPrxEntry; strncpy( pPrxEntry->chName, path, sizeof( pPrxEntry->chName ) ); pPrxEntry->uiRefCount = 1; memcpy( pPrxEntry->prxParams, params, params->cbSize ); } return modres; } inline int PS3_PrxUnload( sys_prx_id_t id ) { PS3_PrxModuleEntry_t ** ppPrxModulesList = PS3_PrxGetModulesList(); // // Walk the loaded list // for ( PS3_PrxModuleEntry_t *pEntry = *ppPrxModulesList, **ppFromPrevEntry = ppPrxModulesList; pEntry; ppFromPrevEntry = &pEntry->pNextModule, pEntry = pEntry->pNextModule ) { if ( pEntry->prxParams->sysPrxId != id ) continue; if ( -- pEntry->uiRefCount ) { PS3PRXLOADDIAGNOSTIC("PRX MODULE RELREF: %s [0x%08X] (refs=%u)\n", pEntry->chName, pEntry->prxParams->sysPrxId, pEntry->uiRefCount); return 0; } else { PS3PRXLOADDIAGNOSTIC("PRX MODULE UNLOAD: %s [0x%08X]\n", pEntry->chName, pEntry->prxParams->sysPrxId, pEntry->uiRefCount); *ppFromPrevEntry = pEntry->pNextModule; free( pEntry ); break; } } // // Perform the system unload process // int modres; int res; res = sys_prx_stop_module(id, 0, NULL, &modres, 0, NULL); if (res < CELL_OK) { PS3PRXLOADDIAGNOSTIC("sys_prx_stop_module failed: id=0x%08x, 0x%08x\n", id, res); return res; } PS3PRXLOADDIAGNOSTIC("PRX MODULE STOPPED: id=0x%08x, 0x%08x\n", id, res); res = sys_prx_unload_module(id, 0, NULL); if (res < CELL_OK) { PS3PRXLOADDIAGNOSTIC("sys_prx_unload_module failed: id=0x%08X, 0x%08x\n", id, res); return res; } PS3PRXLOADDIAGNOSTIC("PRX MODULE UNLOADED: id=0x%08x, 0x%08x\n", id, res); return modres; } ////////////////////////////////////////////////////////////////////////// // // DEFINITION OF BASIC APPSYSTEM PRX IMPLEMENTATION // // #include "ps3_changelistver.h" #ifndef PS3CLVERMAJOR #define PS3CLVERMAJOR ((APPCHANGELISTVERSION / 256) % 256) #define PS3CLVERMINOR (APPCHANGELISTVERSION % 256) #endif #ifdef _DEBUG #define PS3_PRX_SYS_MODULE_INFO_FULLMACROREPLACEMENTHELPER(ps3modulename) SYS_MODULE_INFO( ps3modulename##_dbg, 0, PS3CLVERMAJOR, PS3CLVERMINOR) #else #define PS3_PRX_SYS_MODULE_INFO_FULLMACROREPLACEMENTHELPER(ps3modulename) SYS_MODULE_INFO( ps3modulename##_rel, 0, PS3CLVERMAJOR, PS3CLVERMINOR) #endif #define PS3_PRX_SYS_MODULE_START_NAME_FULLMACROREPLACEMENTHELPER(ps3modulename) _##ps3modulename##_ps3_prx_entry #define PS3_PRX_APPSYSTEM_MODULE( ps3modulename ) \ \ PS3_PRX_SYS_MODULE_INFO_FULLMACROREPLACEMENTHELPER( ps3modulename ); \ SYS_MODULE_START( PS3_PRX_SYS_MODULE_START_NAME_FULLMACROREPLACEMENTHELPER( ps3modulename ) ); \ \ extern "C" int PS3_PRX_SYS_MODULE_START_NAME_FULLMACROREPLACEMENTHELPER( ps3modulename )( unsigned int args, void *pArg ) \ { \ Assert( args >= sizeof( PS3_LoadAppSystemInterface_Parameters_t ) ); \ PS3_LoadAppSystemInterface_Parameters_t *pParams = reinterpret_cast< PS3_LoadAppSystemInterface_Parameters_t * >( pArg ); \ Assert( pParams->cbSize >= sizeof( PS3_LoadAppSystemInterface_Parameters_t ) ); \ pParams->pfnCreateInterface = CreateInterface; \ return SYS_PRX_RESIDENT; \ } \ // // // END DEFINITION OF BASIC APPSYSTEM PRX IMPLEMENTATION // // ////////////////////////////////////////////////////////////////////////// #endif // __PS3_HELPERS__