Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement vm::reservation_op #9043

Merged
merged 1 commit into from Oct 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
86 changes: 18 additions & 68 deletions rpcs3/Emu/Cell/Modules/cellSpurs.cpp
Expand Up @@ -160,32 +160,6 @@ extern u32 ppu_lwarx(ppu_thread&, u32);
extern bool ppu_stwcx(ppu_thread&, u32, u32);
extern bool ppu_stdcx(ppu_thread&, u32, u64);

bool do_atomic_128_load(cpu_thread& cpu, u32 addr, void* dst)
{
verify(HERE), (addr % 128) == 0;

while (!cpu.test_stopped())
{
const u64 rtime = vm::reservation_acquire(addr, 128);

if (rtime % 128)
{
continue;
}

std::memcpy(dst, vm::base(addr), 128);

if (rtime != vm::reservation_acquire(addr, 128))
{
continue;
}

return true;
}

return false;
}

error_code sys_spu_image_close(ppu_thread&, vm::ptr<sys_spu_image> img);

//----------------------------------------------------------------------------
Expand Down Expand Up @@ -2516,7 +2490,7 @@ s32 cellSpursShutdownWorkload(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid

if (wid >= (spurs->flags1 & SF1_32_WORKLOADS ? CELL_SPURS_MAX_WORKLOAD2 : CELL_SPURS_MAX_WORKLOAD))
return CELL_SPURS_POLICY_MODULE_ERROR_INVAL;

if (spurs->exception)
return CELL_SPURS_POLICY_MODULE_ERROR_STAT;

Expand Down Expand Up @@ -4393,7 +4367,7 @@ s32 _spurs::check_job_chain_attribute(u32 sdkVer, vm::cptr<u64> jcEntry, u16 siz
{
if (!jcEntry)
return CELL_SPURS_JOB_ERROR_NULL_POINTER;

if (!jcEntry.aligned())
return CELL_SPURS_JOB_ERROR_ALIGN;

Expand Down Expand Up @@ -4592,13 +4566,12 @@ s32 cellSpursGetJobChainInfo(ppu_thread& ppu, vm::ptr<CellSpursJobChain> jobChai
return err;
}

CellSpursJobChain data;

// Read the commands queue atomically
if (!do_atomic_128_load(ppu, jobChain.addr(), &data))
CellSpursJobChain data;
vm::reservation_peek(ppu, vm::unsafe_ptr_cast<CellSpursJobChain_x00>(jobChain), [&](const CellSpursJobChain_x00& jch)
{
return 0;
}
std::memcpy(&data, &jch, sizeof(jch));
});

info->linkRegister[0] = +data.linkRegister[0];
info->linkRegister[1] = +data.linkRegister[1];
Expand Down Expand Up @@ -4896,48 +4869,25 @@ s32 cellSpursAddUrgentCommand(ppu_thread& ppu, vm::ptr<CellSpursJobChain> jobCha
if (jobChain->workloadId >= CELL_SPURS_MAX_WORKLOAD2)
return CELL_SPURS_JOB_ERROR_INVAL;

for (u32 i = 0;;)
{
if (i >= std::size(jobChain->urgentCmds))
{
// Exausted all slots
return CELL_SPURS_JOB_ERROR_BUSY;
}
s32 result = CELL_OK;

u64 currCmd = ppu_ldarx(ppu, jobChain.ptr(&CellSpursJobChain::urgentCmds, i).addr());
std::atomic_thread_fence(std::memory_order_acq_rel);

bool found = false;
bool reset = false;

if (!currCmd)
vm::reservation_op(vm::unsafe_ptr_cast<CellSpursJobChain_x00>(jobChain), [&](CellSpursJobChain_x00& jch)
{
for (auto& cmd : jch.urgentCmds)
{
if (i != 0 && !jobChain->urgentCmds[i - 1])
if (!cmd)
{
// Restart search, someone emptied out the previous one
reset = true;
}
else
{
found = true;
currCmd = newCmd;
cmd = newCmd;
return true;
}
}

if (reset || !ppu_stdcx(ppu, jobChain.ptr(&CellSpursJobChain::urgentCmds, i).addr(), currCmd))
{
// Someone modified the job chain or the previous slot is empty, restart search
i = 0;
continue;
}

if (found)
break;

i++;
}
// Considered unlikely so unoptimized
result = CELL_SPURS_JOB_ERROR_BUSY;
return false;
});

return CELL_OK;
return result;
}

s32 cellSpursAddUrgentCall(ppu_thread& ppu, vm::ptr<CellSpursJobChain> jobChain, vm::ptr<u64> commandList)
Expand Down
23 changes: 21 additions & 2 deletions rpcs3/Emu/Cell/Modules/cellSpurs.h
Expand Up @@ -465,6 +465,25 @@ struct alignas(128) CellSpursJobChain
u8 unk5[0x100 - 0xA8];
};

struct alignas(128) CellSpursJobChain_x00
{
vm::bcptr<u64, u64> pc; // 0x00
vm::bcptr<u64, u64> linkRegister[3]; // 0x08
u8 unk0[0x3]; // 0x20
b8 isHalted; // 0x23
b8 autoReadyCount; // 0x24
u8 unk1[0x7]; // 0x25
u8 val2C; // 0x2C
u8 val2D; // 0x2D
u8 val2E; // 0x2E
u8 val2F; // 0x2F
be_t<u64> urgentCmds[4]; // 0x30
u8 unk2[0x22]; // 0x50
be_t<u16> maxGrabbedJob; // 0x72
be_t<u32> workloadId; // 0x74
vm::bptr<CellSpurs, u64> spurs; // 0x78
};

struct CellSpursJobChainInfo
{
be_t<u64> urgentCommandSlot[4]; // 0x00
Expand Down Expand Up @@ -494,7 +513,7 @@ struct alignas(8) CellSpursJobChainAttribute
be_t<u32> maxGrabbedJob; // 0x0E
u8 priorities[8]; // 0x10
be_t<u32> maxContention; // 0x18
b8 autoSpuCount; // 0x1C
b8 autoSpuCount; // 0x1C
u8 padding[3]; // 0x1D
be_t<u32> tag1; // 0x20
be_t<u32> tag2; // 0x24
Expand Down Expand Up @@ -1031,7 +1050,7 @@ struct alignas(16) CellSpursTaskBinInfo

struct alignas(128) CellSpursBarrier
{
be_t<u32> zero; // 0x00
be_t<u32> zero; // 0x00
be_t<u32> remained; // 0x04
u8 unk0[0x34 - 0x8];
vm::bptr<CellSpursTaskset> taskset; // 0x34
Expand Down
47 changes: 47 additions & 0 deletions rpcs3/Emu/Memory/vm.cpp
Expand Up @@ -13,6 +13,7 @@
#include "Emu/CPU/CPUThread.h"
#include "Emu/Cell/lv2/sys_memory.h"
#include "Emu/RSX/GSRender.h"
#include "Emu/Cell/SPURecompiler.h"
#include <atomic>
#include <thread>
#include <deque>
Expand Down Expand Up @@ -470,6 +471,52 @@ namespace vm
}
}

void reservation_op_internal(u32 addr, std::function<bool()> func)
{
const auto _cpu = get_current_cpu_thread();

// Acknowledge contender if necessary (TODO: check)
_cpu->state += cpu_flag::wait;

{
cpu_thread::suspend_all cpu_lock(_cpu);

// Wait to acquire PUTLLUC lock
while (vm::reservation_acquire(addr, 128).bts(std::countr_zero<u32>(vm::putlluc_lockb)))
{
busy_wait(100);
}

if (func())
{
// Success, release PUTLLUC and PUTLLC locks if necessary
vm::reservation_acquire(addr, 128) += 63;
}
else
{
// Fake update (TODO)
vm::reservation_acquire(addr, 128) += 63;
}
}

vm::reservation_notifier(addr, 128).notify_all();
}

void reservation_escape_internal()
{
const auto _cpu = get_current_cpu_thread();

if (_cpu && _cpu->id_type() == 1)
{
thread_ctrl::emergency_exit("vm::reservation_escape");
}

if (_cpu && _cpu->id_type() == 2)
{
spu_runtime::g_escape(static_cast<spu_thread*>(_cpu));
}
}

static void _page_map(u32 addr, u8 flags, u32 size, utils::shm* shm)
{
if (!size || (size | addr) % 4096 || flags & page_allocated)
Expand Down
7 changes: 7 additions & 0 deletions rpcs3/Emu/Memory/vm_ptr.h
Expand Up @@ -323,6 +323,13 @@ namespace vm
{
return vm::cast(other.addr(), HERE);
}

// Perform reinterpret cast
template <typename CT, typename T, typename AT, typename = decltype(reinterpret_cast<to_be_t<CT>*>(std::declval<T*>()))>
inline _ptr_base<to_be_t<CT>, u32> unsafe_ptr_cast(const _ptr_base<T, AT>& other)
{
return vm::cast(other.addr(), HERE);
}
}

struct null_t
Expand Down