diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index d332443a4b..267fadd92e 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -591,6 +591,18 @@ bool get_x64_reg_value(x64_context* context, x64_reg_t reg, size_t d_size, size_ case 8: out_value = (u64)imm_value; return true; // sign-extended } } + else if (reg == X64_IMM16) + { + // load the immediate value (assuming it's at the end of the instruction) + out_value = *(s16*)(RIP(context) + i_size - 2); + return true; + } + else if (reg == X64_IMM8) + { + // load the immediate value (assuming it's at the end of the instruction) + out_value = *(s8*)(RIP(context) + i_size - 1); + return true; + } else if (reg == X64R_ECX) { out_value = (u32)RCX(context); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp index 86f2d01add..08d14fb48a 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp @@ -2284,14 +2284,18 @@ s32 cellSpursShutdownTaskset(vm::ptr taskset) u32 _cellSpursGetSdkVersion() { - s32 sdk_version; + // Commenting this out for now since process_get_sdk_version does not return + // the correct SDK version and instead returns a version too high for the game + // and causes SPURS to fail. + //s32 sdk_version; - if (process_get_sdk_version(process_getpid(), sdk_version) != CELL_OK) - { - throw __FUNCTION__; - } + //if (process_get_sdk_version(process_getpid(), sdk_version) != CELL_OK) + //{ + // throw __FUNCTION__; + //} - return sdk_version; + //return sdk_version; + return 1; } s32 spursCreateTask(vm::ptr taskset, vm::ptr task_id, vm::ptr elf_addr, vm::ptr context_addr, u32 context_size, vm::ptr ls_pattern, vm::ptr arg) @@ -2333,10 +2337,11 @@ s32 spursCreateTask(vm::ptr taskset, vm::ptr task_id, vm: alloc_ls_blocks = context_size > 0x3D400 ? 0x7A : ((context_size - 0x400) >> 11); if (ls_pattern.addr() != 0) { - u32 ls_blocks = 0; + u128 ls_pattern_128 = u128::from64r(ls_pattern->_u64[0], ls_pattern->_u64[1]); + u32 ls_blocks = 0; for (auto i = 0; i < 128; i++) { - if (ls_pattern->_u128.value()._bit[i]) + if (ls_pattern_128._bit[i]) { ls_blocks++; } @@ -2348,7 +2353,7 @@ s32 spursCreateTask(vm::ptr taskset, vm::ptr task_id, vm: } u128 _0 = u128::from32(0); - if ((ls_pattern->_u128.value() & u128::from32r(0xFC000000)) != _0) + if ((ls_pattern_128 & u128::from32r(0xFC000000)) != _0) { // Prevent save/restore to SPURS management area return CELL_SPURS_TASK_ERROR_INVAL; @@ -2432,19 +2437,19 @@ s32 cellSpursCreateTask(vm::ptr taskset, vm::ptr taskId, vm::var tmpTaskId; auto rc = spursCreateTask(taskset, tmpTaskId, vm::ptr::make(elf_addr), vm::ptr::make(context_addr), context_size, lsPattern, argument); - if (rc != CELL_OK) - { - return rc; - } + if (rc != CELL_OK) + { + return rc; + } - rc = spursTaskStart(taskset, tmpTaskId); - if (rc != CELL_OK) - { - return rc; - } + rc = spursTaskStart(taskset, tmpTaskId); + if (rc != CELL_OK) + { + return rc; + } - *taskId = tmpTaskId; - return CELL_OK; + *taskId = tmpTaskId; + return CELL_OK; } s32 _cellSpursSendSignal(vm::ptr taskset, u32 taskId) @@ -2636,10 +2641,10 @@ s32 _cellSpursTaskAttribute2Initialize(vm::ptr attribut attribute->revision = revision; attribute->sizeContext = 0; attribute->eaContext = 0; - + for (s32 c = 0; c < 4; c++) { - attribute->lsPattern._u128 = u128::from64r(0); + attribute->lsPattern._u32[c] = 0; } attribute->name_addr = 0; diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h index f474da8893..b45ac75b60 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h @@ -623,12 +623,14 @@ static_assert(sizeof(CellSpursEventFlag) == CellSpursEventFlag::size, "Wrong Cel union CellSpursTaskArgument { - be_t _u128; + be_t _u32[4]; + be_t _u64[2]; }; union CellSpursTaskLsPattern { - be_t _u128; + be_t _u32[4]; + be_t _u64[2]; }; struct CellSpursTaskset @@ -927,32 +929,32 @@ static_assert(sizeof(SpursKernelContext) == 0x190, "Incorrect size for SpursKern // The SPURS taskset policy module context. This resides at 0x2700 of the LS. struct SpursTasksetContext { - u8 tempAreaTaskset[0x80]; // 0x2700 - u8 tempAreaTaskInfo[0x30]; // 0x2780 - be_t x27B0; // 0x27B0 - vm::bptr taskset; // 0x27B8 - be_t kernelMgmtAddr; // 0x27C0 - be_t syscallAddr; // 0x27C4 - be_t x27C8; // 0x27C8 - be_t spuNum; // 0x27CC - be_t dmaTagId; // 0x27D0 - be_t taskId; // 0x27D4 - u8 x27D8[0x2840 - 0x27D8]; // 0x27D8 - u8 moduleId[16]; // 0x2840 - u8 stackArea[0x2C80 - 0x2850]; // 0x2850 - be_t savedContextLr; // 0x2C80 - be_t savedContextSp; // 0x2C90 - be_t savedContextR80ToR127[48]; // 0x2CA0 - be_t savedContextFpscr; // 0x2FA0 - be_t savedWriteTagGroupQueryMask; // 0x2FB0 - be_t savedSpuWriteEventMask; // 0x2FB4 - be_t tasksetMgmtAddr; // 0x2FB8 - be_t guidAddr; // 0x2FBC - be_t x2FC0; // 0x2FC0 - be_t x2FC8; // 0x2FC8 - be_t taskExitCode; // 0x2FD0 - be_t x2FD4; // 0x2FD4 - u8 x2FD8[0x3000 - 0x2FD8]; // 0x2FD8 + u8 tempAreaTaskset[0x80]; // 0x2700 + u8 tempAreaTaskInfo[0x30]; // 0x2780 + be_t x27B0; // 0x27B0 + vm::bptr taskset; // 0x27B8 + be_t kernelMgmtAddr; // 0x27C0 + be_t syscallAddr; // 0x27C4 + be_t x27C8; // 0x27C8 + be_t spuNum; // 0x27CC + be_t dmaTagId; // 0x27D0 + be_t taskId; // 0x27D4 + u8 x27D8[0x2840 - 0x27D8]; // 0x27D8 + u8 moduleId[16]; // 0x2840 + u8 stackArea[0x2C80 - 0x2850]; // 0x2850 + be_t savedContextLr; // 0x2C80 + be_t savedContextSp; // 0x2C90 + be_t savedContextR80ToR127[48]; // 0x2CA0 + be_t savedContextFpscr; // 0x2FA0 + be_t savedWriteTagGroupQueryMask; // 0x2FB0 + be_t savedSpuWriteEventMask; // 0x2FB4 + be_t tasksetMgmtAddr; // 0x2FB8 + be_t guidAddr; // 0x2FBC + be_t x2FC0; // 0x2FC0 + be_t x2FC8; // 0x2FC8 + be_t taskExitCode; // 0x2FD0 + be_t x2FD4; // 0x2FD4 + u8 x2FD8[0x3000 - 0x2FD8]; // 0x2FD8 }; static_assert(sizeof(SpursTasksetContext) == 0x900, "Incorrect size for SpursTasksetContext"); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp index c3934b8d74..25c2911a8f 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp @@ -156,19 +156,19 @@ void spursHalt(SPUThread & spu) { /// Select a workload to run bool spursKernel1SelectWorkload(SPUThread & spu) { - auto ctxt = vm::get_ptr(spu.ls_offset + 0x100); + auto ctxt = vm::get_ptr(spu.ls_offset + 0x100); // The first and only argument to this function is a boolean that is set to false if the function // is called by the SPURS kernel and set to true if called by cellSpursModulePollStatus. // If the first argument is true then the shared data is not updated with the result. - const auto isPoll = spu.GPR[3]._u32[3]; + const auto isPoll = spu.GPR[3]._u32[3]; - u32 wklSelectedId; - u32 pollStatus; + u32 wklSelectedId; + u32 pollStatus; - vm::reservation_op(vm::cast(ctxt->spurs.addr()), 128, [&]() { + vm::reservation_op(vm::cast(ctxt->spurs.addr()), 128, [&]() { // lock the first 0x80 bytes of spurs - auto spurs = ctxt->spurs.get_priv_ptr(); + auto spurs = ctxt->spurs.get_priv_ptr(); // Calculate the contention (number of SPUs used) for each workload u8 contention[CELL_SPURS_MAX_WORKLOAD]; @@ -302,7 +302,7 @@ bool spursKernel1SelectWorkload(SPUThread & spu) { } } - memcpy(vm::get_ptr(spu.ls_offset + 0x100), spurs, 128); + memcpy(vm::get_ptr(spu.ls_offset + 0x100), spurs, 128); }); u64 result = (u64)wklSelectedId << 32; @@ -323,9 +323,9 @@ bool spursKernel2SelectWorkload(SPUThread & spu) { u32 wklSelectedId; u32 pollStatus; - vm::reservation_op(vm::cast(ctxt->spurs.addr()), 128, [&]() { + vm::reservation_op(vm::cast(ctxt->spurs.addr()), 128, [&]() { // lock the first 0x80 bytes of spurs - auto spurs = ctxt->spurs.get_priv_ptr(); + auto spurs = ctxt->spurs.get_priv_ptr(); // Calculate the contention (number of SPUs used) for each workload u8 contention[CELL_SPURS_MAX_WORKLOAD2]; @@ -449,7 +449,7 @@ bool spursKernel2SelectWorkload(SPUThread & spu) { } } - memcpy(vm::get_ptr(spu.ls_offset + 0x100), spurs, 128); + memcpy(vm::get_ptr(spu.ls_offset + 0x100), spurs, 128); }); u64 result = (u64)wklSelectedId << 32; @@ -471,7 +471,7 @@ void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus) { wid < CELL_SPURS_MAX_WORKLOAD2 && isKernel2 ? &ctxt->spurs->m.wklInfo2[wid & 0xf] : &ctxt->spurs->m.wklInfoSysSrv; - memcpy(vm::get_ptr(spu.ls_offset + 0x3FFE0), wklInfoOffset, 0x20); + memcpy(vm::get_ptr(spu.ls_offset + 0x3FFE0), wklInfoOffset, 0x20); // Load the workload to LS auto wklInfo = vm::get_ptr(spu.ls_offset + 0x3FFE0); @@ -484,7 +484,7 @@ void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus) { spu.RegisterHleFunction(0xA00, spursTasksetEntry); break; default: - memcpy(vm::get_ptr(spu.ls_offset + 0xA00), wklInfo->addr.get_ptr(), wklInfo->size); + memcpy(vm::get_ptr(spu.ls_offset + 0xA00), wklInfo->addr.get_ptr(), wklInfo->size); break; } @@ -598,7 +598,7 @@ void spursSysServiceIdleHandler(SPUThread & spu, SpursKernelContext * ctxt) { bool shouldExit; while (true) { - vm::reservation_acquire(vm::get_ptr(spu.ls_offset + 0x100), vm::cast(ctxt->spurs.addr()), 128, [&spu](){ spu.Notify(); }); + vm::reservation_acquire(vm::get_ptr(spu.ls_offset + 0x100), vm::cast(ctxt->spurs.addr()), 128, [&spu](){ spu.Notify(); }); auto spurs = vm::get_ptr(spu.ls_offset + 0x100); // Find the number of SPUs that are idling in this SPURS instance @@ -665,11 +665,11 @@ void spursSysServiceIdleHandler(SPUThread & spu, SpursKernelContext * ctxt) { // If all SPUs are idling and the exit_if_no_work flag is set then the SPU thread group must exit. Otherwise wait for external events. if (spuIdling && shouldExit == false && foundReadyWorkload == false) { // The system service blocks by making a reservation and waiting on the lock line reservation lost event. - spu.WaitForAnySignal(1); - if (Emu.IsStopped()) return; + spu.WaitForAnySignal(1); + if (Emu.IsStopped()) return; } - if (vm::reservation_update(vm::cast(ctxt->spurs.addr()), vm::get_ptr(spu.ls_offset + 0x100), 128) && (shouldExit || foundReadyWorkload)) { + if (vm::reservation_update(vm::cast(ctxt->spurs.addr()), vm::get_ptr(spu.ls_offset + 0x100), 128) && (shouldExit || foundReadyWorkload)) { break; } } @@ -684,7 +684,7 @@ void spursSysServiceMain(SPUThread & spu, u32 pollStatus) { auto ctxt = vm::get_ptr(spu.ls_offset + 0x100); if (ctxt->spurs.addr() % CellSpurs::align) { - assert(!"spursSysServiceMain(): invalid spurs alignment"); + assert(!"spursSysServiceMain(): invalid spurs alignment"); //spursHalt(spu); //return; } @@ -693,22 +693,22 @@ void spursSysServiceMain(SPUThread & spu, u32 pollStatus) { if (ctxt->sysSrvInitialised == 0) { ctxt->sysSrvInitialised = 1; - vm::reservation_acquire(vm::get_ptr(spu.ls_offset + 0x100), vm::cast(ctxt->spurs.addr()), 128); + vm::reservation_acquire(vm::get_ptr(spu.ls_offset + 0x100), vm::cast(ctxt->spurs.addr()), 128); - vm::reservation_op(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklState1)), 128, [&]() { - auto spurs = ctxt->spurs.get_priv_ptr(); + vm::reservation_op(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklState1)), 128, [&]() { + auto spurs = ctxt->spurs.get_priv_ptr(); // Halt if already initialised if (spurs->m.sysSrvOnSpu & (1 << ctxt->spuNum)) { - assert(!"spursSysServiceMain(): already initialized"); + assert(!"spursSysServiceMain(): already initialized"); //spursHalt(spu); //return; } spurs->m.sysSrvOnSpu |= 1 << ctxt->spuNum; - memcpy(vm::get_ptr(spu.ls_offset + 0x2D80), spurs->m.wklState1, 128); - }); + memcpy(vm::get_ptr(spu.ls_offset + 0x2D80), spurs->m.wklState1, 128); + }); ctxt->traceBuffer = 0; ctxt->traceMsgCount = -1; @@ -773,7 +773,7 @@ poll: cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); spursSysServiceIdleHandler(spu, ctxt); - if (Emu.IsStopped()) return; + if (Emu.IsStopped()) return; goto poll; } @@ -785,8 +785,8 @@ void spursSysServiceProcessRequests(SPUThread & spu, SpursKernelContext * ctxt) bool updateWorkload = false; bool terminate = false; - vm::reservation_op(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklState1)), 128, [&]() { - auto spurs = ctxt->spurs.get_priv_ptr(); + vm::reservation_op(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklState1)), 128, [&]() { + auto spurs = ctxt->spurs.get_priv_ptr(); // Terminate request if (spurs->m.sysSrvMsgTerminate & (1 << ctxt->spuNum)) { @@ -805,7 +805,7 @@ void spursSysServiceProcessRequests(SPUThread & spu, SpursKernelContext * ctxt) updateTrace = true; } - memcpy(vm::get_ptr(spu.ls_offset + 0x2D80), spurs->m.wklState1, 128); + memcpy(vm::get_ptr(spu.ls_offset + 0x2D80), spurs->m.wklState1, 128); }); // Process update workload message @@ -827,9 +827,9 @@ void spursSysServiceProcessRequests(SPUThread & spu, SpursKernelContext * ctxt) /// Activate a workload void spursSysServiceActivateWorkload(SPUThread & spu, SpursKernelContext * ctxt) { auto spurs = vm::get_ptr(spu.ls_offset + 0x100); - memcpy(vm::get_ptr(spu.ls_offset + 0x30000), vm::get_ptr(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklInfo1))), 0x200); + memcpy(vm::get_ptr(spu.ls_offset + 0x30000), vm::get_ptr(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklInfo1))), 0x200); if (spurs->m.flags1 & SF1_32_WORKLOADS) { - memcpy(vm::get_ptr(spu.ls_offset + 0x30200), vm::get_ptr(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklInfo2))), 0x200); + memcpy(vm::get_ptr(spu.ls_offset + 0x30200), vm::get_ptr(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklInfo2))), 0x200); } u32 wklShutdownBitSet = 0; @@ -852,8 +852,8 @@ void spursSysServiceActivateWorkload(SPUThread & spu, SpursKernelContext * ctxt) } } - vm::reservation_op(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklState1)), 128, [&]() { - auto spurs = ctxt->spurs.get_priv_ptr(); + vm::reservation_op(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklState1)), 128, [&]() { + auto spurs = ctxt->spurs.get_priv_ptr(); for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) { // Update workload status and runnable flag based on the workload state @@ -895,7 +895,7 @@ void spursSysServiceActivateWorkload(SPUThread & spu, SpursKernelContext * ctxt) } } - memcpy(vm::get_ptr(spu.ls_offset + 0x2D80), spurs->m.wklState1, 128); + memcpy(vm::get_ptr(spu.ls_offset + 0x2D80), spurs->m.wklState1, 128); }); if (wklShutdownBitSet) { @@ -909,8 +909,8 @@ void spursSysServiceUpdateShutdownCompletionEvents(SPUThread & spu, SpursKernelC // workloads that have a shutdown completion hook registered u32 wklNotifyBitSet; u8 spuPort; - vm::reservation_op(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklState1)), 128, [&]() { - auto spurs = ctxt->spurs.get_priv_ptr(); + vm::reservation_op(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklState1)), 128, [&]() { + auto spurs = ctxt->spurs.get_priv_ptr(); wklNotifyBitSet = 0; spuPort = spurs->m.spuPort;; @@ -930,7 +930,7 @@ void spursSysServiceUpdateShutdownCompletionEvents(SPUThread & spu, SpursKernelC } } - memcpy(vm::get_ptr(spu.ls_offset + 0x2D80), spurs->m.wklState1, 128); + memcpy(vm::get_ptr(spu.ls_offset + 0x2D80), spurs->m.wklState1, 128); }); if (wklNotifyBitSet) { @@ -951,8 +951,8 @@ void spursSysServiceTraceUpdate(SPUThread & spu, SpursKernelContext * ctxt, u32 bool notify; u8 sysSrvMsgUpdateTrace; - vm::reservation_op(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklState1)), 128, [&]() { - auto spurs = ctxt->spurs.get_priv_ptr(); + vm::reservation_op(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklState1)), 128, [&]() { + auto spurs = ctxt->spurs.get_priv_ptr(); sysSrvMsgUpdateTrace = spurs->m.sysSrvMsgUpdateTrace; spurs->m.sysSrvMsgUpdateTrace &= ~(1 << ctxt->spuNum); @@ -970,18 +970,18 @@ void spursSysServiceTraceUpdate(SPUThread & spu, SpursKernelContext * ctxt, u32 notify = true; } - memcpy(vm::get_ptr(spu.ls_offset + 0x2D80), spurs->m.wklState1, 128); + memcpy(vm::get_ptr(spu.ls_offset + 0x2D80), spurs->m.wklState1, 128); }); // Get trace parameters from CellSpurs and store them in the LS if (((sysSrvMsgUpdateTrace & (1 << ctxt->spuNum)) != 0) || (arg3 != 0)) { - vm::reservation_acquire(vm::get_ptr(spu.ls_offset + 0x80), vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.traceBuffer)), 128); + vm::reservation_acquire(vm::get_ptr(spu.ls_offset + 0x80), vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.traceBuffer)), 128); auto spurs = vm::get_ptr(spu.ls_offset + 0x80 - offsetof(CellSpurs, m.traceBuffer)); if (ctxt->traceMsgCount != 0xFF || spurs->m.traceBuffer.addr() == 0) { spursSysServiceTraceSaveCount(spu, ctxt); } else { - memcpy(vm::get_ptr(spu.ls_offset + 0x2C00), vm::get_ptr(spurs->m.traceBuffer.addr() & -0x4), 0x80); + memcpy(vm::get_ptr(spu.ls_offset + 0x2C00), vm::get_ptr(spurs->m.traceBuffer.addr() & -0x4), 0x80); auto traceBuffer = vm::get_ptr(spu.ls_offset + 0x2C00); ctxt->traceMsgCount = traceBuffer->count[ctxt->spuNum]; } @@ -1003,28 +1003,28 @@ void spursSysServiceTraceUpdate(SPUThread & spu, SpursKernelContext * ctxt, u32 void spursSysServiceCleanupAfterSystemWorkload(SPUThread & spu, SpursKernelContext * ctxt) { u8 wklId; - bool do_return = false; + bool do_return = false; - vm::reservation_op(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklState1)), 128, [&]() { + vm::reservation_op(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklState1)), 128, [&]() { auto spurs = ctxt->spurs.get_priv_ptr(); if (spurs->m.sysSrvWorkload[ctxt->spuNum] == 0xFF) { - do_return = true; + do_return = true; return; } wklId = spurs->m.sysSrvWorkload[ctxt->spuNum]; spurs->m.sysSrvWorkload[ctxt->spuNum] = 0xFF; - memcpy(vm::get_ptr(spu.ls_offset + 0x2D80), spurs->m.wklState1, 128); + memcpy(vm::get_ptr(spu.ls_offset + 0x2D80), spurs->m.wklState1, 128); }); - if (do_return) return; + if (do_return) return; spursSysServiceActivateWorkload(spu, ctxt); - vm::reservation_op(vm::cast(ctxt->spurs.addr()), 128, [&]() { - auto spurs = ctxt->spurs.get_priv_ptr(); + vm::reservation_op(vm::cast(ctxt->spurs.addr()), 128, [&]() { + auto spurs = ctxt->spurs.get_priv_ptr(); if (wklId >= CELL_SPURS_MAX_WORKLOAD) { spurs->m.wklCurrentContention[wklId & 0x0F] -= 0x10; @@ -1034,7 +1034,7 @@ void spursSysServiceCleanupAfterSystemWorkload(SPUThread & spu, SpursKernelConte spurs->m.wklIdleSpuCountOrReadyCount2[wklId & 0x0F].write_relaxed(spurs->m.wklIdleSpuCountOrReadyCount2[wklId & 0x0F].read_relaxed() - 1); } - memcpy(vm::get_ptr(spu.ls_offset + 0x100), spurs, 128); + memcpy(vm::get_ptr(spu.ls_offset + 0x100), spurs, 128); }); // Set the current workload id to the id of the pre-empted workload since cellSpursModulePutTrace @@ -1140,7 +1140,7 @@ void spursTasksetStartTask(SPUThread & spu, CellSpursTaskArgument & taskArgs) { auto taskset = vm::get_ptr(spu.ls_offset + 0x2700); spu.GPR[2].clear(); - spu.GPR[3] = taskArgs._u128; + spu.GPR[3] = u128::from64r(taskArgs._u64[0], taskArgs._u64[1]); spu.GPR[4]._u64[1] = taskset->m.args; spu.GPR[4]._u64[0] = taskset->m.spurs.addr(); for (auto i = 5; i < 128; i++) { @@ -1157,14 +1157,14 @@ s32 spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 * s32 rc = CELL_OK; s32 numNewlyReadyTasks; - vm::reservation_op(vm::cast(ctxt->taskset.addr()), 128, [&]() { - auto taskset = ctxt->taskset.get_priv_ptr(); + vm::reservation_op(vm::cast(ctxt->taskset.addr()), 128, [&]() { + auto taskset = ctxt->taskset.get_priv_ptr(); // Verify taskset state is valid auto _0 = be_t::make(u128::from32(0)); if ((taskset->m.waiting & taskset->m.running) != _0 || (taskset->m.ready & taskset->m.pending_ready) != _0 || ((taskset->m.running | taskset->m.ready | taskset->m.pending_ready | taskset->m.signalled | taskset->m.waiting) & be_t::make(~taskset->m.enabled.value())) != _0) { - assert(!"Invalid taskset state"); + assert(!"Invalid taskset state"); //spursHalt(spu); //return CELL_OK; } @@ -1282,7 +1282,7 @@ s32 spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 * } break; default: - assert(!"Unknown taskset request"); + assert(!"Unknown taskset request"); //spursHalt(spu); //return CELL_OK; } @@ -1294,12 +1294,12 @@ s32 spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 * taskset->m.signalled = signalled; taskset->m.ready = ready; - memcpy(vm::get_ptr(spu.ls_offset + 0x2700), taskset, 128); + memcpy(vm::get_ptr(spu.ls_offset + 0x2700), taskset, 128); }); // Increment the ready count of the workload by the number of tasks that have become ready - vm::reservation_op(vm::cast(kernelCtxt->spurs.addr()), 128, [&]() { - auto spurs = kernelCtxt->spurs.get_priv_ptr(); + vm::reservation_op(vm::cast(kernelCtxt->spurs.addr()), 128, [&]() { + auto spurs = kernelCtxt->spurs.get_priv_ptr(); s32 readyCount = kernelCtxt->wklCurrentId < CELL_SPURS_MAX_WORKLOAD ? spurs->m.wklReadyCount1[kernelCtxt->wklCurrentId].read_relaxed() : spurs->m.wklIdleSpuCountOrReadyCount2[kernelCtxt->wklCurrentId & 0x0F].read_relaxed(); readyCount += numNewlyReadyTasks; @@ -1311,7 +1311,7 @@ s32 spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 * spurs->m.wklIdleSpuCountOrReadyCount2[kernelCtxt->wklCurrentId & 0x0F].write_relaxed(readyCount); } - memcpy(vm::get_ptr(spu.ls_offset + 0x100), spurs, 128); + memcpy(vm::get_ptr(spu.ls_offset + 0x100), spurs, 128); }); return rc; @@ -1350,7 +1350,7 @@ void spursTasksetExit(SPUThread & spu) { // Not sure why this check exists. Perhaps to check for memory corruption. if (memcmp(ctxt->moduleId, "SPURSTASK MODULE", 16) != 0) { //spursHalt(spu); - assert(!"spursTasksetExit(): memory corruption"); + assert(!"spursTasksetExit(): memory corruption"); } cellSpursModuleExit(spu); @@ -1360,7 +1360,7 @@ void spursTasksetExit(SPUThread & spu) { void spursTasksetOnTaskExit(SPUThread & spu, u64 addr, u32 taskId, s32 exitCode, u64 args) { auto ctxt = vm::get_ptr(spu.ls_offset + 0x2700); - memcpy(vm::get_ptr(spu.ls_offset + 0x10000), vm::get_ptr(addr & -0x80), (addr & 0x7F) << 11); + memcpy(vm::get_ptr(spu.ls_offset + 0x10000), vm::get_ptr(addr & -0x80), (addr & 0x7F) << 11); spu.GPR[3]._u64[1] = ctxt->taskset.addr(); spu.GPR[4]._u32[3] = taskId; @@ -1382,8 +1382,9 @@ s32 spursTasketSaveTaskContext(SPUThread & spu) { u32 allocLsBlocks = taskInfo->context_save_storage_and_alloc_ls_blocks & 0x7F; u32 lsBlocks = 0; + u128 ls_pattern = u128::from64r(taskInfo->ls_pattern._u64[0], taskInfo->ls_pattern._u64[1]); for (auto i = 0; i < 128; i++) { - if (taskInfo->ls_pattern._u128.value()._bit[i]) { + if (ls_pattern._bit[i]) { lsBlocks++; } } @@ -1394,7 +1395,7 @@ s32 spursTasketSaveTaskContext(SPUThread & spu) { // Make sure the stack is area is specified in the ls pattern for (auto i = (ctxt->savedContextSp.value()._u32[3]) >> 11; i < 128; i++) { - if (taskInfo->ls_pattern._u128.value()._bit[i] == false) { + if (ls_pattern._bit[i] == false) { return CELL_SPURS_TASK_ERROR_STAT; } } @@ -1410,13 +1411,13 @@ s32 spursTasketSaveTaskContext(SPUThread & spu) { // Store the processor context const u32 contextSaveStorage = vm::cast(taskInfo->context_save_storage_and_alloc_ls_blocks & -0x80); - memcpy(vm::get_ptr(contextSaveStorage), vm::get_ptr(spu.ls_offset + 0x2C80), 0x380); + memcpy(vm::get_ptr(contextSaveStorage), vm::get_ptr(spu.ls_offset + 0x2C80), 0x380); // Save LS context for (auto i = 6; i < 128; i++) { - if (taskInfo->ls_pattern._u128.value()._bit[i]) { + if (ls_pattern._bit[i]) { // TODO: Combine DMA requests for consecutive blocks into a single request - memcpy(vm::get_ptr(contextSaveStorage + 0x400 + ((i - 6) << 11)), vm::get_ptr(spu.ls_offset + CELL_SPURS_TASK_TOP + ((i - 6) << 11)), 0x800); + memcpy(vm::get_ptr(contextSaveStorage + 0x400 + ((i - 6) << 11)), vm::get_ptr(spu.ls_offset + CELL_SPURS_TASK_TOP + ((i - 6) << 11)), 0x800); } } @@ -1440,7 +1441,7 @@ void spursTasksetDispatch(SPUThread & spu) { ctxt->taskId = taskId; // DMA in the task info for the selected task - memcpy(vm::get_ptr(spu.ls_offset + 0x2780), &ctxt->taskset->m.task_info[taskId], sizeof(CellSpursTaskset::TaskInfo)); + memcpy(vm::get_ptr(spu.ls_offset + 0x2780), &ctxt->taskset->m.task_info[taskId], sizeof(CellSpursTaskset::TaskInfo)); auto taskInfo = vm::get_ptr(spu.ls_offset + 0x2780); auto elfAddr = taskInfo->elf_addr.addr().value(); taskInfo->elf_addr.set(taskInfo->elf_addr.addr() & 0xFFFFFFFFFFFFFFF8ull); @@ -1461,7 +1462,7 @@ void spursTasksetDispatch(SPUThread & spu) { u32 entryPoint; u32 lowestLoadAddr; if (spursTasksetLoadElf(spu, &entryPoint, &lowestLoadAddr, taskInfo->elf_addr.addr(), false) != CELL_OK) { - assert(!"spursTaskLoadElf() failed"); + assert(!"spursTaskLoadElf() failed"); //spursHalt(spu); //return; } @@ -1476,7 +1477,7 @@ void spursTasksetDispatch(SPUThread & spu) { ctxt->x2FD4 = elfAddr & 5; // TODO: Figure this out if ((elfAddr & 5) == 1) { - memcpy(vm::get_ptr(spu.ls_offset + 0x2FC0), &((CellSpursTaskset2*)(ctxt->taskset.get_ptr()))->m.task_exit_code[taskId], 0x10); + memcpy(vm::get_ptr(spu.ls_offset + 0x2FC0), &((CellSpursTaskset2*)(ctxt->taskset.get_ptr()))->m.task_exit_code[taskId], 0x10); } // Trace - GUID @@ -1498,11 +1499,12 @@ void spursTasksetDispatch(SPUThread & spu) { } // If the entire LS is saved then there is no need to load the ELF as it will be be saved in the context save area as well - if (taskInfo->ls_pattern._u128.value() != u128::from64r(0x03FFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull)) { + u128 ls_pattern = u128::from64r(taskInfo->ls_pattern._u64[0], taskInfo->ls_pattern._u64[1]); + if (ls_pattern != u128::from64r(0x03FFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull)) { // Load the ELF u32 entryPoint; if (spursTasksetLoadElf(spu, &entryPoint, nullptr, taskInfo->elf_addr.addr(), true) != CELL_OK) { - assert(!"spursTasksetLoadElf() failed"); + assert(!"spursTasksetLoadElf() failed"); //spursHalt(spu); //return; } @@ -1510,11 +1512,11 @@ void spursTasksetDispatch(SPUThread & spu) { // Load saved context from main memory to LS const u32 contextSaveStorage = vm::cast(taskInfo->context_save_storage_and_alloc_ls_blocks & -0x80); - memcpy(vm::get_ptr(spu.ls_offset + 0x2C80), vm::get_ptr(contextSaveStorage), 0x380); + memcpy(vm::get_ptr(spu.ls_offset + 0x2C80), vm::get_ptr(contextSaveStorage), 0x380); for (auto i = 6; i < 128; i++) { - if (taskInfo->ls_pattern._u128.value()._bit[i]) { + if (ls_pattern._bit[i]) { // TODO: Combine DMA requests for consecutive blocks into a single request - memcpy(vm::get_ptr(spu.ls_offset + CELL_SPURS_TASK_TOP + ((i - 6) << 11)), vm::get_ptr(contextSaveStorage + 0x400 + ((i - 6) << 11)), 0x800); + memcpy(vm::get_ptr(spu.ls_offset + CELL_SPURS_TASK_TOP + ((i - 6) << 11)), vm::get_ptr(contextSaveStorage + 0x400 + ((i - 6) << 11)), 0x800); } } @@ -1597,7 +1599,7 @@ s32 spursTasksetProcessSyscall(SPUThread & spu, u32 syscallNum, u32 args) { break; case CELL_SPURS_TASK_SYSCALL_RECV_WKL_FLAG: if (args == 0) { // TODO: Figure this out - assert(!"args == 0"); + assert(!"args == 0"); //spursHalt(spu); } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp index 3a3f32ae6f..c524e17515 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp @@ -162,6 +162,17 @@ PPUThread* ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, bool i { PPUThread& new_thread = *(PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU); + // Note: (Syphurith) I haven't figured out the minimum stack size of PPU Thread. + // Maybe it can be done with pthread_attr_getstacksize function. + // And i toke 4096 (PTHREAD_STACK_MIN, and the smallest allocation unit) for this. + if ((stacksize % 4096) || (stacksize == 0)) { + // If not times of smallest allocation unit, round it up to the nearest one. + // And regard zero as a same condition. + sys_ppu_thread.Warning("sys_ppu_thread_create: stacksize increased from 0x%x to 0x%x.", + stacksize, 4096 * ((u32)(stacksize / 4096) + 1)); + stacksize = 4096 * ((u32)(stacksize / 4096) + 1); + } + u32 id = new_thread.GetId(); new_thread.SetEntry(entry); new_thread.SetPrio(prio);