mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-06 00:40:11 +00:00
RawSPU: protect NPC from writes/reads in running state
This commit is contained in:
parent
fad8b38b28
commit
727d783959
@ -1787,7 +1787,6 @@ void spursTasksetDispatch(spu_thread& spu)
|
||||
if (elfAddr & 2)
|
||||
{
|
||||
// TODO: Figure this out
|
||||
spu.status |= SPU_STATUS_STOPPED_BY_STOP;
|
||||
spu_runtime::g_escape(&spu);
|
||||
}
|
||||
|
||||
@ -1841,7 +1840,6 @@ void spursTasksetDispatch(spu_thread& spu)
|
||||
if (elfAddr & 2)
|
||||
{
|
||||
// TODO: Figure this out
|
||||
spu.status |= SPU_STATUS_STOPPED_BY_STOP;
|
||||
spu_runtime::g_escape(&spu);
|
||||
}
|
||||
|
||||
|
@ -8,14 +8,14 @@
|
||||
|
||||
inline void try_start(spu_thread& spu)
|
||||
{
|
||||
if (spu.status.fetch_op([](u32& status)
|
||||
if (spu.status_npc.fetch_op([](typename spu_thread::status_npc_sync_var& value)
|
||||
{
|
||||
if (status & SPU_STATUS_RUNNING)
|
||||
if (value.status & SPU_STATUS_RUNNING)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
status = SPU_STATUS_RUNNING;
|
||||
value.status = SPU_STATUS_RUNNING;
|
||||
return true;
|
||||
}).second)
|
||||
{
|
||||
@ -124,7 +124,7 @@ bool spu_thread::read_reg(const u32 addr, u32& value)
|
||||
|
||||
case SPU_Status_offs:
|
||||
{
|
||||
value = status;
|
||||
value = status_npc.load().status;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -136,8 +136,8 @@ bool spu_thread::read_reg(const u32 addr, u32& value)
|
||||
|
||||
case SPU_NPC_offs:
|
||||
{
|
||||
//npc = pc | ((ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0);
|
||||
value = npc;
|
||||
const auto current = status_npc.load();
|
||||
value = !(current.status & SPU_STATUS_RUNNING) ? current.npc : 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -238,13 +238,15 @@ bool spu_thread::write_reg(const u32 addr, const u32 value)
|
||||
|
||||
case SPU_RunCntl_offs:
|
||||
{
|
||||
run_ctrl = value;
|
||||
|
||||
if (value == SPU_RUNCNTL_RUN_REQUEST)
|
||||
{
|
||||
try_start(*this);
|
||||
}
|
||||
else if (value == SPU_RUNCNTL_STOP_REQUEST)
|
||||
{
|
||||
status &= ~SPU_STATUS_RUNNING;
|
||||
// TODO: Wait for the SPU to stop?
|
||||
state += cpu_flag::stop;
|
||||
}
|
||||
else
|
||||
@ -252,18 +254,22 @@ bool spu_thread::write_reg(const u32 addr, const u32 value)
|
||||
break;
|
||||
}
|
||||
|
||||
run_ctrl = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
case SPU_NPC_offs:
|
||||
{
|
||||
if ((value & 2) || value >= 0x40000)
|
||||
status_npc.fetch_op([value = value & 0x3fffd](status_npc_sync_var& state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (!(state.status & SPU_STATUS_RUNNING))
|
||||
{
|
||||
state.npc = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
npc = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -300,5 +306,5 @@ void spu_load_exec(const spu_exec_object& elf)
|
||||
}
|
||||
}
|
||||
|
||||
spu->npc = elf.header.e_entry;
|
||||
spu->status_npc = {SPU_STATUS_RUNNING, elf.header.e_entry};
|
||||
}
|
||||
|
@ -3399,7 +3399,6 @@ void spu_recompiler::HGT(spu_opcode_t op)
|
||||
c->lea(addr->r64(), get_pc(pos));
|
||||
c->and_(*addr, 0x3fffc);
|
||||
c->mov(SPU_OFF_32(pc), *addr);
|
||||
c->lock().bts(SPU_OFF_32(status), 2);
|
||||
c->mov(addr->r64(), reinterpret_cast<u64>(vm::base(0xffdead00)));
|
||||
c->mov(asmjit::x86::dword_ptr(addr->r64()), "HALT"_u32);
|
||||
c->jmp(ret);
|
||||
@ -3741,7 +3740,6 @@ void spu_recompiler::HLGT(spu_opcode_t op)
|
||||
c->lea(addr->r64(), get_pc(pos));
|
||||
c->and_(*addr, 0x3fffc);
|
||||
c->mov(SPU_OFF_32(pc), *addr);
|
||||
c->lock().bts(SPU_OFF_32(status), 2);
|
||||
c->mov(addr->r64(), reinterpret_cast<u64>(vm::base(0xffdead00)));
|
||||
c->mov(asmjit::x86::dword_ptr(addr->r64()), "HALT"_u32);
|
||||
c->jmp(ret);
|
||||
@ -4071,7 +4069,6 @@ void spu_recompiler::HEQ(spu_opcode_t op)
|
||||
c->lea(addr->r64(), get_pc(pos));
|
||||
c->and_(*addr, 0x3fffc);
|
||||
c->mov(SPU_OFF_32(pc), *addr);
|
||||
c->lock().bts(SPU_OFF_32(status), 2);
|
||||
c->mov(addr->r64(), reinterpret_cast<u64>(vm::base(0xffdead00)));
|
||||
c->mov(asmjit::x86::dword_ptr(addr->r64()), "HALT"_u32);
|
||||
c->jmp(ret);
|
||||
@ -4593,7 +4590,6 @@ void spu_recompiler::HGTI(spu_opcode_t op)
|
||||
c->lea(addr->r64(), get_pc(pos));
|
||||
c->and_(*addr, 0x3fffc);
|
||||
c->mov(SPU_OFF_32(pc), *addr);
|
||||
c->lock().bts(SPU_OFF_32(status), 2);
|
||||
c->mov(addr->r64(), reinterpret_cast<u64>(vm::base(0xffdead00)));
|
||||
c->mov(asmjit::x86::dword_ptr(addr->r64()), "HALT"_u32);
|
||||
c->jmp(ret);
|
||||
@ -4638,7 +4634,6 @@ void spu_recompiler::HLGTI(spu_opcode_t op)
|
||||
c->lea(addr->r64(), get_pc(pos));
|
||||
c->and_(*addr, 0x3fffc);
|
||||
c->mov(SPU_OFF_32(pc), *addr);
|
||||
c->lock().bts(SPU_OFF_32(status), 2);
|
||||
c->mov(addr->r64(), reinterpret_cast<u64>(vm::base(0xffdead00)));
|
||||
c->mov(asmjit::x86::dword_ptr(addr->r64()), "HALT"_u32);
|
||||
c->jmp(ret);
|
||||
@ -4701,7 +4696,6 @@ void spu_recompiler::HEQI(spu_opcode_t op)
|
||||
c->lea(addr->r64(), get_pc(pos));
|
||||
c->and_(*addr, 0x3fffc);
|
||||
c->mov(SPU_OFF_32(pc), *addr);
|
||||
c->lock().bts(SPU_OFF_32(status), 2);
|
||||
c->mov(addr->r64(), reinterpret_cast<u64>(vm::base(0xffdead00)));
|
||||
c->mov(asmjit::x86::dword_ptr(addr->r64()), "HALT"_u32);
|
||||
c->jmp(ret);
|
||||
|
@ -7773,9 +7773,6 @@ public:
|
||||
m_ir->CreateStore(&*(m_function->arg_begin() + 2), spu_ptr<u32>(&spu_thread::pc))->setVolatile(true);
|
||||
else
|
||||
update_pc();
|
||||
const auto pstatus = spu_ptr<u32>(&spu_thread::status);
|
||||
const auto chalt = m_ir->getInt32(SPU_STATUS_STOPPED_BY_HALT);
|
||||
m_ir->CreateAtomicRMW(llvm::AtomicRMWInst::Or, pstatus, chalt, llvm::AtomicOrdering::Release)->setVolatile(true);
|
||||
const auto ptr = _ptr<u32>(m_memptr, 0xffdead00);
|
||||
m_ir->CreateStore(m_ir->getInt32("HALT"_u32), ptr)->setVolatile(true);
|
||||
m_ir->CreateBr(next);
|
||||
|
@ -1067,9 +1067,7 @@ void spu_thread::cpu_init()
|
||||
}
|
||||
|
||||
run_ctrl.raw() = 0;
|
||||
status.raw() = 0;
|
||||
npc.raw() = 0;
|
||||
skip_npc_set = false;
|
||||
status_npc.raw() = {};
|
||||
|
||||
int_ctrl[0].clear();
|
||||
int_ctrl[1].clear();
|
||||
@ -1082,15 +1080,19 @@ void spu_thread::cpu_stop()
|
||||
{
|
||||
if (!group && offset >= RAW_SPU_BASE_ADDR)
|
||||
{
|
||||
// Save next PC and current SPU Interrupt Status
|
||||
if (skip_npc_set)
|
||||
status_npc.fetch_op([this](status_npc_sync_var& state)
|
||||
{
|
||||
skip_npc_set = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
npc = pc | interrupts_enabled;
|
||||
}
|
||||
if (state.status & SPU_STATUS_RUNNING)
|
||||
{
|
||||
// Save next PC and current SPU Interrupt Status
|
||||
// Used only by RunCtrl stop requests
|
||||
state.status &= ~SPU_STATUS_RUNNING;
|
||||
state.npc = pc | +interrupts_enabled;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
else if (group && is_stopped())
|
||||
{
|
||||
@ -1128,9 +1130,7 @@ extern thread_local std::string(*g_tls_log_prefix)();
|
||||
void spu_thread::cpu_task()
|
||||
{
|
||||
// Get next PC and SPU Interrupt status
|
||||
pc = npc.exchange(0);
|
||||
|
||||
skip_npc_set = false;
|
||||
pc = status_npc.load().npc;
|
||||
|
||||
// Note: works both on RawSPU and threaded SPU!
|
||||
set_interrupt_status((pc & 1) != 0);
|
||||
@ -2786,14 +2786,13 @@ bool spu_thread::stop_and_signal(u32 code)
|
||||
if (offset >= RAW_SPU_BASE_ADDR)
|
||||
{
|
||||
// Save next PC and current SPU Interrupt Status
|
||||
npc = (pc + 4) | (interrupts_enabled);
|
||||
skip_npc_set = true;
|
||||
state += cpu_flag::stop + cpu_flag::wait;
|
||||
status.atomic_op([code](u32& status)
|
||||
status_npc.atomic_op([&](status_npc_sync_var& state)
|
||||
{
|
||||
status = (status & 0xffff) | (code << 16);
|
||||
status |= SPU_STATUS_STOPPED_BY_STOP;
|
||||
status &= ~SPU_STATUS_RUNNING;
|
||||
state.status = (state.status & 0xffff) | (code << 16);
|
||||
state.status |= SPU_STATUS_STOPPED_BY_STOP;
|
||||
state.status &= ~SPU_STATUS_RUNNING;
|
||||
state.npc = (pc + 4) | +interrupts_enabled;
|
||||
});
|
||||
|
||||
int_ctrl[2].set(SPU_INT2_STAT_SPU_STOP_AND_SIGNAL_INT);
|
||||
@ -3118,7 +3117,7 @@ bool spu_thread::stop_and_signal(u32 code)
|
||||
}
|
||||
|
||||
spu_log.trace("sys_spu_thread_exit(status=0x%x)", ch_out_mbox.get_value());
|
||||
status |= SPU_STATUS_STOPPED_BY_STOP;
|
||||
status_npc = {SPU_STATUS_STOPPED_BY_STOP, 0};
|
||||
state += cpu_flag::stop;
|
||||
check_state();
|
||||
return true;
|
||||
@ -3143,10 +3142,11 @@ void spu_thread::halt()
|
||||
{
|
||||
state += cpu_flag::stop + cpu_flag::wait;
|
||||
|
||||
status.atomic_op([](u32& status)
|
||||
status_npc.atomic_op([this](status_npc_sync_var& state)
|
||||
{
|
||||
status |= SPU_STATUS_STOPPED_BY_HALT;
|
||||
status &= ~SPU_STATUS_RUNNING;
|
||||
state.status |= SPU_STATUS_STOPPED_BY_HALT;
|
||||
state.status &= ~SPU_STATUS_RUNNING;
|
||||
state.npc = pc | +interrupts_enabled;
|
||||
});
|
||||
|
||||
int_ctrl[2].set(SPU_INT2_STAT_SPU_HALT_OR_STEP_INT);
|
||||
@ -3154,7 +3154,6 @@ void spu_thread::halt()
|
||||
spu_runtime::g_escape(this);
|
||||
}
|
||||
|
||||
status |= SPU_STATUS_STOPPED_BY_HALT;
|
||||
fmt::throw_exception("Halt" HERE);
|
||||
}
|
||||
|
||||
|
@ -577,14 +577,18 @@ public:
|
||||
atomic_t<u32> ch_event_stat;
|
||||
atomic_t<bool> interrupts_enabled;
|
||||
|
||||
bool skip_npc_set = false;
|
||||
|
||||
u64 ch_dec_start_timestamp; // timestamp of writing decrementer value
|
||||
u32 ch_dec_value; // written decrementer value
|
||||
|
||||
atomic_t<u32> run_ctrl; // SPU Run Control register (only provided to get latest data written)
|
||||
atomic_t<u32> status; // SPU Status register
|
||||
atomic_t<u32> npc; // SPU Next Program Counter register
|
||||
|
||||
struct alignas(8) status_npc_sync_var
|
||||
{
|
||||
u32 status; // SPU Status register
|
||||
u32 npc; // SPU Next Program Counter register
|
||||
};
|
||||
|
||||
atomic_t<status_npc_sync_var> status_npc;
|
||||
|
||||
std::array<spu_int_ctrl_t, 3> int_ctrl; // SPU Class 0, 1, 2 Interrupt Management
|
||||
|
||||
|
@ -433,7 +433,7 @@ error_code sys_spu_thread_get_exit_status(ppu_thread& ppu, u32 id, vm::ptr<u32>
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (thread->status & SPU_STATUS_STOPPED_BY_STOP)
|
||||
if (thread->status_npc.load().status & SPU_STATUS_STOPPED_BY_STOP)
|
||||
{
|
||||
*status = thread->ch_out_mbox.get_value();
|
||||
return CELL_OK;
|
||||
@ -668,13 +668,12 @@ error_code sys_spu_thread_group_start(ppu_thread& ppu, u32 id)
|
||||
sys_spu_image::deploy(thread->offset, img.second.data(), img.first.nsegs);
|
||||
|
||||
thread->cpu_init();
|
||||
thread->npc = img.first.entry_point;
|
||||
thread->gpr[3] = v128::from64(0, args[0]);
|
||||
thread->gpr[4] = v128::from64(0, args[1]);
|
||||
thread->gpr[5] = v128::from64(0, args[2]);
|
||||
thread->gpr[6] = v128::from64(0, args[3]);
|
||||
|
||||
thread->status.exchange(SPU_STATUS_RUNNING);
|
||||
thread->status_npc = {SPU_STATUS_RUNNING, img.first.entry_point};
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user