mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 03:25:16 +00:00
[SPU, TSX] Fix reservation corruption in PUTLLC
Change reservation locking logic.
This commit is contained in:
parent
3ad743ecaa
commit
49e96b39dd
2 changed files with 32 additions and 31 deletions
|
@ -1137,14 +1137,9 @@ extern bool ppu_stwcx(ppu_thread& ppu, u32 addr, u32 reg_value)
|
|||
|
||||
auto& res = vm::reservation_acquire(addr, sizeof(u32));
|
||||
|
||||
const auto [_, ok] = res.fetch_op([&](u64& reserv)
|
||||
{
|
||||
return (++reserv & -128) == ppu.rtime;
|
||||
});
|
||||
|
||||
ppu.raddr = 0;
|
||||
|
||||
if (ok)
|
||||
if (res == ppu.rtime && res.compare_and_swap_test(ppu.rtime, ppu.rtime | 1))
|
||||
{
|
||||
if (data.compare_and_swap_test(old_data, reg_value))
|
||||
{
|
||||
|
@ -1258,14 +1253,9 @@ extern bool ppu_stdcx(ppu_thread& ppu, u32 addr, u64 reg_value)
|
|||
|
||||
auto& res = vm::reservation_acquire(addr, sizeof(u64));
|
||||
|
||||
const auto [_, ok] = res.fetch_op([&](u64& reserv)
|
||||
{
|
||||
return (++reserv & -128) == ppu.rtime;
|
||||
});
|
||||
|
||||
ppu.raddr = 0;
|
||||
|
||||
if (ok)
|
||||
if (res == ppu.rtime && res.compare_and_swap_test(ppu.rtime, ppu.rtime | 1))
|
||||
{
|
||||
if (data.compare_and_swap_test(old_data, reg_value))
|
||||
{
|
||||
|
|
|
@ -349,7 +349,6 @@ const auto spu_putllc_tx = build_function_asm<u32(*)(u32 raddr, u64 rtime, const
|
|||
c.bind(fall);
|
||||
c.sar(x86::eax, 24);
|
||||
c.js(fail);
|
||||
c.lock().add(x86::qword_ptr(x86::rbx), 1);
|
||||
c.lock().bts(x86::dword_ptr(args[2], ::offset32(&spu_thread::state) - ::offset32(&spu_thread::rdata)), static_cast<u32>(cpu_flag::wait));
|
||||
|
||||
// Touch memory if transaction failed without RETRY flag on the first attempt
|
||||
|
@ -364,6 +363,13 @@ const auto spu_putllc_tx = build_function_asm<u32(*)(u32 raddr, u64 rtime, const
|
|||
|
||||
// Lightened transaction: only compare and swap data
|
||||
c.bind(next);
|
||||
|
||||
// Try to "lock" reservation
|
||||
c.mov(x86::rax, x86::r13);
|
||||
c.add(x86::r13, 1);
|
||||
c.lock().cmpxchg(x86::qword_ptr(x86::rbx), x86::r13);
|
||||
c.jne(fail);
|
||||
|
||||
build_transaction_enter(c, fall2, x86::r12, 666);
|
||||
|
||||
if (s_tsx_avx)
|
||||
|
@ -848,7 +854,6 @@ const auto spu_putlluc_tx = build_function_asm<u32(*)(u32 raddr, const void* rda
|
|||
//c.jmp(fall);
|
||||
|
||||
c.bind(fall);
|
||||
c.lock().add(x86::qword_ptr(x86::rbx), 1);
|
||||
c.lock().bts(x86::dword_ptr(args[2], ::offset32(&spu_thread::state)), static_cast<u32>(cpu_flag::wait));
|
||||
|
||||
// Touch memory if transaction failed without RETRY flag on the first attempt
|
||||
|
@ -859,9 +864,15 @@ const auto spu_putlluc_tx = build_function_asm<u32(*)(u32 raddr, const void* rda
|
|||
c.xor_(x86::rbp, 0xf80);
|
||||
|
||||
Label fall2 = c.newLabel();
|
||||
Label fail2 = c.newLabel();
|
||||
|
||||
// Lightened transaction
|
||||
c.bind(next);
|
||||
|
||||
// Try to acquire "PUTLLUC lock"
|
||||
c.lock().bts(x86::qword_ptr(x86::rbx), 6);
|
||||
c.jc(fail2);
|
||||
|
||||
build_transaction_enter(c, fall2, x86::r12, 666);
|
||||
|
||||
if (s_tsx_avx)
|
||||
|
@ -884,10 +895,14 @@ const auto spu_putlluc_tx = build_function_asm<u32(*)(u32 raddr, const void* rda
|
|||
}
|
||||
|
||||
c.xend();
|
||||
c.lock().add(x86::qword_ptr(x86::rbx), 127);
|
||||
c.lock().add(x86::qword_ptr(x86::rbx), 64);
|
||||
c.mov(x86::eax, 1);
|
||||
c.jmp(_ret);
|
||||
|
||||
c.bind(fail2);
|
||||
c.xor_(x86::eax, x86::eax);
|
||||
c.jmp(_ret);
|
||||
|
||||
c.bind(fall2);
|
||||
c.mov(x86::eax, 2);
|
||||
//c.jmp(_ret);
|
||||
|
@ -1617,24 +1632,16 @@ void spu_thread::do_putlluc(const spu_mfc_cmd& args)
|
|||
{
|
||||
cpu_thread::suspend_all cpu_lock(this);
|
||||
|
||||
// Try to obtain bit 7 (+64)
|
||||
if (!vm::reservation_acquire(addr, 128).bts(6))
|
||||
if (vm::reservation_acquire(addr, 128) & 64)
|
||||
{
|
||||
auto& data = vm::_ref<decltype(rdata)>(addr);
|
||||
mov_rdata(data, to_write);
|
||||
|
||||
// Keep checking written data against a rogue transaction sneak in
|
||||
while (std::atomic_thread_fence(std::memory_order_seq_cst), !cmp_rdata(data, to_write))
|
||||
// Wait for PUTLLC to complete
|
||||
while (vm::reservation_acquire(addr, 128) & 1)
|
||||
{
|
||||
mov_rdata(data, to_write);
|
||||
busy_wait(100);
|
||||
}
|
||||
|
||||
vm::reservation_acquire(addr, 128) += 63;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Give up if another PUTLLUC command took precedence
|
||||
vm::reservation_acquire(addr, 128) -= 1;
|
||||
mov_rdata(vm::_ref<decltype(rdata)>(addr), to_write);
|
||||
vm::reservation_acquire(addr, 128) += 64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1921,8 +1928,8 @@ bool spu_thread::process_mfc_cmd()
|
|||
|
||||
cpu_thread::suspend_all cpu_lock(this);
|
||||
|
||||
// Give up if other PUTLLC/PUTLLUC commands are in progress
|
||||
if (!vm::reservation_acquire(addr, 128).try_dec(rtime + 1))
|
||||
// Give up if PUTLLUC happened
|
||||
if (vm::reservation_acquire(addr, 128) == (rtime | 1))
|
||||
{
|
||||
auto& data = vm::_ref<decltype(rdata)>(addr);
|
||||
|
||||
|
@ -1937,6 +1944,10 @@ bool spu_thread::process_mfc_cmd()
|
|||
vm::reservation_acquire(addr, 128) -= 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vm::reservation_acquire(addr, 128) -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (auto& data = vm::_ref<decltype(rdata)>(addr); rtime == (vm::reservation_acquire(raddr, 128) & -128) && cmp_rdata(rdata, data))
|
||||
|
|
Loading…
Add table
Reference in a new issue