PPU Debugger/Memory: STDCX/STWCX breakpoints, make vm::_ref const

This commit is contained in:
elad335 2025-04-19 15:01:00 +03:00
parent 564c903fbd
commit b34a08fc99
14 changed files with 61 additions and 91 deletions

View file

@ -446,7 +446,7 @@ error_code _cellGcmInitBody(ppu_thread& ppu, vm::pptr<CellGcmContextData> contex
gcm_cfg.zculls_addr = vm::alloc(sizeof(CellGcmZcullInfo) * 8, vm::main);
gcm_cfg.tiles_addr = vm::alloc(sizeof(CellGcmTileInfo) * 15, vm::main);
vm::_ref<CellGcmContextData>(gcm_cfg.gcm_info.context_addr) = gcm_cfg.current_context;
vm::write<CellGcmContextData>(gcm_cfg.gcm_info.context_addr, gcm_cfg.current_context);
context->set(gcm_cfg.gcm_info.context_addr);
// 0x40 is to offset CellGcmControl from RsxDmaControl
@ -590,7 +590,7 @@ ret_type gcmSetPrepareFlip(ppu_thread& ppu, vm::ptr<CellGcmContextData> ctxt, u3
if (!old_api && ctxt.addr() == gcm_cfg.gcm_info.context_addr)
{
vm::_ref<CellGcmControl>(gcm_cfg.gcm_info.control_addr).put += cmd_size;
vm::_ptr<CellGcmControl>(gcm_cfg.gcm_info.control_addr)->put += cmd_size;
}
return static_cast<ret_type>(not_an_error(id));
@ -1463,7 +1463,7 @@ s32 cellGcmCallback(ppu_thread& ppu, vm::ptr<CellGcmContextData> context, u32 co
auto& gcm_cfg = g_fxo->get<gcm_config>();
auto& ctrl = vm::_ref<CellGcmControl>(gcm_cfg.gcm_info.control_addr);
auto& ctrl = *vm::_ptr<CellGcmControl>(gcm_cfg.gcm_info.control_addr);
// Flush command buffer (ie allow RSX to read up to context->current)
ctrl.put.exchange(getOffsetFromAddress(context->current.addr()));

View file

@ -4134,7 +4134,7 @@ s32 _spurs::create_task(vm::ptr<CellSpursTaskset> taskset, vm::ptr<u32> task_id,
u32 tmp_task_id;
vm::light_op(vm::_ref<atomic_be_t<v128>>(taskset.ptr(&CellSpursTaskset::enabled).addr()), [&](atomic_be_t<v128>& ptr)
vm::light_op(*vm::_ptr<atomic_be_t<v128>>(taskset.ptr(&CellSpursTaskset::enabled).addr()), [&](atomic_be_t<v128>& ptr)
{
// NOTE: Realfw processes this using 4 32-bits atomic loops
// But here its processed within a single 128-bit atomic op

View file

@ -1594,12 +1594,12 @@ s32 spursTasksetProcessRequest(spu_thread& spu, s32 request, u32* taskId, u32* i
spursHalt(spu);
}
vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::waiting)) = waiting;
vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::running)) = running;
vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::ready)) = ready;
vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::pending_ready)) = v128{};
vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::enabled)) = enabled;
vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::signalled)) = signalled;
// vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::waiting)) = waiting;
// vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::running)) = running;
// vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::ready)) = ready;
// vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::pending_ready)) = v128{};
// vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::enabled)) = enabled;
// vm::_ref<v128>(ctxt->taskset.addr() + ::offset32(&CellSpursTaskset::signalled)) = signalled;
std::memcpy(spu._ptr<void>(0x2700), spu._ptr<void>(0x100), 128); // Copy data
}//);

View file

@ -3367,7 +3367,10 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
fmt::throw_exception("PPU %s: Unaligned address: 0x%08x", sizeof(T) == 4 ? "STWCX" : "STDCX", addr);
}
auto& data = vm::_ref<atomic_be_t<u64>>(addr & -8);
// Notify breakpoint handler
vm::write<void>(addr, T{0}, &ppu);
auto& data = const_cast<atomic_be_t<u64>&>(vm::_ref<atomic_be_t<u64>>(addr & -8));
auto& res = vm::reservation_acquire(addr);
const u64 rtime = ppu.rtime;

View file

@ -3833,14 +3833,14 @@ bool spu_thread::do_putllc(const spu_mfc_cmd& args)
{
if (addr - spurs_addr <= 0x80)
{
mov_rdata(vm::_ref<spu_rdata_t>(addr), to_write);
mov_rdata(*vm::_ptr<spu_rdata_t>(addr), to_write);
res += 64;
return true;
}
}
else if (!g_use_rtm)
{
vm::_ref<atomic_t<u32>>(addr) += 0;
*vm::_ptr<atomic_t<u32>>(addr) += 0;
}
if (g_use_rtm) [[likely]]

View file

@ -181,7 +181,7 @@ error_code sys_rsx_memory_allocate(cpu_thread& cpu, vm::ptr<u32> mem_handle, vm:
if (u32 addr = rsx::get_current_renderer()->driver_info)
{
vm::_ref<RsxDriverInfo>(addr).memory_size = size;
vm::_ptr<RsxDriverInfo>(addr)->memory_size = size;
}
*mem_addr = rsx::constants::local_mem_base;
@ -265,7 +265,7 @@ error_code sys_rsx_context_allocate(cpu_thread& cpu, vm::ptr<u32> context_id, vm
*lpar_driver_info = dma_address + 0x100000;
*lpar_reports = dma_address + 0x200000;
auto &reports = vm::_ref<RsxReports>(vm::cast(*lpar_reports));
auto &reports = *vm::_ptr<RsxReports>(vm::cast(*lpar_reports));
std::memset(&reports, 0, sizeof(RsxReports));
for (usz i = 0; i < std::size(reports.notify); ++i)
@ -273,10 +273,10 @@ error_code sys_rsx_context_allocate(cpu_thread& cpu, vm::ptr<u32> context_id, vm
for (usz i = 0; i < std::size(reports.semaphore); i += 4)
{
reports.semaphore[i + 0].val.raw() = 0x1337C0D3;
reports.semaphore[i + 1].val.raw() = 0x1337BABE;
reports.semaphore[i + 2].val.raw() = 0x1337BEEF;
reports.semaphore[i + 3].val.raw() = 0x1337F001;
reports.semaphore[i + 0] = 0x1337C0D3;
reports.semaphore[i + 1] = 0x1337BABE;
reports.semaphore[i + 2] = 0x1337BEEF;
reports.semaphore[i + 3] = 0x1337F001;
}
for (usz i = 0; i < std::size(reports.report); ++i)
@ -286,7 +286,7 @@ error_code sys_rsx_context_allocate(cpu_thread& cpu, vm::ptr<u32> context_id, vm
reports.report[i].pad = -1;
}
auto &driverInfo = vm::_ref<RsxDriverInfo>(vm::cast(*lpar_driver_info));
auto &driverInfo = *vm::_ptr<RsxDriverInfo>(vm::cast(*lpar_driver_info));
std::memset(&driverInfo, 0, sizeof(RsxDriverInfo));
@ -303,7 +303,7 @@ error_code sys_rsx_context_allocate(cpu_thread& cpu, vm::ptr<u32> context_id, vm
render->driver_info = vm::cast(*lpar_driver_info);
auto &dmaControl = vm::_ref<RsxDmaControl>(vm::cast(*lpar_dma_control));
auto &dmaControl = *vm::_ptr<RsxDmaControl>(vm::cast(*lpar_dma_control));
dmaControl.get = 0;
dmaControl.put = 0;
dmaControl.ref = 0; // Set later to -1 by cellGcmSys
@ -527,7 +527,7 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
return { CELL_EINVAL, "context_id is 0x%x", context_id };
}
auto &driverInfo = vm::_ref<RsxDriverInfo>(render->driver_info);
auto &driverInfo = *vm::_ptr<RsxDriverInfo>(render->driver_info);
switch (package_id)
{
case 0x001: // FIFO
@ -862,7 +862,7 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
// seems gcmSysWaitLabel uses this offset, so lets set it to 0 every flip
// NOTE: Realhw resets 16 bytes of this semaphore for some reason
vm::_ref<atomic_t<u128>>(render->label_addr + 0x10).store(u128{});
vm::_ptr<atomic_t<u128>>(render->label_addr + 0x10)->store(u128{});
render->send_event(0, SYS_RSX_EVENT_FLIP_BASE << 1, 0);
break;

View file

@ -87,10 +87,7 @@ struct RsxDmaControl
be_t<u32> unk1;
};
struct RsxSemaphore
{
atomic_be_t<u32> val;
};
using RsxSemaphore = be_t<u32>;
struct alignas(16) RsxNotify
{

View file

@ -553,7 +553,7 @@ error_code sys_ss_individual_info_manager(u64 pkg_id, u64 a2, vm::ptr<u64> out_s
case 0x17002:
{
// TODO
vm::_ref<u64>(a5) = a4; // Write back size of buffer
vm::write<u64>(a5, a4); // Write back size of buffer
break;
}
// Get EID size

View file

@ -8,14 +8,14 @@
#include "util/to_endian.hpp"
class ppu_thread;
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
#include "rpcs3qt/breakpoint_handler.h"
#include "util/logs.hpp"
LOG_CHANNEL(debugbp_log, "DebugBP");
class ppu_thread;
void ppubreak(ppu_thread& ppu);
#endif
@ -282,9 +282,10 @@ namespace vm
}
// Convert specified PS3 address to a reference of specified (possibly converted to BE) type
template <typename T, typename U> inline to_be_t<T>& _ref(const U& addr)
// Const lvalue: prevent abused writes
template <typename T, typename U> inline const to_be_t<T>& _ref(const U& addr)
{
return *static_cast<to_be_t<T>*>(base(addr));
return *static_cast<const to_be_t<T>*>(base(addr));
}
// Access memory bypassing memory protection
@ -300,42 +301,43 @@ namespace vm
}
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
inline void write16(u32 addr, be_t<u16> value, ppu_thread* ppu = nullptr)
template <typename T, typename U = T>
inline void write(u32 addr, U value, ppu_thread* ppu = nullptr)
#else
inline void write16(u32 addr, be_t<u16> value)
template <typename T, typename U = T>
inline void write(u32 addr, U value, ppu_thread* = nullptr)
#endif
{
_ref<u16>(addr) = value;
using dest_t = std::conditional_t<std::is_void_v<T>, U, T>;
if constexpr (!std::is_void_v<T>)
{
*_ptr<dest_t>(addr) = value;
}
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
if (ppu && g_breakpoint_handler.HasBreakpoint(addr, breakpoint_types::bp_write))
{
debugbp_log.success("BPMW: breakpoint writing(16) 0x%x at 0x%x", value, addr);
debugbp_log.success("BPMW: breakpoint writing(%d) 0x%x at 0x%x",
sizeof(dest_t) * CHAR_BIT, value, addr);
ppubreak(*ppu);
}
#endif
}
inline void write16(u32 addr, be_t<u16> value, ppu_thread* ppu = nullptr)
{
write<be_t<u16>>(addr, value, ppu);
}
inline const be_t<u32>& read32(u32 addr)
{
return _ref<u32>(addr);
}
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
inline void write32(u32 addr, be_t<u32> value, ppu_thread* ppu = nullptr)
#else
inline void write32(u32 addr, be_t<u32> value)
#endif
{
_ref<u32>(addr) = value;
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
if (ppu && g_breakpoint_handler.HasBreakpoint(addr, breakpoint_types::bp_write))
{
debugbp_log.success("BPMW: breakpoint writing(32) 0x%x at 0x%x", value, addr);
ppubreak(*ppu);
}
#endif
write<be_t<u32>>(addr, value, ppu);
}
inline const be_t<u64>& read64(u32 addr)
@ -343,41 +345,9 @@ namespace vm
return _ref<u64>(addr);
}
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
inline void write64(u32 addr, be_t<u64> value, ppu_thread* ppu = nullptr)
#else
inline void write64(u32 addr, be_t<u64> value)
#endif
{
_ref<u64>(addr) = value;
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
if (ppu && g_breakpoint_handler.HasBreakpoint(addr, breakpoint_types::bp_write))
{
debugbp_log.success("BPMW: breakpoint writing(64) 0x%x at 0x%x", value, addr);
ppubreak(*ppu);
}
#endif
}
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
template <typename T, typename U = T>
inline void write(u32 addr, U value, ppu_thread* ppu = nullptr)
#else
template <typename T, typename U = T>
inline void write(u32 addr, U value)
#endif
{
_ref<T>(addr) = static_cast<T>(value);
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
if (ppu && g_breakpoint_handler.HasBreakpoint(addr, breakpoint_types::bp_write))
{
debugbp_log.success("BPMW: breakpoint writing(%d) 0x%x at 0x%x",
sizeof(T) * CHAR_BIT, value, addr);
ppubreak(*ppu);
}
#endif
write<be_t<u64>>(addr, value, ppu);
}
void init();

View file

@ -15,7 +15,7 @@ namespace rsx
RSX(ctx)->sync();
// Write ref+get (get will be written again with the same value at command end)
auto& dma = vm::_ref<RsxDmaControl>(RSX(ctx)->dma_address);
auto& dma = *vm::_ptr<RsxDmaControl>(RSX(ctx)->dma_address);
dma.get.release(RSX(ctx)->fifo_ctrl->get_pos());
dma.ref.store(arg);
}
@ -28,7 +28,7 @@ namespace rsx
// Syncronization point, may be associated with memory changes without actually changing addresses
RSX(ctx)->m_graphics_state |= rsx::pipeline_state::fragment_program_needs_rehash;
const auto& sema = vm::_ref<RsxSemaphore>(addr).val;
const auto& sema = vm::_ref<RsxSemaphore>(addr);
if (sema == arg)
{

View file

@ -566,7 +566,7 @@ namespace rsx
default:
rsx_log.error("NV4097_GET_REPORT: Bad type %d", type);
vm::_ref<atomic_t<CellGcmReportData>>(address_ptr).atomic_op([&](CellGcmReportData& data)
vm::_ptr<atomic_t<CellGcmReportData>>(address_ptr)->atomic_op([&](CellGcmReportData& data)
{
data.timer = RSX(ctx)->timestamp();
data.padding = 0;
@ -651,7 +651,7 @@ namespace rsx
ensure(addr != umax);
vm::_ref<atomic_t<RsxNotify>>(addr).store(
vm::_ptr<atomic_t<RsxNotify>>(addr)->store(
{
RSX(ctx)->timestamp(),
0

View file

@ -21,7 +21,7 @@ namespace rsx
// First, queue the GPU work. If it flushes the queue for us, the following routines will be faster.
const bool handled = RSX(ctx)->get_backend_config().supports_host_gpu_labels && RSX(ctx)->release_GCM_label(address, data);
if (vm::_ref<RsxSemaphore>(address).val == data)
if (vm::_ref<RsxSemaphore>(address) == data)
{
// It's a no-op to write the same value (although there is a delay in real-hw so it's more accurate to allow GPU label in this case)
return;
@ -57,7 +57,7 @@ namespace rsx
}
}
vm::_ref<RsxSemaphore>(address).val = data;
vm::write<atomic_t<RsxSemaphore>>(address, data);
}
}
}

View file

@ -1212,7 +1212,7 @@ namespace rsx
if (const u64 get_put = new_get_put.exchange(u64{umax});
get_put != umax)
{
vm::_ref<atomic_be_t<u64>>(dma_address + ::offset32(&RsxDmaControl::put)).release(get_put);
vm::_ptr<atomic_be_t<u64>>(dma_address + ::offset32(&RsxDmaControl::put))->release(get_put);
fifo_ctrl->set_get(static_cast<u32>(get_put));
fifo_ctrl->abort();
fifo_ret_addr = RSX_CALL_STACK_EMPTY;
@ -2457,7 +2457,7 @@ namespace rsx
}
rsx::reservation_lock<true> lock(sink, 16);
vm::_ref<atomic_t<CellGcmReportData>>(sink).store({timestamp(), value, 0});
vm::_ptr<atomic_t<CellGcmReportData>>(sink)->store({timestamp(), value, 0});
}
u32 thread::copy_zcull_stats(u32 memory_range_start, u32 memory_range, u32 destination)

View file

@ -62,7 +62,7 @@ namespace rsx
RSX(ctx)->reset();
RSX(ctx)->on_frame_end(arg);
RSX(ctx)->request_emu_flip(arg);
vm::_ref<atomic_t<u128>>(RSX(ctx)->label_addr + 0x10).store(u128{});
vm::_ptr<atomic_t<u128>>(RSX(ctx)->label_addr + 0x10)->store(u128{});
}
void user_command(context* ctx, u32, u32 arg)