This commit is contained in:
Nekotekina 2015-02-20 14:38:57 +03:00
commit 7ab1e64aab
5 changed files with 155 additions and 123 deletions

View file

@ -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 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) else if (reg == X64R_ECX)
{ {
out_value = (u32)RCX(context); out_value = (u32)RCX(context);

View file

@ -2284,14 +2284,18 @@ s32 cellSpursShutdownTaskset(vm::ptr<CellSpursTaskset> taskset)
u32 _cellSpursGetSdkVersion() 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) //if (process_get_sdk_version(process_getpid(), sdk_version) != CELL_OK)
{ //{
throw __FUNCTION__; // throw __FUNCTION__;
} //}
return sdk_version; //return sdk_version;
return 1;
} }
s32 spursCreateTask(vm::ptr<CellSpursTaskset> taskset, vm::ptr<u32> task_id, vm::ptr<u32> elf_addr, vm::ptr<u32> context_addr, u32 context_size, vm::ptr<CellSpursTaskLsPattern> ls_pattern, vm::ptr<CellSpursTaskArgument> arg) s32 spursCreateTask(vm::ptr<CellSpursTaskset> taskset, vm::ptr<u32> task_id, vm::ptr<u32> elf_addr, vm::ptr<u32> context_addr, u32 context_size, vm::ptr<CellSpursTaskLsPattern> ls_pattern, vm::ptr<CellSpursTaskArgument> arg)
@ -2333,10 +2337,11 @@ s32 spursCreateTask(vm::ptr<CellSpursTaskset> taskset, vm::ptr<u32> task_id, vm:
alloc_ls_blocks = context_size > 0x3D400 ? 0x7A : ((context_size - 0x400) >> 11); alloc_ls_blocks = context_size > 0x3D400 ? 0x7A : ((context_size - 0x400) >> 11);
if (ls_pattern.addr() != 0) 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++) for (auto i = 0; i < 128; i++)
{ {
if (ls_pattern->_u128.value()._bit[i]) if (ls_pattern_128._bit[i])
{ {
ls_blocks++; ls_blocks++;
} }
@ -2348,7 +2353,7 @@ s32 spursCreateTask(vm::ptr<CellSpursTaskset> taskset, vm::ptr<u32> task_id, vm:
} }
u128 _0 = u128::from32(0); 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 // Prevent save/restore to SPURS management area
return CELL_SPURS_TASK_ERROR_INVAL; return CELL_SPURS_TASK_ERROR_INVAL;
@ -2432,19 +2437,19 @@ s32 cellSpursCreateTask(vm::ptr<CellSpursTaskset> taskset, vm::ptr<u32> taskId,
vm::var<u32> tmpTaskId; vm::var<u32> tmpTaskId;
auto rc = spursCreateTask(taskset, tmpTaskId, vm::ptr<u32>::make(elf_addr), vm::ptr<u32>::make(context_addr), context_size, lsPattern, argument); auto rc = spursCreateTask(taskset, tmpTaskId, vm::ptr<u32>::make(elf_addr), vm::ptr<u32>::make(context_addr), context_size, lsPattern, argument);
if (rc != CELL_OK) if (rc != CELL_OK)
{ {
return rc; return rc;
} }
rc = spursTaskStart(taskset, tmpTaskId); rc = spursTaskStart(taskset, tmpTaskId);
if (rc != CELL_OK) if (rc != CELL_OK)
{ {
return rc; return rc;
} }
*taskId = tmpTaskId; *taskId = tmpTaskId;
return CELL_OK; return CELL_OK;
} }
s32 _cellSpursSendSignal(vm::ptr<CellSpursTaskset> taskset, u32 taskId) s32 _cellSpursSendSignal(vm::ptr<CellSpursTaskset> taskset, u32 taskId)
@ -2636,10 +2641,10 @@ s32 _cellSpursTaskAttribute2Initialize(vm::ptr<CellSpursTaskAttribute2> attribut
attribute->revision = revision; attribute->revision = revision;
attribute->sizeContext = 0; attribute->sizeContext = 0;
attribute->eaContext = 0; attribute->eaContext = 0;
for (s32 c = 0; c < 4; c++) for (s32 c = 0; c < 4; c++)
{ {
attribute->lsPattern._u128 = u128::from64r(0); attribute->lsPattern._u32[c] = 0;
} }
attribute->name_addr = 0; attribute->name_addr = 0;

View file

@ -623,12 +623,14 @@ static_assert(sizeof(CellSpursEventFlag) == CellSpursEventFlag::size, "Wrong Cel
union CellSpursTaskArgument union CellSpursTaskArgument
{ {
be_t<u128> _u128; be_t<u32> _u32[4];
be_t<u64> _u64[2];
}; };
union CellSpursTaskLsPattern union CellSpursTaskLsPattern
{ {
be_t<u128> _u128; be_t<u32> _u32[4];
be_t<u64> _u64[2];
}; };
struct CellSpursTaskset 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. // The SPURS taskset policy module context. This resides at 0x2700 of the LS.
struct SpursTasksetContext struct SpursTasksetContext
{ {
u8 tempAreaTaskset[0x80]; // 0x2700 u8 tempAreaTaskset[0x80]; // 0x2700
u8 tempAreaTaskInfo[0x30]; // 0x2780 u8 tempAreaTaskInfo[0x30]; // 0x2780
be_t<u64> x27B0; // 0x27B0 be_t<u64> x27B0; // 0x27B0
vm::bptr<CellSpursTaskset, 1, u64> taskset; // 0x27B8 vm::bptr<CellSpursTaskset, 1, u64> taskset; // 0x27B8
be_t<u32> kernelMgmtAddr; // 0x27C0 be_t<u32> kernelMgmtAddr; // 0x27C0
be_t<u32> syscallAddr; // 0x27C4 be_t<u32> syscallAddr; // 0x27C4
be_t<u32> x27C8; // 0x27C8 be_t<u32> x27C8; // 0x27C8
be_t<u32> spuNum; // 0x27CC be_t<u32> spuNum; // 0x27CC
be_t<u32> dmaTagId; // 0x27D0 be_t<u32> dmaTagId; // 0x27D0
be_t<u32> taskId; // 0x27D4 be_t<u32> taskId; // 0x27D4
u8 x27D8[0x2840 - 0x27D8]; // 0x27D8 u8 x27D8[0x2840 - 0x27D8]; // 0x27D8
u8 moduleId[16]; // 0x2840 u8 moduleId[16]; // 0x2840
u8 stackArea[0x2C80 - 0x2850]; // 0x2850 u8 stackArea[0x2C80 - 0x2850]; // 0x2850
be_t<u128> savedContextLr; // 0x2C80 be_t<u128> savedContextLr; // 0x2C80
be_t<u128> savedContextSp; // 0x2C90 be_t<u128> savedContextSp; // 0x2C90
be_t<u128> savedContextR80ToR127[48]; // 0x2CA0 be_t<u128> savedContextR80ToR127[48]; // 0x2CA0
be_t<u128> savedContextFpscr; // 0x2FA0 be_t<u128> savedContextFpscr; // 0x2FA0
be_t<u32> savedWriteTagGroupQueryMask; // 0x2FB0 be_t<u32> savedWriteTagGroupQueryMask; // 0x2FB0
be_t<u32> savedSpuWriteEventMask; // 0x2FB4 be_t<u32> savedSpuWriteEventMask; // 0x2FB4
be_t<u32> tasksetMgmtAddr; // 0x2FB8 be_t<u32> tasksetMgmtAddr; // 0x2FB8
be_t<u32> guidAddr; // 0x2FBC be_t<u32> guidAddr; // 0x2FBC
be_t<u64> x2FC0; // 0x2FC0 be_t<u64> x2FC0; // 0x2FC0
be_t<u64> x2FC8; // 0x2FC8 be_t<u64> x2FC8; // 0x2FC8
be_t<u32> taskExitCode; // 0x2FD0 be_t<u32> taskExitCode; // 0x2FD0
be_t<u32> x2FD4; // 0x2FD4 be_t<u32> x2FD4; // 0x2FD4
u8 x2FD8[0x3000 - 0x2FD8]; // 0x2FD8 u8 x2FD8[0x3000 - 0x2FD8]; // 0x2FD8
}; };
static_assert(sizeof(SpursTasksetContext) == 0x900, "Incorrect size for SpursTasksetContext"); static_assert(sizeof(SpursTasksetContext) == 0x900, "Incorrect size for SpursTasksetContext");

View file

@ -156,19 +156,19 @@ void spursHalt(SPUThread & spu) {
/// Select a workload to run /// Select a workload to run
bool spursKernel1SelectWorkload(SPUThread & spu) { bool spursKernel1SelectWorkload(SPUThread & spu) {
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.ls_offset + 0x100); auto ctxt = vm::get_ptr<SpursKernelContext>(spu.ls_offset + 0x100);
// The first and only argument to this function is a boolean that is set to false if the function // 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. // 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. // 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 wklSelectedId;
u32 pollStatus; 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 // 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 // Calculate the contention (number of SPUs used) for each workload
u8 contention[CELL_SPURS_MAX_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; u64 result = (u64)wklSelectedId << 32;
@ -323,9 +323,9 @@ bool spursKernel2SelectWorkload(SPUThread & spu) {
u32 wklSelectedId; u32 wklSelectedId;
u32 pollStatus; 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 // 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 // Calculate the contention (number of SPUs used) for each workload
u8 contention[CELL_SPURS_MAX_WORKLOAD2]; 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; 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] : wid < CELL_SPURS_MAX_WORKLOAD2 && isKernel2 ? &ctxt->spurs->m.wklInfo2[wid & 0xf] :
&ctxt->spurs->m.wklInfoSysSrv; &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 // Load the workload to LS
auto wklInfo = vm::get_ptr<CellSpurs::WorkloadInfo>(spu.ls_offset + 0x3FFE0); auto wklInfo = vm::get_ptr<CellSpurs::WorkloadInfo>(spu.ls_offset + 0x3FFE0);
@ -484,7 +484,7 @@ void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus) {
spu.RegisterHleFunction(0xA00, spursTasksetEntry); spu.RegisterHleFunction(0xA00, spursTasksetEntry);
break; break;
default: 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; break;
} }
@ -598,7 +598,7 @@ void spursSysServiceIdleHandler(SPUThread & spu, SpursKernelContext * ctxt) {
bool shouldExit; bool shouldExit;
while (true) { 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<CellSpurs>(spu.ls_offset + 0x100); auto spurs = vm::get_ptr<CellSpurs>(spu.ls_offset + 0x100);
// Find the number of SPUs that are idling in this SPURS instance // 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 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) { if (spuIdling && shouldExit == false && foundReadyWorkload == false) {
// The system service blocks by making a reservation and waiting on the lock line reservation lost event. // The system service blocks by making a reservation and waiting on the lock line reservation lost event.
spu.WaitForAnySignal(1); spu.WaitForAnySignal(1);
if (Emu.IsStopped()) return; 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; break;
} }
} }
@ -684,7 +684,7 @@ void spursSysServiceMain(SPUThread & spu, u32 pollStatus) {
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.ls_offset + 0x100); auto ctxt = vm::get_ptr<SpursKernelContext>(spu.ls_offset + 0x100);
if (ctxt->spurs.addr() % CellSpurs::align) { if (ctxt->spurs.addr() % CellSpurs::align) {
assert(!"spursSysServiceMain(): invalid spurs alignment"); assert(!"spursSysServiceMain(): invalid spurs alignment");
//spursHalt(spu); //spursHalt(spu);
//return; //return;
} }
@ -693,22 +693,22 @@ void spursSysServiceMain(SPUThread & spu, u32 pollStatus) {
if (ctxt->sysSrvInitialised == 0) { if (ctxt->sysSrvInitialised == 0) {
ctxt->sysSrvInitialised = 1; 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, [&]() { vm::reservation_op(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklState1)), 128, [&]() {
auto spurs = ctxt->spurs.get_priv_ptr(); auto spurs = ctxt->spurs.get_priv_ptr();
// Halt if already initialised // Halt if already initialised
if (spurs->m.sysSrvOnSpu & (1 << ctxt->spuNum)) { if (spurs->m.sysSrvOnSpu & (1 << ctxt->spuNum)) {
assert(!"spursSysServiceMain(): already initialized"); assert(!"spursSysServiceMain(): already initialized");
//spursHalt(spu); //spursHalt(spu);
//return; //return;
} }
spurs->m.sysSrvOnSpu |= 1 << ctxt->spuNum; 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->traceBuffer = 0;
ctxt->traceMsgCount = -1; ctxt->traceMsgCount = -1;
@ -773,7 +773,7 @@ poll:
cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); cellSpursModulePutTrace(&pkt, ctxt->dmaTagId);
spursSysServiceIdleHandler(spu, ctxt); spursSysServiceIdleHandler(spu, ctxt);
if (Emu.IsStopped()) return; if (Emu.IsStopped()) return;
goto poll; goto poll;
} }
@ -785,8 +785,8 @@ void spursSysServiceProcessRequests(SPUThread & spu, SpursKernelContext * ctxt)
bool updateWorkload = false; bool updateWorkload = false;
bool terminate = false; bool terminate = 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(); auto spurs = ctxt->spurs.get_priv_ptr();
// Terminate request // Terminate request
if (spurs->m.sysSrvMsgTerminate & (1 << ctxt->spuNum)) { if (spurs->m.sysSrvMsgTerminate & (1 << ctxt->spuNum)) {
@ -805,7 +805,7 @@ void spursSysServiceProcessRequests(SPUThread & spu, SpursKernelContext * ctxt)
updateTrace = true; 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 // Process update workload message
@ -827,9 +827,9 @@ void spursSysServiceProcessRequests(SPUThread & spu, SpursKernelContext * ctxt)
/// Activate a workload /// Activate a workload
void spursSysServiceActivateWorkload(SPUThread & spu, SpursKernelContext * ctxt) { void spursSysServiceActivateWorkload(SPUThread & spu, SpursKernelContext * ctxt) {
auto spurs = vm::get_ptr<CellSpurs>(spu.ls_offset + 0x100); auto spurs = vm::get_ptr<CellSpurs>(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) { 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; 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, [&]() { vm::reservation_op(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklState1)), 128, [&]() {
auto spurs = ctxt->spurs.get_priv_ptr(); auto spurs = ctxt->spurs.get_priv_ptr();
for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) { for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) {
// Update workload status and runnable flag based on the workload state // 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) { if (wklShutdownBitSet) {
@ -909,8 +909,8 @@ void spursSysServiceUpdateShutdownCompletionEvents(SPUThread & spu, SpursKernelC
// workloads that have a shutdown completion hook registered // workloads that have a shutdown completion hook registered
u32 wklNotifyBitSet; u32 wklNotifyBitSet;
u8 spuPort; u8 spuPort;
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(); auto spurs = ctxt->spurs.get_priv_ptr();
wklNotifyBitSet = 0; wklNotifyBitSet = 0;
spuPort = spurs->m.spuPort;; 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) { if (wklNotifyBitSet) {
@ -951,8 +951,8 @@ void spursSysServiceTraceUpdate(SPUThread & spu, SpursKernelContext * ctxt, u32
bool notify; bool notify;
u8 sysSrvMsgUpdateTrace; u8 sysSrvMsgUpdateTrace;
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(); auto spurs = ctxt->spurs.get_priv_ptr();
sysSrvMsgUpdateTrace = spurs->m.sysSrvMsgUpdateTrace; sysSrvMsgUpdateTrace = spurs->m.sysSrvMsgUpdateTrace;
spurs->m.sysSrvMsgUpdateTrace &= ~(1 << ctxt->spuNum); spurs->m.sysSrvMsgUpdateTrace &= ~(1 << ctxt->spuNum);
@ -970,18 +970,18 @@ void spursSysServiceTraceUpdate(SPUThread & spu, SpursKernelContext * ctxt, u32
notify = true; 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 // Get trace parameters from CellSpurs and store them in the LS
if (((sysSrvMsgUpdateTrace & (1 << ctxt->spuNum)) != 0) || (arg3 != 0)) { 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<CellSpurs>(spu.ls_offset + 0x80 - offsetof(CellSpurs, m.traceBuffer)); auto spurs = vm::get_ptr<CellSpurs>(spu.ls_offset + 0x80 - offsetof(CellSpurs, m.traceBuffer));
if (ctxt->traceMsgCount != 0xFF || spurs->m.traceBuffer.addr() == 0) { if (ctxt->traceMsgCount != 0xFF || spurs->m.traceBuffer.addr() == 0) {
spursSysServiceTraceSaveCount(spu, ctxt); spursSysServiceTraceSaveCount(spu, ctxt);
} else { } 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<CellSpursTraceInfo>(spu.ls_offset + 0x2C00); auto traceBuffer = vm::get_ptr<CellSpursTraceInfo>(spu.ls_offset + 0x2C00);
ctxt->traceMsgCount = traceBuffer->count[ctxt->spuNum]; ctxt->traceMsgCount = traceBuffer->count[ctxt->spuNum];
} }
@ -1003,28 +1003,28 @@ void spursSysServiceTraceUpdate(SPUThread & spu, SpursKernelContext * ctxt, u32
void spursSysServiceCleanupAfterSystemWorkload(SPUThread & spu, SpursKernelContext * ctxt) { void spursSysServiceCleanupAfterSystemWorkload(SPUThread & spu, SpursKernelContext * ctxt) {
u8 wklId; 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(); auto spurs = ctxt->spurs.get_priv_ptr();
if (spurs->m.sysSrvWorkload[ctxt->spuNum] == 0xFF) { if (spurs->m.sysSrvWorkload[ctxt->spuNum] == 0xFF) {
do_return = true; do_return = true;
return; return;
} }
wklId = spurs->m.sysSrvWorkload[ctxt->spuNum]; wklId = spurs->m.sysSrvWorkload[ctxt->spuNum];
spurs->m.sysSrvWorkload[ctxt->spuNum] = 0xFF; 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); spursSysServiceActivateWorkload(spu, ctxt);
vm::reservation_op(vm::cast(ctxt->spurs.addr()), 128, [&]() { vm::reservation_op(vm::cast(ctxt->spurs.addr()), 128, [&]() {
auto spurs = ctxt->spurs.get_priv_ptr(); auto spurs = ctxt->spurs.get_priv_ptr();
if (wklId >= CELL_SPURS_MAX_WORKLOAD) { if (wklId >= CELL_SPURS_MAX_WORKLOAD) {
spurs->m.wklCurrentContention[wklId & 0x0F] -= 0x10; 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); 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 // 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<CellSpursTaskset>(spu.ls_offset + 0x2700); auto taskset = vm::get_ptr<CellSpursTaskset>(spu.ls_offset + 0x2700);
spu.GPR[2].clear(); 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[1] = taskset->m.args;
spu.GPR[4]._u64[0] = taskset->m.spurs.addr(); spu.GPR[4]._u64[0] = taskset->m.spurs.addr();
for (auto i = 5; i < 128; i++) { 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 rc = CELL_OK;
s32 numNewlyReadyTasks; s32 numNewlyReadyTasks;
vm::reservation_op(vm::cast(ctxt->taskset.addr()), 128, [&]() { vm::reservation_op(vm::cast(ctxt->taskset.addr()), 128, [&]() {
auto taskset = ctxt->taskset.get_priv_ptr(); auto taskset = ctxt->taskset.get_priv_ptr();
// Verify taskset state is valid // Verify taskset state is valid
auto _0 = be_t<u128>::make(u128::from32(0)); auto _0 = be_t<u128>::make(u128::from32(0));
if ((taskset->m.waiting & taskset->m.running) != _0 || (taskset->m.ready & taskset->m.pending_ready) != _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<u128>::make(~taskset->m.enabled.value())) != _0) { ((taskset->m.running | taskset->m.ready | taskset->m.pending_ready | taskset->m.signalled | taskset->m.waiting) & be_t<u128>::make(~taskset->m.enabled.value())) != _0) {
assert(!"Invalid taskset state"); assert(!"Invalid taskset state");
//spursHalt(spu); //spursHalt(spu);
//return CELL_OK; //return CELL_OK;
} }
@ -1282,7 +1282,7 @@ s32 spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 *
} }
break; break;
default: default:
assert(!"Unknown taskset request"); assert(!"Unknown taskset request");
//spursHalt(spu); //spursHalt(spu);
//return CELL_OK; //return CELL_OK;
} }
@ -1294,12 +1294,12 @@ s32 spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 *
taskset->m.signalled = signalled; taskset->m.signalled = signalled;
taskset->m.ready = ready; 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 // 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, [&]() { vm::reservation_op(vm::cast(kernelCtxt->spurs.addr()), 128, [&]() {
auto spurs = kernelCtxt->spurs.get_priv_ptr(); 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(); 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; readyCount += numNewlyReadyTasks;
@ -1311,7 +1311,7 @@ s32 spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 *
spurs->m.wklIdleSpuCountOrReadyCount2[kernelCtxt->wklCurrentId & 0x0F].write_relaxed(readyCount); 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; return rc;
@ -1350,7 +1350,7 @@ void spursTasksetExit(SPUThread & spu) {
// Not sure why this check exists. Perhaps to check for memory corruption. // Not sure why this check exists. Perhaps to check for memory corruption.
if (memcmp(ctxt->moduleId, "SPURSTASK MODULE", 16) != 0) { if (memcmp(ctxt->moduleId, "SPURSTASK MODULE", 16) != 0) {
//spursHalt(spu); //spursHalt(spu);
assert(!"spursTasksetExit(): memory corruption"); assert(!"spursTasksetExit(): memory corruption");
} }
cellSpursModuleExit(spu); cellSpursModuleExit(spu);
@ -1360,7 +1360,7 @@ void spursTasksetExit(SPUThread & spu) {
void spursTasksetOnTaskExit(SPUThread & spu, u64 addr, u32 taskId, s32 exitCode, u64 args) { void spursTasksetOnTaskExit(SPUThread & spu, u64 addr, u32 taskId, s32 exitCode, u64 args) {
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.ls_offset + 0x2700); auto ctxt = vm::get_ptr<SpursTasksetContext>(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[3]._u64[1] = ctxt->taskset.addr();
spu.GPR[4]._u32[3] = taskId; 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 allocLsBlocks = taskInfo->context_save_storage_and_alloc_ls_blocks & 0x7F;
u32 lsBlocks = 0; 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++) { for (auto i = 0; i < 128; i++) {
if (taskInfo->ls_pattern._u128.value()._bit[i]) { if (ls_pattern._bit[i]) {
lsBlocks++; lsBlocks++;
} }
} }
@ -1394,7 +1395,7 @@ s32 spursTasketSaveTaskContext(SPUThread & spu) {
// Make sure the stack is area is specified in the ls pattern // Make sure the stack is area is specified in the ls pattern
for (auto i = (ctxt->savedContextSp.value()._u32[3]) >> 11; i < 128; i++) { 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; return CELL_SPURS_TASK_ERROR_STAT;
} }
} }
@ -1410,13 +1411,13 @@ s32 spursTasketSaveTaskContext(SPUThread & spu) {
// Store the processor context // Store the processor context
const u32 contextSaveStorage = vm::cast(taskInfo->context_save_storage_and_alloc_ls_blocks & -0x80); 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 // Save LS context
for (auto i = 6; i < 128; i++) { 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 // 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; ctxt->taskId = taskId;
// DMA in the task info for the selected task // 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<CellSpursTaskset::TaskInfo>(spu.ls_offset + 0x2780); auto taskInfo = vm::get_ptr<CellSpursTaskset::TaskInfo>(spu.ls_offset + 0x2780);
auto elfAddr = taskInfo->elf_addr.addr().value(); auto elfAddr = taskInfo->elf_addr.addr().value();
taskInfo->elf_addr.set(taskInfo->elf_addr.addr() & 0xFFFFFFFFFFFFFFF8ull); taskInfo->elf_addr.set(taskInfo->elf_addr.addr() & 0xFFFFFFFFFFFFFFF8ull);
@ -1461,7 +1462,7 @@ void spursTasksetDispatch(SPUThread & spu) {
u32 entryPoint; u32 entryPoint;
u32 lowestLoadAddr; u32 lowestLoadAddr;
if (spursTasksetLoadElf(spu, &entryPoint, &lowestLoadAddr, taskInfo->elf_addr.addr(), false) != CELL_OK) { if (spursTasksetLoadElf(spu, &entryPoint, &lowestLoadAddr, taskInfo->elf_addr.addr(), false) != CELL_OK) {
assert(!"spursTaskLoadElf() failed"); assert(!"spursTaskLoadElf() failed");
//spursHalt(spu); //spursHalt(spu);
//return; //return;
} }
@ -1476,7 +1477,7 @@ void spursTasksetDispatch(SPUThread & spu) {
ctxt->x2FD4 = elfAddr & 5; // TODO: Figure this out ctxt->x2FD4 = elfAddr & 5; // TODO: Figure this out
if ((elfAddr & 5) == 1) { 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 // 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 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 // Load the ELF
u32 entryPoint; u32 entryPoint;
if (spursTasksetLoadElf(spu, &entryPoint, nullptr, taskInfo->elf_addr.addr(), true) != CELL_OK) { if (spursTasksetLoadElf(spu, &entryPoint, nullptr, taskInfo->elf_addr.addr(), true) != CELL_OK) {
assert(!"spursTasksetLoadElf() failed"); assert(!"spursTasksetLoadElf() failed");
//spursHalt(spu); //spursHalt(spu);
//return; //return;
} }
@ -1510,11 +1512,11 @@ void spursTasksetDispatch(SPUThread & spu) {
// Load saved context from main memory to LS // Load saved context from main memory to LS
const u32 contextSaveStorage = vm::cast(taskInfo->context_save_storage_and_alloc_ls_blocks & -0x80); 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++) { 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 // 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; break;
case CELL_SPURS_TASK_SYSCALL_RECV_WKL_FLAG: case CELL_SPURS_TASK_SYSCALL_RECV_WKL_FLAG:
if (args == 0) { // TODO: Figure this out if (args == 0) { // TODO: Figure this out
assert(!"args == 0"); assert(!"args == 0");
//spursHalt(spu); //spursHalt(spu);
} }

View file

@ -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); 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(); u32 id = new_thread.GetId();
new_thread.SetEntry(entry); new_thread.SetEntry(entry);
new_thread.SetPrio(prio); new_thread.SetPrio(prio);