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.
447 lines
11 KiB
447 lines
11 KiB
#ifndef __PS3_HELPERS__
|
|
#define __PS3_HELPERS__
|
|
|
|
#ifndef SN_TARGET_PS3
|
|
#error
|
|
#endif
|
|
|
|
|
|
#include <cellstatus.h>
|
|
#include <sys/paths.h>
|
|
#include <sys/prx.h>
|
|
#include <sys/synchronization.h>
|
|
#include <sys/ppu_thread.h>
|
|
#include <sys/timer.h>
|
|
#include "ppu_intrinsics.h"
|
|
#include <np.h>
|
|
#include <np/drm.h>
|
|
|
|
// 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__
|