diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp index efc7c91bf3..82cff805eb 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp @@ -94,12 +94,12 @@ s64 spursInit( { spurs->m.wklMsk1.write_relaxed(be_t::make(0xffff)); } - spurs->m.unk6[0xC] = 0; - spurs->m.unk6[0xD] = 0; - spurs->m.unk6[0xE] = 0; + spurs->m.xCC = 0; + spurs->m.xCD = 0; + spurs->m.xCE = 0; for (u32 i = 0; i < 8; i++) { - spurs->m.unk6[i] = -1; + spurs->m.xC0[i] = -1; } #ifdef PRX_DEBUG spurs->m.unk7 = vm::read32(libsre_rtoc - 0x7EA4); // write 64-bit pointer to unknown data @@ -131,10 +131,7 @@ s64 spursInit( spurs->m.unk11 = -1; spurs->m.unk12 = -1; spurs->m.unk13 = 0; - spurs->m.x70.direct_op([nSpus](CellSpurs::_sub_x70& x70) - { - x70.nSpus = nSpus; - }); + spurs->m.nSpus = nSpus; spurs->m.spuPriority = spuPriority; #ifdef PRX_DEBUG assert(spu_image_import(spurs->m.spuImg, vm::read32(libsre_rtoc - (isSecond ? 0x7E94 : 0x7E98)), 1) == CELL_OK); @@ -187,12 +184,9 @@ s64 spursInit( assert(lwmutex_create(spurs->m.mutex, SYS_SYNC_PRIORITY, SYS_SYNC_NOT_RECURSIVE, *(u64*)"_spuPrv") == CELL_OK); assert(lwcond_create(spurs->m.cond, spurs->m.mutex, *(u64*)"_spuPrv") == CELL_OK); - spurs->m.x70.direct_op([flags, isSecond](CellSpurs::_sub_x70& x70) - { - x70.flags1 = (flags & SAF_EXIT_IF_NO_WORK) << 7 | (isSecond ? 0x40 : 0); - x70.unk7 = -1; - }); - spurs->m.unk18 = -1; + spurs->m.flags1 = (flags & SAF_EXIT_IF_NO_WORK) << 7 | (isSecond ? 0x40 : 0); + spurs->m.flagRecv.write_relaxed(0xff); + spurs->m.wklFlag.flag.write_relaxed(be_t::make(-1)); spurs->_u8[0xD64] = 0; spurs->_u8[0xD65] = 0; spurs->_u8[0xD66] = 0; @@ -569,7 +563,7 @@ s64 spursAttachLv2EventQueue(vm::ptr spurs, u32 queue, vm::ptr po { return CELL_SPURS_CORE_ERROR_ALIGN; } - if (spurs->m.unk21.ToBE()) + if (spurs->m.exception.ToBE()) { return CELL_SPURS_CORE_ERROR_STAT; } @@ -773,13 +767,13 @@ s64 spursWakeUp(vm::ptr spurs) { return CELL_SPURS_POLICY_MODULE_ERROR_ALIGN; } - if (spurs->m.unk21.ToBE()) + if (spurs->m.exception.ToBE()) { return CELL_SPURS_POLICY_MODULE_ERROR_STAT; } - spurs->m.unk19[0].exchange(1); - if (spurs->m.unk19[1].read_sync()) + spurs->m.xD64.exchange(1); + if (spurs->m.xD65.read_sync()) { assert(sys_lwmutex_lock(vm::ptr::make(spurs.addr() + 0xdb0), 0) == 0); assert(sys_lwcond_signal(vm::ptr::make(spurs.addr() + 0xdc8)) == 0); @@ -826,13 +820,13 @@ s32 spursAddWorkload( { return CELL_SPURS_POLICY_MODULE_ERROR_INVAL; } - if (spurs->m.unk21.ToBE()) + if (spurs->m.exception.ToBE()) { return CELL_SPURS_POLICY_MODULE_ERROR_STAT; } u32 wnum; - const u32 wmax = spurs->m.x70.read_relaxed().flags1 & 0x40 ? 0x20 : 0x10; // check isSecond (TODO: check if can be changed) + const u32 wmax = spurs->m.flags1 & 0x40 ? 0x20 : 0x10; // check isSecond (TODO: check if can be changed) spurs->m.wklMsk1.atomic_op([spurs, wmax, &wnum](be_t& value) { wnum = cntlz32(~(u32)value); // found empty position @@ -853,7 +847,7 @@ s32 spursAddWorkload( { assert((spurs->m.wklA[wnum] & 0xf) == 0); assert((spurs->m.wklB[wnum] & 0xf) == 0); - spurs->m.wklC1[wnum] = 1; + spurs->m.wklStat1[wnum].write_relaxed(1); spurs->m.wklD1[wnum] = 0; spurs->m.wklE1[wnum] = 0; spurs->m.wklG1[wnum].wklPm = pm; @@ -870,10 +864,9 @@ s32 spursAddWorkload( spurs->m.wklF1[wnum].hookArg = hookArg; spurs->m.wklE1[wnum] |= 2; } - spurs->m.wklZ1[wnum] = 0; - if ((spurs->m.x70.read_relaxed().flags1 & 0x40) == 0) + if ((spurs->m.flags1 & 0x40) == 0) { - spurs->m.wklZ2[wnum] = 0; + spurs->m.wklReadyCount[wnum + 16].write_relaxed(0); spurs->m.wklMinCnt[wnum] = minContention > 8 ? 8 : minContention; } } @@ -881,7 +874,7 @@ s32 spursAddWorkload( { assert((spurs->m.wklA[index] & 0xf0) == 0); assert((spurs->m.wklB[index] & 0xf0) == 0); - spurs->m.wklC2[index] = 1; + spurs->m.wklStat2[index].write_relaxed(1); spurs->m.wklD2[index] = 0; spurs->m.wklE2[index] = 0; spurs->m.wklG2[index].wklPm = pm; @@ -898,8 +891,8 @@ s32 spursAddWorkload( spurs->m.wklF2[index].hookArg = hookArg; spurs->m.wklE2[index] |= 2; } - spurs->m.wklZ2[index] = 0; } + spurs->m.wklReadyCount[wnum].write_relaxed(0); u32 pos = ((~wnum * 8) | (wnum / 4)) & 0x1c; spurs->m.wklMaxCnt[index / 4].atomic_op([pos, maxContention](be_t& v) @@ -910,26 +903,26 @@ s32 spursAddWorkload( if (wnum <= 15) { - spurs->m.x70._and_not({ be_t::make(0x8000 >> index) }); // clear bit in wklFlag1 + spurs->m.wklSet1._and_not({ be_t::make(0x8000 >> index) }); // clear bit in wklFlag1 } else { - spurs->m.x78._and_not({ be_t::make(0x8000 >> index) }); // clear bit in wklFlag2 + spurs->m.wklSet2._and_not({ be_t::make(0x8000 >> index) }); // clear bit in wklFlag2 } - spurs->m.x70.atomic_op([wnum](CellSpurs::_sub_x70& x70) + spurs->m.flagRecv.atomic_op([wnum](u8& FR) { - if (x70.unk7 == wnum) + if (FR == wnum) { - x70.unk7 = 0xff; + FR = 0xff; } }); u32 res_wkl; - spurs->m.wklMsk2.atomic_op_sync([spurs, wnum, &res_wkl](be_t& v) + CellSpurs::_sub_str3& wkl = wnum <= 15 ? spurs->m.wklG1[wnum] : spurs->m.wklG2[wnum & 0xf]; + spurs->m.wklMsk2.atomic_op_sync([spurs, &wkl, wnum, &res_wkl](be_t& v) { - CellSpurs::_sub_str3& wkl = wnum <= 15 ? spurs->m.wklG1[wnum] : spurs->m.wklG2[wnum & 0xf]; - const u32 mask = v.ToLE() & ~(0x80000000 >> wnum); + const u32 mask = v.ToLE() & ~(0x80000000u >> wnum); res_wkl = 0; for (u32 i = 0, m = 0x80000000, k = 0; i < 32; i++, m >>= 1) @@ -952,21 +945,13 @@ s32 spursAddWorkload( } wkl.wklCopy.exchange((u8)res_wkl); + v = mask | (0x80000000u >> wnum); }); assert(res_wkl <= 31); - if (wnum <= 15) - { - spurs->m.wklC1[wnum] = 2; - } - else - { - spurs->m.wklC2[index] = 2; - } - - spurs->m.unk23[5].exchange(-1); // write 0xff byte at 0xbd - spurs->m.x70._and_not({ {}, -1 }); // clear byte at 0x72 - + spurs->wklStat(wnum).exchange(2); + spurs->m.xBD.exchange(0xff); + spurs->m.x72.exchange(0); return CELL_OK; } @@ -1162,26 +1147,94 @@ s64 cellSpursShutdownWorkload() #endif } -s64 _cellSpursWorkloadFlagReceiver() +s64 _cellSpursWorkloadFlagReceiver(vm::ptr spurs, u32 wid, u32 is_set) { -#ifdef PRX_DEBUG - cellSpurs->Warning("%s()", __FUNCTION__); + cellSpurs->Warning("%s(spurs_addr=0x%x, wid=%d, is_set=%d)", __FUNCTION__, spurs.addr(), wid, is_set); + +#ifdef PRX_DEBUG_XXX return GetCurrentPPUThread().FastCall2(libsre + 0xF158, libsre_rtoc); -#else - UNIMPLEMENTED_FUNC(cellSpurs); - return CELL_OK; #endif + if (!spurs) + { + return CELL_SPURS_POLICY_MODULE_ERROR_NULL_POINTER; + } + if (spurs.addr() % 128) + { + return CELL_SPURS_POLICY_MODULE_ERROR_ALIGN; + } + if (wid >= (spurs->m.flags1 & 0x40 ? 0x20u : 0x10u)) + { + return CELL_SPURS_POLICY_MODULE_ERROR_INVAL; + } + if ((spurs->m.wklMsk1.read_relaxed().ToLE() & (0x80000000u >> wid)) == 0) + { + return CELL_SPURS_POLICY_MODULE_ERROR_SRCH; + } + if (spurs->m.exception.ToBE()) + { + return CELL_SPURS_POLICY_MODULE_ERROR_STAT; + } + if (s32 res = spurs->m.wklFlag.flag.atomic_op_sync(0, [spurs, wid, is_set](be_t& flag) -> s32 + { + if (is_set) + { + if (spurs->m.flagRecv.read_relaxed() != 0xff) + { + return CELL_SPURS_POLICY_MODULE_ERROR_BUSY; + } + } + else + { + if (spurs->m.flagRecv.read_relaxed() != wid) + { + return CELL_SPURS_POLICY_MODULE_ERROR_PERM; + } + } + flag = -1; + return 0; + })) + { + return res; + } + + spurs->m.flagRecv.atomic_op([wid, is_set](u8& FR) + { + if (is_set) + { + if (FR == 0xff) + { + FR = (u8)wid; + } + } + else + { + if (FR == wid) + { + FR = 0xff; + } + } + }); + return CELL_OK; } -s64 cellSpursGetWorkloadFlag() +s64 cellSpursGetWorkloadFlag(vm::ptr spurs, vm::ptr> flag) { -#ifdef PRX_DEBUG - cellSpurs->Warning("%s()", __FUNCTION__); + cellSpurs->Warning("%s(spurs_addr=0x%x, flag_addr=0x%x)", __FUNCTION__, spurs.addr(), flag.addr()); + +#ifdef PRX_DEBUG_XXX return GetCurrentPPUThread().FastCall2(libsre + 0xEC00, libsre_rtoc); -#else - UNIMPLEMENTED_FUNC(cellSpurs); - return CELL_OK; #endif + if (!spurs || !flag) + { + return CELL_SPURS_POLICY_MODULE_ERROR_NULL_POINTER; + } + if (spurs.addr() % 128) + { + return CELL_SPURS_POLICY_MODULE_ERROR_ALIGN; + } + + *flag = vm::bptr::make(Memory.RealToVirtualAddr(&spurs->m.wklFlag)); + return CELL_OK; } s64 cellSpursSendWorkloadSignal() @@ -1206,15 +1259,36 @@ s64 cellSpursGetWorkloadData() #endif } -s64 cellSpursReadyCountStore() +s64 cellSpursReadyCountStore(vm::ptr spurs, u32 wid, u32 value) { -#ifdef PRX_DEBUG - cellSpurs->Warning("%s()", __FUNCTION__); + cellSpurs->Warning("%s(spurs_addr=0x%x, wid=%d, value=0x%x)", __FUNCTION__, spurs.addr(), wid, value); + +#ifdef PRX_DEBUG_XXX return GetCurrentPPUThread().FastCall2(libsre + 0xAB2C, libsre_rtoc); -#else - UNIMPLEMENTED_FUNC(cellSpurs); - return CELL_OK; #endif + if (!spurs) + { + return CELL_SPURS_POLICY_MODULE_ERROR_NULL_POINTER; + } + if (spurs.addr() % 128) + { + return CELL_SPURS_POLICY_MODULE_ERROR_ALIGN; + } + if (wid >= (spurs->m.flags1 & 0x40 ? 0x20u : 0x10u) || value > 0xff) + { + return CELL_SPURS_POLICY_MODULE_ERROR_INVAL; + } + if ((spurs->m.wklMsk1.read_relaxed().ToLE() & (0x80000000u >> wid)) == 0) + { + return CELL_SPURS_POLICY_MODULE_ERROR_SRCH; + } + if (spurs->m.exception.ToBE() || spurs->wklStat(wid).read_relaxed() != 2) + { + return CELL_SPURS_POLICY_MODULE_ERROR_STAT; + } + + spurs->m.wklReadyCount[wid].exchange((u8)value); + return CELL_OK; } s64 cellSpursReadyCountAdd() diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h index 47ab8d975f..87a01466f1 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h @@ -56,6 +56,38 @@ enum CELL_SPURS_TASK_ERROR_SHUTDOWN = 0x80410920, }; +enum +{ + CELL_SPURS_JOB_ERROR_AGAIN = 0x80410A01, + CELL_SPURS_JOB_ERROR_INVAL = 0x80410A02, + CELL_SPURS_JOB_ERROR_NOSYS = 0x80410A03, + CELL_SPURS_JOB_ERROR_NOMEM = 0x80410A04, + CELL_SPURS_JOB_ERROR_SRCH = 0x80410A05, + CELL_SPURS_JOB_ERROR_NOENT = 0x80410A06, + CELL_SPURS_JOB_ERROR_NOEXEC = 0x80410A07, + CELL_SPURS_JOB_ERROR_DEADLK = 0x80410A08, + CELL_SPURS_JOB_ERROR_PERM = 0x80410A09, + CELL_SPURS_JOB_ERROR_BUSY = 0x80410A0A, + CELL_SPURS_JOB_ERROR_JOB_DESCRIPTOR = 0x80410A0B, + CELL_SPURS_JOB_ERROR_JOB_DESCRIPTOR_SIZE = 0x80410A0C, + CELL_SPURS_JOB_ERROR_FAULT = 0x80410A0D, + CELL_SPURS_JOB_ERROR_CHILD = 0x80410A0E, + CELL_SPURS_JOB_ERROR_STAT = 0x80410A0F, + CELL_SPURS_JOB_ERROR_ALIGN = 0x80410A10, + CELL_SPURS_JOB_ERROR_NULL_POINTER = 0x80410A11, + CELL_SPURS_JOB_ERROR_MEMORY_CORRUPTED = 0x80410A12, + + CELL_SPURS_JOB_ERROR_MEMORY_SIZE = 0x80410A17, + CELL_SPURS_JOB_ERROR_UNKNOWN_COMMAND = 0x80410A18, + CELL_SPURS_JOB_ERROR_JOBLIST_ALIGNMENT = 0x80410A19, + CELL_SPURS_JOB_ERROR_JOB_ALIGNMENT = 0x80410A1a, + CELL_SPURS_JOB_ERROR_CALL_OVERFLOW = 0x80410A1b, + CELL_SPURS_JOB_ERROR_ABORT = 0x80410A1c, + CELL_SPURS_JOB_ERROR_DMALIST_ELEMENT = 0x80410A1d, + CELL_SPURS_JOB_ERROR_NUM_CACHE = 0x80410A1e, + CELL_SPURS_JOB_ERROR_INVALID_BINARY = 0x80410A1f, +}; + // SPURS defines. enum SPURSKernelInterfaces { @@ -160,6 +192,13 @@ struct CellSpursAttribute }; }; +struct CellSpursWorkloadFlag +{ + be_t unused0; + be_t unused1; + atomic_t flag; +}; + typedef void(*CellSpursShutdownCompletionEventHook)(vm::ptr, u32 wid, vm::ptr arg); // Core CellSpurs structures @@ -213,23 +252,6 @@ struct CellSpurs vm::bptr nameInstance; }; - struct _sub_x70 - { - be_t wklFlag1; // 0x70 - u8 unk2; // 0x72 - u8 unk3; - u8 flags1; - u8 unk5; - u8 nSpus; - u8 unk7; - }; - - struct _sub_x78 - { - be_t wklFlag2; - u8 unk[6]; - }; - union { // raw data @@ -239,27 +261,42 @@ struct CellSpurs // real data struct { - u8 wklZ1[0x10]; // 0x0 - u8 wklZ2[0x10]; // 0x10 + atomic_t wklReadyCount[0x20]; u8 wklA[0x10]; // 0x20 u8 wklB[0x10]; // 0x30 u8 wklMinCnt[0x10]; // 0x40 atomic_t wklMaxCnt[4]; // 0x50 - u8 unknown0[0x6C - 0x60]; - be_t unk18; // 0x6C - atomic_t<_sub_x70> x70; // 0x70 - atomic_t<_sub_x78> x78; // 0x78 - u8 wklC1[0x10]; // 0x80 + CellSpursWorkloadFlag wklFlag; // 0x60 + atomic_t wklSet1; // 0x70 + atomic_t x72; // 0x72 + u8 x73; // 0x73 + u8 flags1; // 0x74 + u8 x75; // 0x75 + u8 nSpus; // 0x76 + atomic_t flagRecv; // 0x77 + atomic_t wklSet2; // 0x78 + u8 x7A[6]; // 0x7A + atomic_t wklStat1[0x10]; // 0x80 u8 wklD1[0x10]; // 0x90 u8 wklE1[0x10]; // 0xA0 - atomic_t wklMsk1;// 0xB0 - atomic_t wklMsk2;// 0xB4 - atomic_t unk23[8];// 0xB8 - u8 unk6[0x10]; // 0xC0 (SPU port at 0xc9) - u8 wklC2[0x10]; // 0xD0 + atomic_t wklMsk1; // 0xB0 + atomic_t wklMsk2; // 0xB4 + u8 xB8[5]; // 0xB8 + atomic_t xBD; // 0xBD + u8 xBE[2]; // 0xBE + u8 xC0[8]; // 0xC0 + u8 xC8; // 0xC8 + u8 spuPort; // 0xC9 + u8 xCA; // 0xCA + u8 xCB; // 0xCB + u8 xCC; // 0xCC + u8 xCD; // 0xCD + u8 xCE; // 0xCE + u8 xCF; // 0xCF + atomic_t wklStat2[0x10]; // 0xD0 u8 wklD2[0x10]; // 0xE0 u8 wklE2[0x10]; // 0xF0 - _sub_str1 wklF1[0x10];// 0x100 + _sub_str1 wklF1[0x10]; // 0x100 be_t unk22; // 0x900 u8 unknown7[0x980 - 0x908]; be_t semPrv; // 0x980 @@ -280,9 +317,11 @@ struct CellSpurs u8 unknown3[0xD5C - 0xD54]; be_t queue; // 0xD5C be_t port; // 0xD60 - atomic_t unk19[4]; // 0xD64 (used in wakeup) + atomic_t xD64; // 0xD64 + atomic_t xD65; // 0xD65 + atomic_t xD66; // 0xD66 atomic_t enableEH; // 0xD68 - be_t unk21; // 0xD6C + be_t exception; // 0xD6C sys_spu_image spuImg; // 0xD70 be_t flags; // 0xD80 be_t spuPriority;// 0xD84 @@ -292,7 +331,7 @@ struct CellSpurs be_t unk5; // 0xD9C be_t revision; // 0xDA0 be_t sdkVersion; // 0xDA4 - atomic_t spups;// 0xDA8 + atomic_t spups; // 0xDA8 sys_lwmutex_t mutex; // 0xDB0 sys_lwcond_t cond; // 0xDC8 u8 unknown9[0xE00 - 0xDD0]; @@ -310,6 +349,18 @@ struct CellSpurs SPURSManager *spurs; } c; }; + + __forceinline atomic_t& wklStat(const u32 wid) + { + if (wid & 0x10) + { + return m.wklStat2[wid & 0xf]; + } + else + { + return m.wklStat1[wid & 0xf]; + } + } }; typedef CellSpurs CellSpurs2;