sys_spu: Fix SPU Thread Id

* Removed wrong code in sys_spu_thread_group_terminate.
* SPU Thread ID is accurate, including 5th thread id "rule".
* Fixed possible use-after-free access of spu_thread::group member.
* RawSPU ID management simplified.
This commit is contained in:
Eladash 2019-11-03 01:44:02 +02:00 committed by Ivan
parent e050dcbc52
commit 5631382623
7 changed files with 122 additions and 120 deletions

View file

@ -1319,14 +1319,15 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
{ {
data2 = (SYS_MEMORY_PAGE_FAULT_TYPE_PPU_THREAD << 32) | cpu->id; data2 = (SYS_MEMORY_PAGE_FAULT_TYPE_PPU_THREAD << 32) | cpu->id;
} }
else if (static_cast<spu_thread*>(cpu)->group)
{
data2 = (SYS_MEMORY_PAGE_FAULT_TYPE_SPU_THREAD << 32) | cpu->id;
}
else else
{ {
// Index is the correct ID in RawSPU const auto& spu = static_cast<spu_thread&>(*cpu);
data2 = (SYS_MEMORY_PAGE_FAULT_TYPE_RAW_SPU << 32) | static_cast<spu_thread*>(cpu)->index;
const u64 type = spu.offset < RAW_SPU_BASE_ADDR ?
SYS_MEMORY_PAGE_FAULT_TYPE_SPU_THREAD :
SYS_MEMORY_PAGE_FAULT_TYPE_RAW_SPU;
data2 = (type << 32) | spu.lv2_id;
} }
u64 data3; u64 data3;

View file

@ -266,7 +266,7 @@ bool spu_thread::write_reg(const u32 addr, const u32 value)
void spu_load_exec(const spu_exec_object& elf) void spu_load_exec(const spu_exec_object& elf)
{ {
auto ls0 = vm::cast(vm::falloc(RAW_SPU_BASE_ADDR, 0x80000, vm::spu)); auto ls0 = vm::cast(vm::falloc(RAW_SPU_BASE_ADDR, 0x80000, vm::spu));
auto spu = idm::make_ptr<named_thread<spu_thread>>("TEST_SPU", ls0, nullptr, 0, ""); auto spu = idm::make_ptr<named_thread<spu_thread>>("TEST_SPU", ls0, nullptr, 0, "", 0);
spu_thread::g_raw_spu_ctr++; spu_thread::g_raw_spu_ctr++;
spu_thread::g_raw_spu_id[0] = spu->id; spu_thread::g_raw_spu_id[0] = spu->id;

View file

@ -991,7 +991,7 @@ spu_imm_table_t::spu_imm_table_t()
std::string spu_thread::get_name() const std::string spu_thread::get_name() const
{ {
return fmt::format("%sSPU[0x%x] Thread (%s)", offset >= RAW_SPU_BASE_ADDR ? "Raw" : "", id, spu_name.get()); return fmt::format("%sSPU[0x%07x] Thread (%s)", offset >= RAW_SPU_BASE_ADDR ? "Raw" : "", lv2_id, spu_name.get());
} }
std::string spu_thread::dump() const std::string spu_thread::dump() const
@ -1202,12 +1202,13 @@ spu_thread::~spu_thread()
} }
} }
spu_thread::spu_thread(vm::addr_t ls, lv2_spu_group* group, u32 index, std::string_view name) spu_thread::spu_thread(vm::addr_t ls, lv2_spu_group* group, u32 index, std::string_view name, u32 lv2_id)
: cpu_thread(idm::last_id()) : cpu_thread(idm::last_id())
, spu_name(name) , spu_name(name)
, index(index) , index(index)
, offset(ls) , offset(ls)
, group(group) , group(group)
, lv2_id(lv2_id)
{ {
if (g_cfg.core.spu_decoder == spu_decoder_type::asmjit) if (g_cfg.core.spu_decoder == spu_decoder_type::asmjit)
{ {
@ -1295,9 +1296,9 @@ void spu_thread::do_dma_transfer(const spu_mfc_cmd& args)
{ {
fmt::throw_exception("SPU MMIO used for RawSPU (cmd=0x%x, lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x)" HERE, args.cmd, args.lsa, args.eal, args.tag, args.size); fmt::throw_exception("SPU MMIO used for RawSPU (cmd=0x%x, lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x)" HERE, args.cmd, args.lsa, args.eal, args.tag, args.size);
} }
else if (group && group->threads[index]) else if (group && group->threads_map[index] != -1)
{ {
auto& spu = static_cast<spu_thread&>(*group->threads[index]); auto& spu = static_cast<spu_thread&>(*group->threads[group->threads_map[index]]);
if (offset + args.size - 1 < 0x40000) // LS access if (offset + args.size - 1 < 0x40000) // LS access
{ {
@ -2506,7 +2507,7 @@ bool spu_thread::set_ch_value(u32 ch, u32 value)
ch_in_mbox.set_values(1, CELL_OK); ch_in_mbox.set_values(1, CELL_OK);
if (!queue->send(SYS_SPU_THREAD_EVENT_USER_KEY, id, (u64{spup} << 32) | (value & 0x00ffffff), data)) if (!queue->send(SYS_SPU_THREAD_EVENT_USER_KEY, lv2_id, (u64{spup} << 32) | (value & 0x00ffffff), data))
{ {
ch_in_mbox.set_values(1, CELL_EBUSY); ch_in_mbox.set_values(1, CELL_EBUSY);
} }
@ -2536,7 +2537,7 @@ bool spu_thread::set_ch_value(u32 ch, u32 value)
} }
// TODO: check passing spup value // TODO: check passing spup value
if (!queue->send(SYS_SPU_THREAD_EVENT_USER_KEY, id, (u64{spup} << 32) | (value & 0x00ffffff), data)) if (!queue->send(SYS_SPU_THREAD_EVENT_USER_KEY, lv2_id, (u64{spup} << 32) | (value & 0x00ffffff), data))
{ {
LOG_WARNING(SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x) failed (queue is full)", spup, (value & 0x00ffffff), data); LOG_WARNING(SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x) failed (queue is full)", spup, (value & 0x00ffffff), data);
} }

View file

@ -510,7 +510,7 @@ public:
static const u32 id_step = 1; static const u32 id_step = 1;
static const u32 id_count = 2048; static const u32 id_count = 2048;
spu_thread(vm::addr_t ls, lv2_spu_group* group, u32 index, std::string_view name); spu_thread(vm::addr_t ls, lv2_spu_group* group, u32 index, std::string_view name, u32 lv2_id);
u32 pc = 0; u32 pc = 0;
@ -575,7 +575,10 @@ public:
const u32 index; // SPU index const u32 index; // SPU index
const u32 offset; // SPU LS offset const u32 offset; // SPU LS offset
lv2_spu_group* const group; // SPU Thread Group private:
lv2_spu_group* const group; // SPU Thread Group (only safe to access in the spu thread itself)
public:
const u32 lv2_id; // The actual id that is used by syscalls
lf_value<std::string> spu_name; // Thread name lf_value<std::string> spu_name; // Thread name

View file

@ -141,6 +141,29 @@ void sys_spu_image::deploy(u32 loc, sys_spu_segment* segs, u32 nsegs)
LOG_NOTICE(LOADER, "Loaded SPU image: %s (<- %u)%s", hash, applied, dump); LOG_NOTICE(LOADER, "Loaded SPU image: %s (<- %u)%s", hash, applied, dump);
} }
// Get spu thread ptr, returns group ptr as well for refcounting
std::pair<named_thread<spu_thread>*, std::shared_ptr<lv2_spu_group>> lv2_spu_group::get_thread(u32 id)
{
if (id >= 0x06000000)
{
// thread index is out of range (5 max)
return {};
}
// Bits 0-23 contain group id (without id base)
decltype(get_thread(0)) res{nullptr, idm::get<lv2_spu_group>((id & 0xFFFFFF) | (lv2_spu_group::id_base & ~0xFFFFFF))};
// Bits 24-31 contain thread index within the group
const u32 index = id >> 24;
if (auto group = res.second.get(); group && group->init > index)
{
res.first = group->threads[index].get();
}
return res;
}
error_code sys_spu_initialize(ppu_thread& ppu, u32 max_usable_spu, u32 max_raw_spu) error_code sys_spu_initialize(ppu_thread& ppu, u32 max_usable_spu, u32 max_raw_spu)
{ {
vm::temporary_unlock(ppu); vm::temporary_unlock(ppu);
@ -253,9 +276,7 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
return CELL_ESRCH; return CELL_ESRCH;
} }
std::lock_guard lock(group->mutex); if (spu_num >= group->threads_map.size())
if (spu_num >= group->threads.size())
{ {
return CELL_EINVAL; return CELL_EINVAL;
} }
@ -265,7 +286,9 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
return CELL_EINVAL; return CELL_EINVAL;
} }
if (group->threads[spu_num] || group->run_state != SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED) std::lock_guard lock(group->mutex);
if (group->threads_map[spu_num] != -1 || group->run_state != SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED)
{ {
return CELL_EBUSY; return CELL_EBUSY;
} }
@ -292,26 +315,30 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
const vm::addr_t ls_addr{verify("SPU LS" HERE, vm::alloc(0x80000, vm::main))}; const vm::addr_t ls_addr{verify("SPU LS" HERE, vm::alloc(0x80000, vm::main))};
const u32 tid = idm::import<named_thread<spu_thread>>([&]() const u32 inited = group->init;
{
const u32 tid = idm::last_id();
std::string full_name = fmt::format("SPU[0x%x] Thread", tid); const u32 tid = (inited << 24) | (group_id & 0xffffff);
verify(HERE), idm::import<named_thread<spu_thread>>([&]()
{
std::string full_name = fmt::format("SPU[0x%07x] Thread", tid);
if (!thread_name.empty()) if (!thread_name.empty())
{ {
fmt::append(full_name, " (%s)", thread_name); fmt::append(full_name, " (%s)", thread_name);
} }
group->threads[spu_num] = std::make_shared<named_thread<spu_thread>>(full_name, ls_addr, group.get(), spu_num, thread_name); const auto spu = std::make_shared<named_thread<spu_thread>>(full_name, ls_addr, group.get(), spu_num, thread_name, tid);
return group->threads[spu_num]; group->threads[inited] = spu;
group->threads_map[spu_num] = static_cast<s8>(inited);
return spu;
}); });
*thread = tid; *thread = tid;
group->args[spu_num] = {arg->arg1, arg->arg2, arg->arg3, arg->arg4}; group->args[inited] = {arg->arg1, arg->arg2, arg->arg3, arg->arg4};
group->imgs[spu_num] = std::make_pair(image, std::vector<sys_spu_segment>()); group->imgs[inited].first = image;
group->imgs[spu_num].second.assign(img->segs.get_ptr(), img->segs.get_ptr() + img->nsegs); group->imgs[inited].second.assign(img->segs.get_ptr(), img->segs.get_ptr() + img->nsegs);
if (++group->init == group->max_num) if (++group->init == group->max_num)
{ {
@ -320,7 +347,7 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
if (group->name.size() >= 20 && group->name.compare(group->name.size() - 20, 20, "CellSpursKernelGroup", 20) == 0) if (group->name.size() >= 20 && group->name.compare(group->name.size() - 20, 20, "CellSpursKernelGroup", 20) == 0)
{ {
// Hack: don't run more SPURS threads than specified. // Hack: don't run more SPURS threads than specified.
group->init = g_cfg.core.max_spurs_threads; group->max_run = g_cfg.core.max_spurs_threads;
LOG_SUCCESS(SPU, "HACK: '%s' (0x%x) limited to %u threads.", group->name, group_id, +g_cfg.core.max_spurs_threads); LOG_SUCCESS(SPU, "HACK: '%s' (0x%x) limited to %u threads.", group->name, group_id, +g_cfg.core.max_spurs_threads);
} }
@ -338,18 +365,16 @@ error_code sys_spu_thread_set_argument(ppu_thread& ppu, u32 id, vm::ptr<sys_spu_
sys_spu.warning("sys_spu_thread_set_argument(id=0x%x, arg=*0x%x)", id, arg); sys_spu.warning("sys_spu_thread_set_argument(id=0x%x, arg=*0x%x)", id, arg);
const auto thread = idm::get<named_thread<spu_thread>>(id); const auto [thread, group] = lv2_spu_group::get_thread(id);
if (UNLIKELY(!thread || !thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
const auto group = thread->group;
std::lock_guard lock(group->mutex); std::lock_guard lock(group->mutex);
group->args[thread->index] = {arg->arg1, arg->arg2, arg->arg3, arg->arg4}; group->args[id >> 24] = {arg->arg1, arg->arg2, arg->arg3, arg->arg4};
return CELL_OK; return CELL_OK;
} }
@ -360,9 +385,9 @@ error_code sys_spu_thread_get_exit_status(ppu_thread& ppu, u32 id, vm::ptr<u32>
sys_spu.warning("sys_spu_thread_get_exit_status(id=0x%x, status=*0x%x)", id, status); sys_spu.warning("sys_spu_thread_get_exit_status(id=0x%x, status=*0x%x)", id, status);
const auto thread = idm::get<named_thread<spu_thread>>(id); const auto [thread, group] = lv2_spu_group::get_thread(id);
if (UNLIKELY(!thread || !thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
@ -427,11 +452,11 @@ error_code sys_spu_thread_group_destroy(ppu_thread& ppu, u32 id)
return group.ret; return group.ret;
} }
// Cleanup for (const auto& t : group->threads)
for (auto& ptr : group->threads)
{ {
if (auto thread = std::move(ptr)) if (auto thread = t.get())
{ {
// Remove ID from IDM (destruction will occur in group destructor)
idm::remove<named_thread<spu_thread>>(thread->id); idm::remove<named_thread<spu_thread>>(thread->id);
} }
} }
@ -463,23 +488,17 @@ error_code sys_spu_thread_group_start(ppu_thread& ppu, u32 id)
std::lock_guard lock(group->mutex); std::lock_guard lock(group->mutex);
u32 max_threads = +group->init; const u32 max_threads = group->max_run;
group->join_state = 0; group->join_state = 0;
group->running = max_threads; group->running = max_threads;
u32 run_threads = max_threads;
for (auto& thread : group->threads) for (auto& thread : group->threads)
{ {
if (!run_threads) if (thread)
{ {
break; auto& args = group->args[thread->lv2_id >> 24];
} auto& img = group->imgs[thread->lv2_id >> 24];
if (thread && run_threads--)
{
auto& args = group->args[thread->index];
auto& img = group->imgs[thread->index];
sys_spu_image::deploy(thread->offset, img.second.data(), img.first.nsegs); sys_spu_image::deploy(thread->offset, img.second.data(), img.first.nsegs);
@ -653,35 +672,13 @@ error_code sys_spu_thread_group_terminate(ppu_thread& ppu, u32 id, s32 value)
sys_spu.trace("sys_spu_thread_group_terminate(id=0x%x, value=0x%x)", id, value); sys_spu.trace("sys_spu_thread_group_terminate(id=0x%x, value=0x%x)", id, value);
// The id can be either SPU Thread Group or SPU Thread const auto group = idm::get<lv2_spu_group>(id);
const auto thread = idm::get<named_thread<spu_thread>>(id);
const auto _group = idm::get<lv2_spu_group>(id);
const auto group = thread ? thread->group : _group.get();
if (!group && (!thread || !thread->group)) if (!group)
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
if (thread)
{
for (auto& t : group->threads)
{
// find primary (?) thread and compare it with the one specified
if (t)
{
if (t == thread)
{
break;
}
else
{
return CELL_EPERM;
}
}
}
}
std::unique_lock lock(group->mutex); std::unique_lock lock(group->mutex);
if (group->run_state <= SPU_THREAD_GROUP_STATUS_INITIALIZED || if (group->run_state <= SPU_THREAD_GROUP_STATUS_INITIALIZED ||
@ -863,15 +860,13 @@ error_code sys_spu_thread_write_ls(ppu_thread& ppu, u32 id, u32 lsa, u64 value,
return CELL_EINVAL; return CELL_EINVAL;
} }
const auto thread = idm::get<named_thread<spu_thread>>(id); const auto [thread, group] = lv2_spu_group::get_thread(id);
if (UNLIKELY(!thread || !thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
const auto group = thread->group;
std::lock_guard lock(group->mutex); std::lock_guard lock(group->mutex);
if (group->run_state < SPU_THREAD_GROUP_STATUS_WAITING || group->run_state > SPU_THREAD_GROUP_STATUS_RUNNING) if (group->run_state < SPU_THREAD_GROUP_STATUS_WAITING || group->run_state > SPU_THREAD_GROUP_STATUS_RUNNING)
@ -902,15 +897,13 @@ error_code sys_spu_thread_read_ls(ppu_thread& ppu, u32 id, u32 lsa, vm::ptr<u64>
return CELL_EINVAL; return CELL_EINVAL;
} }
const auto thread = idm::get<named_thread<spu_thread>>(id); const auto [thread, group] = lv2_spu_group::get_thread(id);
if (UNLIKELY(!thread || !thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
const auto group = thread->group;
std::lock_guard lock(group->mutex); std::lock_guard lock(group->mutex);
if (group->run_state < SPU_THREAD_GROUP_STATUS_WAITING || group->run_state > SPU_THREAD_GROUP_STATUS_RUNNING) if (group->run_state < SPU_THREAD_GROUP_STATUS_WAITING || group->run_state > SPU_THREAD_GROUP_STATUS_RUNNING)
@ -936,15 +929,13 @@ error_code sys_spu_thread_write_spu_mb(ppu_thread& ppu, u32 id, u32 value)
sys_spu.warning("sys_spu_thread_write_spu_mb(id=0x%x, value=0x%x)", id, value); sys_spu.warning("sys_spu_thread_write_spu_mb(id=0x%x, value=0x%x)", id, value);
const auto thread = idm::get<named_thread<spu_thread>>(id); const auto [thread, group] = lv2_spu_group::get_thread(id);
if (UNLIKELY(!thread || !thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
const auto group = thread->group;
std::lock_guard lock(group->mutex); std::lock_guard lock(group->mutex);
thread->ch_in_mbox.push(*thread, value); thread->ch_in_mbox.push(*thread, value);
@ -963,9 +954,9 @@ error_code sys_spu_thread_set_spu_cfg(ppu_thread& ppu, u32 id, u64 value)
return CELL_EINVAL; return CELL_EINVAL;
} }
const auto thread = idm::get<named_thread<spu_thread>>(id); const auto [thread, group] = lv2_spu_group::get_thread(id);
if (UNLIKELY(!thread || !thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
@ -981,9 +972,9 @@ error_code sys_spu_thread_get_spu_cfg(ppu_thread& ppu, u32 id, vm::ptr<u64> valu
sys_spu.warning("sys_spu_thread_get_spu_cfg(id=0x%x, value=*0x%x)", id, value); sys_spu.warning("sys_spu_thread_get_spu_cfg(id=0x%x, value=*0x%x)", id, value);
const auto thread = idm::get<named_thread<spu_thread>>(id); const auto [thread, group] = lv2_spu_group::get_thread(id);
if (UNLIKELY(!thread || !thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
@ -999,9 +990,9 @@ error_code sys_spu_thread_write_snr(ppu_thread& ppu, u32 id, u32 number, u32 val
sys_spu.trace("sys_spu_thread_write_snr(id=0x%x, number=%d, value=0x%x)", id, number, value); sys_spu.trace("sys_spu_thread_write_snr(id=0x%x, number=%d, value=0x%x)", id, number, value);
const auto thread = idm::get<named_thread<spu_thread>>(id); const auto [thread, group] = lv2_spu_group::get_thread(id);
if (UNLIKELY(!thread || !thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
@ -1102,10 +1093,10 @@ error_code sys_spu_thread_connect_event(ppu_thread& ppu, u32 id, u32 eq, u32 et,
sys_spu.warning("sys_spu_thread_connect_event(id=0x%x, eq=0x%x, et=%d, spup=%d)", id, eq, et, spup); sys_spu.warning("sys_spu_thread_connect_event(id=0x%x, eq=0x%x, et=%d, spup=%d)", id, eq, et, spup);
const auto thread = idm::get<named_thread<spu_thread>>(id); const auto [thread, group] = lv2_spu_group::get_thread(id);
const auto queue = idm::get<lv2_obj, lv2_event_queue>(eq); const auto queue = idm::get<lv2_obj, lv2_event_queue>(eq);
if (UNLIKELY(!queue || !thread || !thread->group)) if (UNLIKELY(!queue || !thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
@ -1116,7 +1107,7 @@ error_code sys_spu_thread_connect_event(ppu_thread& ppu, u32 id, u32 eq, u32 et,
return CELL_EINVAL; return CELL_EINVAL;
} }
std::lock_guard lock(thread->group->mutex); std::lock_guard lock(group->mutex);
auto& port = thread->spup[spup]; auto& port = thread->spup[spup];
@ -1136,9 +1127,9 @@ error_code sys_spu_thread_disconnect_event(ppu_thread& ppu, u32 id, u32 et, u8 s
sys_spu.warning("sys_spu_thread_disconnect_event(id=0x%x, et=%d, spup=%d)", id, et, spup); sys_spu.warning("sys_spu_thread_disconnect_event(id=0x%x, et=%d, spup=%d)", id, et, spup);
const auto thread = idm::get<named_thread<spu_thread>>(id); const auto [thread, group] = lv2_spu_group::get_thread(id);
if (UNLIKELY(!thread || !thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
@ -1149,7 +1140,7 @@ error_code sys_spu_thread_disconnect_event(ppu_thread& ppu, u32 id, u32 et, u8 s
return CELL_EINVAL; return CELL_EINVAL;
} }
std::lock_guard lock(thread->group->mutex); std::lock_guard lock(group->mutex);
auto& port = thread->spup[spup]; auto& port = thread->spup[spup];
@ -1169,10 +1160,10 @@ error_code sys_spu_thread_bind_queue(ppu_thread& ppu, u32 id, u32 spuq, u32 spuq
sys_spu.warning("sys_spu_thread_bind_queue(id=0x%x, spuq=0x%x, spuq_num=0x%x)", id, spuq, spuq_num); sys_spu.warning("sys_spu_thread_bind_queue(id=0x%x, spuq=0x%x, spuq_num=0x%x)", id, spuq, spuq_num);
const auto thread = idm::get<named_thread<spu_thread>>(id); const auto [thread, group] = lv2_spu_group::get_thread(id);
const auto queue = idm::get<lv2_obj, lv2_event_queue>(spuq); const auto queue = idm::get<lv2_obj, lv2_event_queue>(spuq);
if (UNLIKELY(!queue || !thread || !thread->group)) if (UNLIKELY(!queue || !thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
@ -1182,7 +1173,7 @@ error_code sys_spu_thread_bind_queue(ppu_thread& ppu, u32 id, u32 spuq, u32 spuq
return CELL_EINVAL; return CELL_EINVAL;
} }
std::lock_guard lock(thread->group->mutex); std::lock_guard lock(group->mutex);
decltype(std::data(thread->spuq)) q{}; decltype(std::data(thread->spuq)) q{};
@ -1223,14 +1214,14 @@ error_code sys_spu_thread_unbind_queue(ppu_thread& ppu, u32 id, u32 spuq_num)
sys_spu.warning("sys_spu_thread_unbind_queue(id=0x%x, spuq_num=0x%x)", id, spuq_num); sys_spu.warning("sys_spu_thread_unbind_queue(id=0x%x, spuq_num=0x%x)", id, spuq_num);
const auto thread = idm::get<named_thread<spu_thread>>(id); const auto [thread, group] = lv2_spu_group::get_thread(id);
if (UNLIKELY(!thread || !thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
std::lock_guard lock(thread->group->mutex); std::lock_guard lock(group->mutex);
for (auto& v : thread->spuq) for (auto& v : thread->spuq)
{ {
@ -1399,9 +1390,9 @@ error_code sys_spu_thread_recover_page_fault(ppu_thread& ppu, u32 id)
sys_spu.warning("sys_spu_thread_recover_page_fault(id=0x%x)", id); sys_spu.warning("sys_spu_thread_recover_page_fault(id=0x%x)", id);
const auto thread = idm::get<named_thread<spu_thread>>(id); const auto [thread, group] = lv2_spu_group::get_thread(id);
if (UNLIKELY(!thread || !thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
@ -1417,7 +1408,7 @@ error_code sys_raw_spu_recover_page_fault(ppu_thread& ppu, u32 id)
const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id)); const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id));
if (UNLIKELY(!thread || thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
@ -1449,7 +1440,7 @@ error_code sys_raw_spu_create(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<void> at
const vm::addr_t ls_addr{verify(HERE, vm::falloc(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, 0x40000, vm::spu))}; const vm::addr_t ls_addr{verify(HERE, vm::falloc(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, 0x40000, vm::spu))};
const u32 tid = idm::make<named_thread<spu_thread>>(fmt::format("RawSPU[0x%x] Thread", index), ls_addr, nullptr, index, ""); const u32 tid = idm::make<named_thread<spu_thread>>(fmt::format("RawSPU[0x%x] Thread", index), ls_addr, nullptr, index, "", index);
spu_thread::g_raw_spu_id[index] = verify("RawSPU ID" HERE, tid); spu_thread::g_raw_spu_id[index] = verify("RawSPU ID" HERE, tid);
@ -1466,7 +1457,7 @@ error_code sys_raw_spu_destroy(ppu_thread& ppu, u32 id)
const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id)); const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id));
if (UNLIKELY(!thread || thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
@ -1538,7 +1529,7 @@ error_code sys_raw_spu_create_interrupt_tag(ppu_thread& ppu, u32 id, u32 class_i
auto thread = idm::check_unlocked<named_thread<spu_thread>>(spu_thread::find_raw_spu(id)); auto thread = idm::check_unlocked<named_thread<spu_thread>>(spu_thread::find_raw_spu(id));
if (!thread || thread->group) if (!thread)
{ {
error = CELL_ESRCH; error = CELL_ESRCH;
return result; return result;
@ -1579,7 +1570,7 @@ error_code sys_raw_spu_set_int_mask(ppu_thread& ppu, u32 id, u32 class_id, u64 m
const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id)); const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id));
if (UNLIKELY(!thread || thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
@ -1602,7 +1593,7 @@ error_code sys_raw_spu_get_int_mask(ppu_thread& ppu, u32 id, u32 class_id, vm::p
const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id)); const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id));
if (UNLIKELY(!thread || thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
@ -1625,7 +1616,7 @@ error_code sys_raw_spu_set_int_stat(ppu_thread& ppu, u32 id, u32 class_id, u64 s
const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id)); const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id));
if (UNLIKELY(!thread || thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
@ -1648,7 +1639,7 @@ error_code sys_raw_spu_get_int_stat(ppu_thread& ppu, u32 id, u32 class_id, vm::p
const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id)); const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id));
if (UNLIKELY(!thread || thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
@ -1666,7 +1657,7 @@ error_code sys_raw_spu_read_puint_mb(ppu_thread& ppu, u32 id, vm::ptr<u32> value
const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id)); const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id));
if (UNLIKELY(!thread || thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
@ -1689,7 +1680,7 @@ error_code sys_raw_spu_set_spu_cfg(ppu_thread& ppu, u32 id, u32 value)
const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id)); const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id));
if (UNLIKELY(!thread || thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
@ -1707,7 +1698,7 @@ error_code sys_raw_spu_get_spu_cfg(ppu_thread& ppu, u32 id, vm::ptr<u32> value)
const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id)); const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id));
if (UNLIKELY(!thread || thread->group)) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }

View file

@ -241,6 +241,7 @@ struct lv2_spu_group
const u32 max_num; const u32 max_num;
const s32 type; // SPU Thread Group Type const s32 type; // SPU Thread Group Type
const u32 ct; // Memory Container Id const u32 ct; // Memory Container Id
u32 max_run;
shared_mutex mutex; shared_mutex mutex;
@ -254,9 +255,10 @@ struct lv2_spu_group
atomic_t<u64> stop_count; atomic_t<u64> stop_count;
class ppu_thread* waiter = nullptr; class ppu_thread* waiter = nullptr;
std::array<std::shared_ptr<named_thread<spu_thread>>, 256> threads; // SPU Threads std::array<std::shared_ptr<named_thread<spu_thread>>, 8> threads; // SPU Threads
std::array<std::pair<sys_spu_image, std::vector<sys_spu_segment>>, 256> imgs; // SPU Images std::array<s8, 256> threads_map; // SPU Threads map based number
std::array<std::array<u64, 4>, 256> args; // SPU Thread Arguments std::array<std::pair<sys_spu_image, std::vector<sys_spu_segment>>, 8> imgs; // SPU Images
std::array<std::array<u64, 4>, 8> args; // SPU Thread Arguments
std::weak_ptr<lv2_event_queue> ep_run; // port for SYS_SPU_THREAD_GROUP_EVENT_RUN events std::weak_ptr<lv2_event_queue> ep_run; // port for SYS_SPU_THREAD_GROUP_EVENT_RUN events
std::weak_ptr<lv2_event_queue> ep_exception; // TODO: SYS_SPU_THREAD_GROUP_EVENT_EXCEPTION std::weak_ptr<lv2_event_queue> ep_exception; // TODO: SYS_SPU_THREAD_GROUP_EVENT_EXCEPTION
@ -266,6 +268,7 @@ struct lv2_spu_group
: id(idm::last_id()) : id(idm::last_id())
, name(name) , name(name)
, max_num(num) , max_num(num)
, max_run(num)
, init(0) , init(0)
, prio(prio) , prio(prio)
, type(type) , type(type)
@ -276,6 +279,7 @@ struct lv2_spu_group
, running(0) , running(0)
, stop_count(0) , stop_count(0)
{ {
threads_map.fill(-1);
} }
void send_run_event(u64 data1, u64 data2, u64 data3) void send_run_event(u64 data1, u64 data2, u64 data3)
@ -301,6 +305,8 @@ struct lv2_spu_group
queue->send(SYS_SPU_THREAD_GROUP_EVENT_SYSTEM_MODULE_KEY, data1, data2, data3); queue->send(SYS_SPU_THREAD_GROUP_EVENT_SYSTEM_MODULE_KEY, data1, data2, data3);
} }
} }
static std::pair<named_thread<spu_thread>*, std::shared_ptr<lv2_spu_group>> get_thread(u32 id);
}; };
class ppu_thread; class ppu_thread;

View file

@ -281,7 +281,7 @@ void kernel_explorer::Update()
idm::select<named_thread<spu_thread>>([&](u32 id, spu_thread& spu) idm::select<named_thread<spu_thread>>([&](u32 id, spu_thread& spu)
{ {
lv2_types.back().count++; lv2_types.back().count++;
l_addTreeChild(lv2_types.back().node, qstr(fmt::format("SPU Thread: ID = 0x%08x '%s'", id, spu.spu_name.get()))); l_addTreeChild(lv2_types.back().node, qstr(fmt::format("SPU Thread: ID = 0x%08x '%s'", spu.lv2_id, spu.spu_name.get())));
}); });
lv2_types.emplace_back(l_addTreeChild(root, "SPU Thread Groups")); lv2_types.emplace_back(l_addTreeChild(root, "SPU Thread Groups"));