diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp index 831748949b..2810152043 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp @@ -2427,7 +2427,7 @@ s64 cellSpursGetTasksetId(vm::ptr taskset, vm::ptr wid) return CELL_SPURS_TASK_ERROR_INVAL; } - *wid = taskset->m.wid.ToBE(); + *wid = taskset->m.wid; return CELL_OK; #endif } @@ -2443,6 +2443,121 @@ s64 cellSpursShutdownTaskset(vm::ptr taskset) #endif } +u32 _cellSpursGetSdkVersion() +{ + static u32 sdk_version = -2; + + if (sdk_version == -2) + { + auto version = vm::ptr::make((u32)Memory.Alloc(sizeof(u32), sizeof(u32))); + sys_process_get_sdk_version(sys_process_getpid(), version); + sdk_version = *version; + Memory.Free(version.addr()); + } + + return sdk_version; +} + +s64 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) +{ + if (!taskset || !elf_addr) + { + return CELL_SPURS_TASK_ERROR_NULL_POINTER; + } + + if (elf_addr.addr() % 16) + { + return CELL_SPURS_TASK_ERROR_ALIGN; + } + + auto sdk_version = _cellSpursGetSdkVersion(); + if (sdk_version < 0x27FFFF) + { + if (context_addr.addr() % 16) + { + return CELL_SPURS_TASK_ERROR_ALIGN; + } + } + else + { + if (context_addr.addr() % 128) + { + return CELL_SPURS_TASK_ERROR_ALIGN; + } + } + + u32 alloc_ls_blocks = 0; + if (context_addr.addr() != 0) + { + if (context_size < CELL_SPURS_TASK_EXECUTION_CONTEXT_SIZE) + { + return CELL_SPURS_TASK_ERROR_INVAL; + } + + alloc_ls_blocks = context_size > 0x3D400 ? 0x7A : ((context_size - 0x400) >> 11); + if (ls_pattern.addr() != 0) + { + u32 ls_blocks = 0; + for (u32 i = 0; i < 2; i++) + { + for (u32 j = 0; j < 64; j++) + { + if (ls_pattern->u64[0] & ((u64)1 << j)) + { + ls_blocks++; + } + } + } + + if (ls_blocks > alloc_ls_blocks) + { + return CELL_SPURS_TASK_ERROR_INVAL; + } + + if (ls_pattern->u32[0] & 0xFC000000) + { + // Prevent save/restore to SPURS management area + return CELL_SPURS_TASK_ERROR_INVAL; + } + } + } + else + { + alloc_ls_blocks = 0; + } + + // TODO: Verify the ELF header is proper and all its load segments are at address >= 0x3000 + + // TODO: Make the following block execute atomically + u32 tmp_task_id; + for (tmp_task_id = 0; tmp_task_id < CELL_SPURS_MAX_TASK; tmp_task_id++) + { + u32 l = tmp_task_id >> 5; + u32 b = tmp_task_id & 0x1F; + if ((taskset->m.enabled_set[l] & (0x80000000 >> b)) == 0) + { + taskset->m.enabled_set[l] |= 0x80000000 >> b; + break; + } + } + + if (tmp_task_id >= CELL_SPURS_MAX_TASK) + { + CELL_SPURS_TASK_ERROR_AGAIN; + } + + taskset->m.task_info[tmp_task_id].elf_addr.set(elf_addr.addr()); + taskset->m.task_info[tmp_task_id].context_save_storage.set((context_addr.addr() & 0xFFFFFFF8) | alloc_ls_blocks); + for (u32 i = 0; i < 2; i++) + { + taskset->m.task_info[tmp_task_id].args.u64[i] = arg != 0 ? arg->u64[i] : 0; + taskset->m.task_info[tmp_task_id].ls_pattern.u64[i] = ls_pattern != 0 ? ls_pattern->u64[i] : 0; + } + + *task_id = tmp_task_id; + return CELL_OK; +} + s64 cellSpursCreateTask(vm::ptr taskset, vm::ptr taskID, u32 elf_addr, u32 context_addr, u32 context_size, vm::ptr lsPattern, vm::ptr argument) { @@ -2451,8 +2566,7 @@ s64 cellSpursCreateTask(vm::ptr taskset, vm::ptr taskID, taskset.addr(), taskID.addr(), elf_addr, context_addr, context_size, lsPattern.addr(), argument.addr()); return GetCurrentPPUThread().FastCall2(libsre + 0x12414, libsre_rtoc); #else - UNIMPLEMENTED_FUNC(cellSpurs); - return CELL_OK; + return spursCreateTask(taskset, taskID, vm::ptr::make(elf_addr), vm::ptr::make(context_addr), context_size, lsPattern, argument); #endif } @@ -2883,7 +2997,7 @@ s64 cellSpursTasksetGetSpursAddress(vm::ptr taskset, vm: return CELL_SPURS_TASK_ERROR_INVAL; } - *spurs = (u32)taskset->m.spurs.addr().ToBE(); + *spurs = (u32)taskset->m.spurs.addr(); return CELL_OK; #endif } diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h index fc8871ecd6..4a8ba993af 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h @@ -132,6 +132,7 @@ enum TaskConstants CELL_SPURS_MAX_TASK_NAME_LENGTH = 32, CELL_SPURS_TASK_ATTRIBUTE_REVISION = 1, CELL_SPURS_TASKSET_ATTRIBUTE_REVISION = 1, + CELL_SPURS_TASK_EXECUTION_CONTEXT_SIZE = 1024, }; class SPURSManager; @@ -417,6 +418,18 @@ struct CellSpursEventFlag SPURSManagerEventFlag *eventFlag; }; +union CellSpursTaskArgument +{ + be_t u32[4]; + be_t u64[2]; +}; + +union CellSpursTaskLsPattern +{ + be_t u32[4]; + be_t u64[2]; +}; + struct CellSpursTaskset { static const u32 align = 128; @@ -429,14 +442,16 @@ struct CellSpursTaskset struct TaskInfo { - be_t args[4]; - vm::bptr elf; - vm::bptr context_save_storage; - be_t ls_pattern[4]; + CellSpursTaskArgument args; + vm::bptr elf_addr; + vm::bptr context_save_storage; // This is ((context_save_storage_addr & 0xFFFFFFF8) | allocated_ls_blocks) + CellSpursTaskLsPattern ls_pattern; }; + static_assert(sizeof(TaskInfo) == 0x30, "Wrong TaskInfo size"); + // Real data - struct + struct _CellSpursTaskset { be_t running_set[4]; // 0x00 be_t ready_set[4]; // 0x10 @@ -459,8 +474,11 @@ struct CellSpursTaskset u32 unk2; // 0x1894 u32 event_flag_id1; // 0x1898 u32 event_flag_id2; // 0x189C + u8 unk3[0x60]; // 0x18A0 } m; + static_assert(sizeof(_CellSpursTaskset) == size, "Wrong _CellSpursTaskset size"); + SPURSManagerTaskset *taskset; }; }; @@ -590,14 +608,16 @@ struct CellSpursTaskset2 struct TaskInfo { - be_t args[4]; - vm::bptr elf_address; - vm::bptr context_save_storage; - be_t ls_pattern[4]; + CellSpursTaskArgument args; + vm::bptr elf_addr; + vm::bptr context_save_storage; // This is ((context_save_storage_addr & 0xFFFFFFF8) | allocated_ls_blocks) + CellSpursTaskLsPattern ls_pattern; }; + static_assert(sizeof(TaskInfo) == 0x30, "Wrong TaskInfo size"); + // Real data - struct + struct _CellSpursTaskset2 { be_t running_set[4]; // 0x00 be_t ready_set[4]; // 0x10 @@ -620,9 +640,12 @@ struct CellSpursTaskset2 u32 unk2; // 0x1894 u32 event_flag_id1; // 0x1898 u32 event_flag_id2; // 0x189C - u8 unk3[0x88]; // 0x1900 - u128 task_exit_code[128]; // 0x1988 + u8 unk3[0xE8]; // 0x18A0 + u64 task_exit_code[256]; // 0x1988 + u8 unk4[0x778]; // 0x2188 } m; + + static_assert(sizeof(_CellSpursTaskset2) == size, "Wrong _CellSpursTaskset2 size"); }; }; @@ -681,21 +704,6 @@ struct CellSpursTraceTaskData be_t task; }; -typedef be_t be_u32; -typedef be_t be_u64; - -struct CellSpursTaskArgument -{ - be_u32 u32[4]; - be_u64 u64[2]; -}; - -struct CellSpursTaskLsPattern -{ - be_u32 u32[4]; - be_u64 u64[2]; -}; - struct CellSpursTaskAttribute2 { be_t revision;