From 954e3f6e6c43fb61a85caa4261c21953afbbc35b Mon Sep 17 00:00:00 2001 From: Eladash Date: Wed, 29 Apr 2020 05:24:28 +0300 Subject: [PATCH 1/7] Fixup for cpu_flag::pause state check after #8114 --- rpcs3/Emu/Cell/PPUThread.cpp | 2 ++ rpcs3/Emu/Cell/SPUThread.cpp | 21 +++++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 10602981c84e..1933387e6513 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -1041,7 +1041,9 @@ static T ppu_load_acquire_reservation(ppu_thread& ppu, u32 addr) } else { + ppu.state += cpu_flag::wait; std::this_thread::yield(); + ppu.check_state(); } }()) { diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 42fac63ff497..88277c659430 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1777,6 +1777,11 @@ bool spu_thread::process_mfc_cmd() // Spinning, might as well yield cpu resources std::this_thread::yield(); + + if (test_stopped()) + { + return false; + } } auto& dst = _ref(ch_mfc_cmd.lsa & 0x3ff80); @@ -1784,7 +1789,7 @@ bool spu_thread::process_mfc_cmd() for (u64 i = 0;; [&]() { - if (is_paused()) + if (state & cpu_flag::pause) { check_state(); } @@ -1795,7 +1800,16 @@ bool spu_thread::process_mfc_cmd() } else { + if (g_use_rtm) + { + state += cpu_flag::wait; + } + std::this_thread::yield(); + + if (test_stopped()) + { + } } }()) { @@ -1826,11 +1840,6 @@ bool spu_thread::process_mfc_cmd() break; } - if (test_stopped()) - { - return false; - } - if (raddr && raddr != addr) { // Last check for event before we replace the reservation with a new one From 791ec9531373fc7d7791b9b04e4a83b1b6657b56 Mon Sep 17 00:00:00 2001 From: Eladash Date: Mon, 13 Apr 2020 09:54:29 +0300 Subject: [PATCH 2/7] sys_rwlock: Do not allow SYS_SYNC_PRIORITY_INHERIT --- rpcs3/Emu/Cell/lv2/sys_rwlock.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp b/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp index 1fe29fe37754..ddf49d2a7d89 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp @@ -26,10 +26,7 @@ error_code sys_rwlock_create(ppu_thread& ppu, vm::ptr rw_lock_id, vm::ptr Date: Wed, 29 Apr 2020 06:46:51 +0300 Subject: [PATCH 3/7] Fix address_range start_length() constructor Fixes an underflow when constructing start_length(0, 0). --- Utilities/address_range.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Utilities/address_range.h b/Utilities/address_range.h index dcccc1a64ef5..634fbb76e954 100644 --- a/Utilities/address_range.h +++ b/Utilities/address_range.h @@ -60,21 +60,26 @@ namespace utils return (start1 >= start2 && end1 <= end2); } - address_range(u32 _start, u32 _end) : start(_start), end(_end) {} + constexpr address_range(u32 _start, u32 _end) : start(_start), end(_end) {} public: // Constructors - address_range() = default; - address_range(const address_range &other) : start(other.start), end(other.end) {} + constexpr address_range() = default; + constexpr address_range(const address_range &other) : start(other.start), end(other.end) {} - static inline address_range start_length(u32 _start, u32 _length) + static constexpr address_range start_length(u32 _start, u32 _length) { - return address_range(_start, _start + (_length - 1)); + if (!_length) + { + return {}; + } + + return {_start, _start + (_length - 1)}; } - static inline address_range start_end(u32 _start, u32 _end) + static constexpr address_range start_end(u32 _start, u32 _end) { - return address_range(_start, _end); + return {_start, _end}; } // Length From 69f82a731126b95bc26b6516b7cfaf0a8deb5241 Mon Sep 17 00:00:00 2001 From: Eladash Date: Wed, 29 Apr 2020 07:46:50 +0300 Subject: [PATCH 4/7] Make spu_mfc_cmd fmt properly show stalled commands --- rpcs3/Emu/Cell/MFC.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rpcs3/Emu/Cell/MFC.cpp b/rpcs3/Emu/Cell/MFC.cpp index bc1e51365346..54ca31f3a7e3 100644 --- a/rpcs3/Emu/Cell/MFC.cpp +++ b/rpcs3/Emu/Cell/MFC.cpp @@ -62,5 +62,7 @@ void fmt_class_string::format(std::string& out, u64 arg) { const auto& cmd = get_object(arg); - fmt::append(out, "%s #%02u 0x%05x:0x%08x 0x%x", cmd.cmd, cmd.tag, cmd.lsa, cmd.eah * 0x100000000ull + cmd.eal, cmd.size); + const u8 tag = cmd.tag; + + fmt::append(out, "%s #%02u 0x%05x:0x%08llx 0x%x%s", cmd.cmd, tag & 0x7f, cmd.lsa, u64{cmd.eah} << 32 | cmd.eal, cmd.size, (tag & 0x80) ? " (stalled)" : ""); } From c1dc6838fae67ebf8a1f13abb50b38cdb5d03224 Mon Sep 17 00:00:00 2001 From: Eladash Date: Wed, 29 Apr 2020 07:57:12 +0300 Subject: [PATCH 5/7] Fix sys_ppu_thread_get_priority page faults --- rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp index 93a14d5daaf6..07b6c8594d94 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp @@ -277,6 +277,8 @@ error_code sys_ppu_thread_get_priority(u32 thread_id, vm::ptr priop) // Clean some detached thread (hack) g_fxo->get()->clean(0); + u32 prio; + const auto thread = idm::check>(thread_id, [&](ppu_thread& thread) { if (thread.joiner == ppu_join_status::exited) @@ -284,7 +286,7 @@ error_code sys_ppu_thread_get_priority(u32 thread_id, vm::ptr priop) return false; } - *priop = thread.prio; + prio = thread.prio; return true; }); @@ -293,6 +295,7 @@ error_code sys_ppu_thread_get_priority(u32 thread_id, vm::ptr priop) return CELL_ESRCH; } + *priop = prio; return CELL_OK; } From dd6825a7bdfbdd32e670c78ee573f4b478e16697 Mon Sep 17 00:00:00 2001 From: Eladash Date: Wed, 29 Apr 2020 08:03:07 +0300 Subject: [PATCH 6/7] Fix sys_ppu_thread_start error checking, fix rare bug in sys_ppu_thread_create * Correct error code to EBUSY. * lv2_obj::awake was called even when EBSUY should be returned. * Fix sys_ppu_thread_create for a newly created thread with the same id as ppu_thread::id_base. (can happen if main thread exited before its creation) --- rpcs3/Emu/Cell/PPUThread.cpp | 11 ++++------- rpcs3/Emu/Cell/lv2/sys_interrupt.cpp | 2 +- rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp | 25 ++++++++++++++++++------- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 1933387e6513..8c5b3adc9cd8 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -788,14 +788,11 @@ ppu_thread::ppu_thread(const ppu_thread_params& param, std::string_view name, u3 gpr[13] = param.tls_addr; - if (detached >= 0 && id != id_base) + if (detached >= 0) { - // Initialize thread entry point - cmd_list - ({ - {ppu_cmd::set_args, 2}, param.arg0, param.arg1, - {ppu_cmd::opd_call, 0}, std::bit_cast(entry_func), - }); + // Initialize thread args + gpr[3] = param.arg0; + gpr[4] = param.arg1; } // Trigger the scheduler diff --git a/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp b/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp index c0e52ed59ef0..e17abbdbf39e 100644 --- a/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp @@ -15,7 +15,7 @@ void lv2_int_serv::exec() ({ { ppu_cmd::reset_stack, 0 }, { ppu_cmd::set_args, 2 }, arg1, arg2, - { ppu_cmd::opd_call, 0 }, std::bit_cast(thread->entry_func), + { ppu_cmd::opd_call, 0 }, thread->entry_func, { ppu_cmd::sleep, 0 } }); diff --git a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp index 07b6c8594d94..078a183841e6 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp @@ -441,26 +441,37 @@ error_code sys_ppu_thread_start(ppu_thread& ppu, u32 thread_id) { sys_ppu_thread.trace("sys_ppu_thread_start(thread_id=0x%x)", thread_id); - const auto thread = idm::get>(thread_id, [&](ppu_thread& thread) + const auto thread = idm::get>(thread_id, [&](ppu_thread& thread) -> CellError { if (thread.joiner == ppu_join_status::exited) { - return false; + return CELL_ESRCH; + } + + if (!thread.state.test_and_reset(cpu_flag::stop)) + { + // Already started + return CELL_EBUSY; } lv2_obj::awake(&thread); - return true; + + thread.cmd_list + ({ + {ppu_cmd::opd_call, 0}, thread.entry_func + }); + + return {}; }); - if (!thread || !thread.ret) + if (!thread) { return CELL_ESRCH; } - if (!thread->state.test_and_reset(cpu_flag::stop)) + if (thread.ret) { - // TODO: what happens there? - return CELL_EPERM; + return thread.ret; } else { From f4f0fb88b1c66dcd2f4c5c29402ac834420865f0 Mon Sep 17 00:00:00 2001 From: Eladash Date: Wed, 29 Apr 2020 09:49:13 +0300 Subject: [PATCH 7/7] kernel explorer: Add more information about SPU/PPU threads --- rpcs3/Emu/Cell/PPUThread.cpp | 2 +- rpcs3/Emu/Cell/lv2/sys_spu.cpp | 22 ++++++++++++++++++++++ rpcs3/Emu/Cell/lv2/sys_spu.h | 4 ++-- rpcs3/rpcs3qt/kernel_explorer.cpp | 6 +++--- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 8c5b3adc9cd8..5f9425fd41e0 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -77,7 +77,7 @@ void fmt_class_string::format(std::string& out, u64 arg) { switch (js) { - case ppu_join_status::joinable: return ""; + case ppu_join_status::joinable: return "none"; case ppu_join_status::detached: return "detached"; case ppu_join_status::zombie: return "zombie"; case ppu_join_status::exited: return "exited"; diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index c98cf7d4c38a..cf8fb39aafb3 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -25,6 +25,28 @@ LOG_CHANNEL(sys_spu); extern u64 get_timebased_time(); +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](spu_group_status value) + { + switch (value) + { + case SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED: return "uninitialized"; + case SPU_THREAD_GROUP_STATUS_INITIALIZED: return "initialized"; + case SPU_THREAD_GROUP_STATUS_READY: return "ready"; + case SPU_THREAD_GROUP_STATUS_WAITING: return "waiting"; + case SPU_THREAD_GROUP_STATUS_SUSPENDED: return "suspended"; + case SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED: return "waiting and suspended"; + case SPU_THREAD_GROUP_STATUS_RUNNING: return "running"; + case SPU_THREAD_GROUP_STATUS_STOPPED: return "stopped"; + case SPU_THREAD_GROUP_STATUS_UNKNOWN: break; + } + + return unknown; + }); +} + void sys_spu_image::load(const fs::file& stream) { const spu_exec_object obj{stream, 0, elf_opt::no_sections + elf_opt::no_data}; diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.h b/rpcs3/Emu/Cell/lv2/sys_spu.h index 7e1fd0b6f329..26222338857b 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.h +++ b/rpcs3/Emu/Cell/lv2/sys_spu.h @@ -48,7 +48,7 @@ enum SYS_SPU_THREAD_GROUP_LOG_GET_STATUS = 0x2, }; -enum : u32 +enum spu_group_status : u32 { SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED, SPU_THREAD_GROUP_STATUS_INITIALIZED, @@ -263,7 +263,7 @@ struct lv2_spu_group atomic_t init; // Initialization Counter atomic_t prio; // SPU Thread Group Priority - atomic_t run_state; // SPU Thread Group State + atomic_t run_state; // SPU Thread Group State atomic_t exit_status; // SPU Thread Group Exit Status atomic_t join_state; // flags used to detect exit cause and signal atomic_t running; // Number of running threads diff --git a/rpcs3/rpcs3qt/kernel_explorer.cpp b/rpcs3/rpcs3qt/kernel_explorer.cpp index e9428a64b0f9..e4dc6b9e6982 100644 --- a/rpcs3/rpcs3qt/kernel_explorer.cpp +++ b/rpcs3/rpcs3qt/kernel_explorer.cpp @@ -282,7 +282,7 @@ void kernel_explorer::Update() idm::select>([&](u32 id, ppu_thread& ppu) { lv2_types.back().count++; - l_addTreeChild(lv2_types.back().node, qstr(fmt::format(u8"PPU Thread: ID = 0x%08x “%s”", id, *ppu.ppu_tname.load()))); + l_addTreeChild(lv2_types.back().node, qstr(fmt::format(u8"PPU: ID = 0x%07x “%s”, priority = %d, joiner = %s, state = %s", id, *ppu.ppu_tname.load(), +ppu.prio, ppu.joiner.load(), ppu.state.load()))); }); lv2_types.emplace_back(l_addTreeChild(root, "SPU Threads")); @@ -290,7 +290,7 @@ void kernel_explorer::Update() idm::select>([&](u32 /*id*/, spu_thread& spu) { lv2_types.back().count++; - l_addTreeChild(lv2_types.back().node, qstr(fmt::format(u8"SPU Thread: ID = 0x%08x “%s”", spu.lv2_id, *spu.spu_tname.load()))); + l_addTreeChild(lv2_types.back().node, qstr(fmt::format(u8"SPU: ID = 0x%07x “%s”, state = %s", spu.lv2_id, *spu.spu_tname.load(), spu.state.load()))); }); lv2_types.emplace_back(l_addTreeChild(root, "SPU Thread Groups")); @@ -298,7 +298,7 @@ void kernel_explorer::Update() idm::select([&](u32 id, lv2_spu_group& tg) { lv2_types.back().count++; - l_addTreeChild(lv2_types.back().node, qstr(fmt::format(u8"SPU Thread Group: ID = 0x%08x “%s”", id, tg.name))); + l_addTreeChild(lv2_types.back().node, qstr(fmt::format(u8"SPU Group: ID = 0x%07x “%s”, status = %s, priority = %d, type = 0x%x", id, tg.name, tg.run_state.load(), +tg.prio, tg.type))); }); lv2_types.emplace_back(l_addTreeChild(root, "File Descriptors"));