From 95c1443e306767370717f18ffe2fb1a7cd0a3422 Mon Sep 17 00:00:00 2001 From: Eladash Date: Mon, 12 Oct 2020 15:20:06 +0300 Subject: [PATCH] SPU: Validate reservation in GET commands (Accurate DMA) (#9062) --- rpcs3/Emu/Cell/SPUThread.cpp | 53 ++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index e3bc4a20ca..568c04376d 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1378,57 +1378,82 @@ void spu_thread::do_dma_transfer(const spu_mfc_cmd& args) continue; } + const auto cpu = static_cast(get_current_cpu_thread()); + + alignas(64) u8 temp[128]; + u8* dst0 = cpu && cpu->id_type() != 1 && (eal & -128) == cpu->raddr ? temp : dst; + + if (dst0 == +temp && time0 != cpu->rtime) + { + // Validate rtime for read data + cpu->set_events(SPU_EVENT_LR); + cpu->raddr = 0; + } + switch (size0) { case 1: { - *reinterpret_cast(dst) = *reinterpret_cast(src); + *reinterpret_cast(dst0) = *reinterpret_cast(src); break; } case 2: { - *reinterpret_cast(dst) = *reinterpret_cast(src); + *reinterpret_cast(dst0) = *reinterpret_cast(src); break; } case 4: { - *reinterpret_cast(dst) = *reinterpret_cast(src); + *reinterpret_cast(dst0) = *reinterpret_cast(src); break; } case 8: { - *reinterpret_cast(dst) = *reinterpret_cast(src); + *reinterpret_cast(dst0) = *reinterpret_cast(src); break; } case 128: { - mov_rdata(*reinterpret_cast(dst), *reinterpret_cast(src)); + mov_rdata(*reinterpret_cast(dst0), *reinterpret_cast(src)); break; } default: { - auto _dst = dst; - auto _src = src; - auto _size = size0; + auto dst1 = dst0; + auto src1 = src; + auto size1 = size0; - while (_size) + while (size1) { - *reinterpret_cast(_dst) = *reinterpret_cast(_src); + *reinterpret_cast(dst1) = *reinterpret_cast(src1); - _dst += 16; - _src += 16; - _size -= 16; + dst1 += 16; + src1 += 16; + size1 -= 16; } break; } } - if (time0 != vm::reservation_acquire(eal, size0) || (size0 == 128 && !cmp_rdata(*reinterpret_cast(dst), *reinterpret_cast(src)))) + if (time0 != vm::reservation_acquire(eal, size0) || (size0 == 128 && !cmp_rdata(*reinterpret_cast(dst0), *reinterpret_cast(src)))) { continue; } + if (dst0 == +temp) + { + // Write to LS + std::memcpy(dst, dst0, size0); + + // Validate data + if (std::memcmp(dst0, &cpu->rdata[eal & 127], size0) != 0) + { + cpu->set_events(SPU_EVENT_LR); + cpu->raddr = 0; + } + } + break; }