diff --git a/rpcs3/Emu/Cell/Modules/cellSpurs.cpp b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp index c57ec77a2f..014273e93b 100644 --- a/rpcs3/Emu/Cell/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp @@ -136,6 +136,25 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](auto error) + { + switch (error) + { + case SPURS_WKL_STATE_NON_EXISTENT: return "Non-existent"; + case SPURS_WKL_STATE_PREPARING: return "Preparing"; + case SPURS_WKL_STATE_RUNNABLE: return "Runnable"; + case SPURS_WKL_STATE_SHUTTING_DOWN: return "In-shutdown"; + case SPURS_WKL_STATE_REMOVABLE: return "Removable"; + case SPURS_WKL_STATE_INVALID: break; + } + + return unknown; + }); +} + extern u64 ppu_ldarx(ppu_thread&, u32); extern u32 ppu_lwarx(ppu_thread&, u32); extern bool ppu_stwcx(ppu_thread&, u32, u32); @@ -761,15 +780,13 @@ s32 _spurs::wakeup_shutdown_completion_waiter(ppu_thread& ppu, vm::ptrwklState1[wid] : spurs->wklState2[wid & 0x0F]; - - if (wklState != SPURS_WKL_STATE_REMOVABLE) + if (spurs->wklState(wid) != SPURS_WKL_STATE_REMOVABLE) { return CELL_SPURS_POLICY_MODULE_ERROR_STAT; } const auto wklF = wid < CELL_SPURS_MAX_WORKLOAD ? &spurs->wklF1[wid] : &spurs->wklF2[wid & 0x0F]; - const auto wklEvent = wid < CELL_SPURS_MAX_WORKLOAD ? &spurs->wklEvent1[wid] : &spurs->wklEvent2[wid & 0x0F]; + const auto wklEvent = &spurs->wklEvent(wid); if (wklF->hook) { @@ -2255,7 +2272,7 @@ s32 _spurs::add_workload(vm::ptr spurs, vm::ptr wid, vm::cptrwklCurrentContention[wnum] & 0xf) == 0; verify(HERE), (spurs->wklPendingContention[wnum] & 0xf) == 0; - spurs->wklState1[wnum] = 1; + spurs->wklState1[wnum] = SPURS_WKL_STATE_PREPARING; spurs->wklStatus1[wnum] = 0; spurs->wklEvent1[wnum] = 0; spurs->wklInfo1[wnum].addr = pm; @@ -2291,7 +2308,7 @@ s32 _spurs::add_workload(vm::ptr spurs, vm::ptr wid, vm::cptrwklCurrentContention[index] & 0xf0) == 0; verify(HERE), (spurs->wklPendingContention[index] & 0xf0) == 0; - spurs->wklState2[index] = 1; + spurs->wklState2[index] = SPURS_WKL_STATE_PREPARING; spurs->wklStatus2[index] = 0; spurs->wklEvent2[index] = 0; spurs->wklInfo2[index].addr = pm; @@ -2370,7 +2387,7 @@ s32 _spurs::add_workload(vm::ptr spurs, vm::ptr wid, vm::cptrwklState(wnum).exchange(2); + spurs->wklState(wnum).exchange(SPURS_WKL_STATE_RUNNABLE); spurs->sysSrvMsgUpdateWorkload.exchange(0xff); spurs->sysSrvMessage.exchange(0xff); return CELL_OK; @@ -2555,7 +2572,7 @@ s32 cellSpursReadyCountStore(ppu_thread& ppu, vm::ptr spurs, u32 wid, return CELL_SPURS_POLICY_MODULE_ERROR_SRCH; } - if (spurs->exception || spurs->wklState(wid) != 2) + if (spurs->exception || spurs->wklState(wid) != SPURS_WKL_STATE_RUNNABLE) { return CELL_SPURS_POLICY_MODULE_ERROR_STAT; } @@ -2591,7 +2608,7 @@ s32 cellSpursReadyCountSwap(ppu_thread& ppu, vm::ptr spurs, u32 wid, return CELL_SPURS_POLICY_MODULE_ERROR_SRCH; } - if (spurs->exception || spurs->wklState(wid) != 2) + if (spurs->exception || spurs->wklState(wid) != SPURS_WKL_STATE_RUNNABLE) { return CELL_SPURS_POLICY_MODULE_ERROR_STAT; } @@ -2629,7 +2646,7 @@ s32 cellSpursReadyCountCompareAndSwap(ppu_thread& ppu, vm::ptr spurs, return CELL_SPURS_POLICY_MODULE_ERROR_SRCH; } - if (spurs->exception || spurs->wklState(wid) != 2) + if (spurs->exception || spurs->wklState(wid) != SPURS_WKL_STATE_RUNNABLE) { return CELL_SPURS_POLICY_MODULE_ERROR_STAT; } @@ -2669,7 +2686,7 @@ s32 cellSpursReadyCountAdd(ppu_thread& ppu, vm::ptr spurs, u32 wid, v return CELL_SPURS_POLICY_MODULE_ERROR_SRCH; } - if (spurs->exception || spurs->wklState(wid) != 2) + if (spurs->exception || spurs->wklState(wid) != SPURS_WKL_STATE_RUNNABLE) { return CELL_SPURS_POLICY_MODULE_ERROR_STAT; } diff --git a/rpcs3/Emu/Cell/Modules/cellSpurs.h b/rpcs3/Emu/Cell/Modules/cellSpurs.h index cbb130b3ea..7e83149bf1 100644 --- a/rpcs3/Emu/Cell/Modules/cellSpurs.h +++ b/rpcs3/Emu/Cell/Modules/cellSpurs.h @@ -145,7 +145,7 @@ enum SpursFlags1 : u8 SF1_EXIT_IF_NO_WORK = 0x80, }; -enum SpursWorkloadConstants : u32 +enum SpursWorkloadState : u8 { // Workload states SPURS_WKL_STATE_NON_EXISTENT = 0, @@ -154,7 +154,10 @@ enum SpursWorkloadConstants : u32 SPURS_WKL_STATE_SHUTTING_DOWN = 3, SPURS_WKL_STATE_REMOVABLE = 4, SPURS_WKL_STATE_INVALID = 5, +}; +enum SpursImgAddrConstants : u32 +{ // Image addresses SPURS_IMG_ADDR_SYS_SRV_WORKLOAD = 0x100, SPURS_IMG_ADDR_TASKSET_PM = 0x200, @@ -537,7 +540,7 @@ struct alignas(128) CellSpurs atomic_t wklFlagReceiver; // 0x77 atomic_be_t wklSignal2; // 0x78 Bitset for 16..32 wids u8 x7A[6]; // 0x7A - atomic_t wklState1[0x10]; // 0x80 SPURS_WKL_STATE_* + atomic_t wklState1[0x10]; // 0x80 u8 wklStatus1[0x10]; // 0x90 atomic_t wklEvent1[0x10]; // 0xA0 atomic_be_t wklEnabled; // 0xB0 @@ -563,7 +566,7 @@ struct alignas(128) CellSpurs atomic_t sysSrvTrace; // 0xCC - atomic_t wklState2[0x10]; // 0xD0 SPURS_WKL_STATE_* + atomic_t wklState2[0x10]; // 0xD0 u8 wklStatus2[0x10]; // 0xE0 atomic_t wklEvent2[0x10]; // 0xF0 _sub_str1 wklF1[0x10]; // 0x100 @@ -615,7 +618,7 @@ struct alignas(128) CellSpurs _sub_str4 wklH2[0x10]; // 0x1A00 u8 unknown_[0x2000 - 0x1B00]; - atomic_t& wklState(const u32 wid) + atomic_t& wklState(u32 wid) { if (wid & 0x10) { @@ -627,6 +630,18 @@ struct alignas(128) CellSpurs } } + atomic_t& wklEvent(u32 wid) + { + if (wid & 0x10) + { + return wklEvent2[wid & 0xf]; + } + else + { + return wklEvent1[wid & 0xf]; + } + } + atomic_t& readyCount(u32 wid) { if (wid & 0x10) @@ -638,6 +653,18 @@ struct alignas(128) CellSpurs return wklIdleSpuCountOrReadyCount2[wid & 0xf]; } } + + _sub_str4& wklName(u32 wid) + { + if (wid & 0x10) + { + return wklH2[wid & 0xf]; + } + else + { + return wklH1[wid & 0xf]; + } + } }; CHECK_SIZE_ALIGN(CellSpurs, 0x2000, 128); diff --git a/rpcs3/rpcs3qt/kernel_explorer.cpp b/rpcs3/rpcs3qt/kernel_explorer.cpp index 8a7a37a2ac..0e937edcc7 100644 --- a/rpcs3/rpcs3qt/kernel_explorer.cpp +++ b/rpcs3/rpcs3qt/kernel_explorer.cpp @@ -29,6 +29,7 @@ #include "Emu/Cell/lv2/sys_vm.h" #include "Emu/Cell/lv2/sys_net.h" #include "Emu/Cell/lv2/sys_fs.h" +#include "Emu/Cell/Modules/cellSpurs.h" #include "Emu/RSX/RSXThread.h" @@ -50,6 +51,7 @@ enum kernel_item_type : int root, node, volatile_node, + solid_node, leaf }; @@ -134,6 +136,20 @@ static QTreeWidgetItem* add_volatile_node(QTreeWidget* tree, QTreeWidgetItem *pa return node; } +static QTreeWidgetItem* add_solid_node(QTreeWidget* tree, QTreeWidgetItem *parent, const QString& base_text, const QString& text = "", int column = 0) +{ + QTreeWidgetItem* node = find_first_node(tree, parent, base_text + ".*"); + if (!node) + { + node = add_child(parent, base_text, column, kernel_item_type::solid_node); + } + if (node) + { + node->setText(0, text.isEmpty() ? base_text : text); + } + return node; +} + kernel_explorer::kernel_explorer(QWidget* parent) : QDialog(parent) { setWindowTitle(tr("Kernel Explorer")); @@ -251,6 +267,7 @@ void kernel_explorer::Update() } [[fallthrough]]; } + case kernel_item_type::solid_node: case kernel_item_type::node: case kernel_item_type::root: default: @@ -480,7 +497,65 @@ void kernel_explorer::Update() idm::select([&](u32 id, lv2_spu_group& tg) { - add_leaf(find_node(m_tree, additional_nodes::spu_thread_groups), qstr(fmt::format(u8"SPU Group 0x%07x: ā€œ%sā€, Status = %s, Priority = %d, Type = 0x%x", id, tg.name, tg.run_state.load(), +tg.prio, tg.type))); + QTreeWidgetItem* spu_tree = add_solid_node(m_tree, find_node(m_tree, additional_nodes::spu_thread_groups), qstr(fmt::format(u8"SPU Group 0x%07x: ā€œ%sā€, Status = %s, Priority = %d, Type = 0x%x", id, tg.name, tg.run_state.load(), +tg.prio, tg.type))); + + if (tg.name.ends_with("CellSpursKernelGroup"sv)) + { + vm::ptr pspurs{}; + + for (const auto& thread : tg.threads) + { + if (thread) + { + // Find SPURS structure address + const u64 arg = tg.args[thread->index][1]; + + if (!pspurs) + { + if (arg < UINT32_MAX && arg % 0x80 == 0 && vm::check_addr(arg, pspurs.size())) + { + pspurs.set(static_cast(arg)); + } + else + { + break; + } + } + else if (pspurs.addr() != arg) + { + pspurs = {}; + break; + } + } + } + + CellSpurs spurs{}; + + if (pspurs && pspurs.try_read(spurs)) + { + const QString branch_name = "SPURS"; + const u32 wklEnabled = spurs.wklEnabled; + QTreeWidgetItem* spurs_tree = add_solid_node(m_tree, spu_tree, branch_name, branch_name + qstr(fmt::format(", Instance: *0x%x, LWMutex: 0x%x, LWCond: 0x%x" + , pspurs, spurs.mutex.sleep_queue, spurs.cond.lwcond_queue))); + + for (u32 i = 1; i; i <<= 1) + { + if (!(wklEnabled & i)) + { + continue; + } + + const u32 wid = std::countr_zero(i); + const u32 ready_count = spurs.readyCount(wid); + const auto state = spurs.wklState(wid).load(); + add_leaf(spurs_tree, qstr(fmt::format("Workload %u, Name: %s, State: %s, ReadyCnt: %u", wid, +spurs.wklName(wid).nameInstance, state, ready_count))); + } + } + else + { + // TODO: Might be old CellSpurs structure which is smaller + } + } }); QTreeWidgetItem* rsx_context_node = find_node(m_tree, additional_nodes::rsx_contexts); @@ -504,7 +579,7 @@ void kernel_explorer::Update() } const QString branch_name = "RSX Context 0x55555555"; - QTreeWidgetItem* rsx_tree = add_volatile_node(m_tree, rsx_context_node, branch_name, + QTreeWidgetItem* rsx_tree = add_solid_node(m_tree, rsx_context_node, branch_name, branch_name + qstr(fmt::format(u8", Local Size: %u MB, Base Addr: 0x%x, Device Addr: 0x%x, Handlers: 0x%x", context_info->memory_size >> 20, base, context_info->device_addr, +vm::_ref(context_info->driver_info).handlers))); QTreeWidgetItem* io_tree = add_volatile_node(m_tree, rsx_tree, tr("IO-EA Table")); @@ -611,7 +686,7 @@ void kernel_explorer::Update() continue; } - switch (node->data(0, kernel_item_role::type_role).toInt()) + switch (int type = node->data(0, kernel_item_role::type_role).toInt()) { case kernel_item_type::leaf: { @@ -619,6 +694,7 @@ void kernel_explorer::Update() break; } case kernel_item_type::node: + case kernel_item_type::solid_node: case kernel_item_type::volatile_node: { const int count = final_touches(node); @@ -633,7 +709,7 @@ void kernel_explorer::Update() } // Hide node if it has no children - node->setHidden(count <= 0); + node->setHidden(type != kernel_item_type::solid_node && count <= 0); break; } case kernel_item_type::root: