1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00

cellSpurs: Implement more HLE functions (part 1)

This commit is contained in:
Eladash 2020-10-05 15:37:59 +03:00 committed by Ivan
parent a5cff8b186
commit c628147521
3 changed files with 561 additions and 90 deletions

View File

@ -269,15 +269,21 @@ class b8
public:
b8() = default;
constexpr b8(bool value)
constexpr b8(bool value) noexcept
: m_value(value)
{
}
constexpr operator bool() const
constexpr operator bool() const noexcept
{
return m_value != 0;
}
constexpr bool set(bool value) noexcept
{
m_value = value;
return value;
}
};
#ifndef _MSC_VER

View File

@ -160,6 +160,32 @@ 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);
//----------------------------------------------------------------------------
@ -456,6 +482,13 @@ namespace _spurs
// SPURS job chain functions
//
namespace _spurs
{
s32 check_job_chain_attribute(u32 sdkVer, vm::cptr<u64> jcEntry, u16 sizeJobDescr, u16 maxGrabbedJob
, u64 priorities, u32 maxContention, u8 autoSpuCount, u32 tag1, u32 tag2
, u8 isFixedMemAlloc, u32 maxSizeJob, u32 initSpuCount);
}
//s32 cellSpursCreateJobChainWithAttribute();
//s32 cellSpursCreateJobChain();
//s32 cellSpursJoinJobChain();
@ -599,15 +632,10 @@ s32 _spurs::detach_lv2_eq(vm::ptr<CellSpurs> spurs, u8 spuPort, bool spursCreate
{
const u64 mask = 1ull << spuPort;
if (_spurs::get_sdk_version() >= 0x180000)
if (!(spurs->spuPortBits.fetch_and(~mask) & mask) && _spurs::get_sdk_version() >= 0x180000)
{
if ((spurs->spuPortBits.load() & mask) == 0u)
{
return CELL_SPURS_CORE_ERROR_SRCH;
}
return CELL_SPURS_CORE_ERROR_SRCH;
}
spurs->spuPortBits &= ~mask;
}
return CELL_OK;
@ -1813,6 +1841,16 @@ s32 cellSpursSetPriorities(vm::ptr<CellSpurs> spurs, u32 wid, vm::cptr<u8[8]> pr
s32 cellSpursSetPriority(vm::ptr<CellSpurs> spurs, u32 wid, u32 spuId, u32 priority)
{
cellSpurs.todo("cellSpursSetPriority(spurs=*0x%x, wid=%d, spuId=%d, priority=%d)", spurs, wid, spuId, priority);
if (!spurs)
return CELL_SPURS_CORE_ERROR_NULL_POINTER;
if (!spurs.aligned())
return CELL_SPURS_CORE_ERROR_ALIGN;
if (wid >= (spurs->flags1 & SF1_32_WORKLOADS ? CELL_SPURS_MAX_WORKLOAD2 : CELL_SPURS_MAX_WORKLOAD))
return CELL_SPURS_CORE_ERROR_INVAL;
return CELL_OK;
}
@ -1910,6 +1948,15 @@ s32 cellSpursUnsetGlobalExceptionEventHandler(vm::ptr<CellSpurs> spurs)
{
cellSpurs.warning("cellSpursUnsetGlobalExceptionEventHandler(spurs=*0x%x)", spurs);
if (!spurs)
return CELL_SPURS_CORE_ERROR_NULL_POINTER;
if (!spurs.aligned())
return CELL_SPURS_CORE_ERROR_ALIGN;
if (spurs->exception)
return CELL_SPURS_CORE_ERROR_STAT;
spurs->globalSpuExceptionHandlerArgs = 0;
spurs->globalSpuExceptionHandler.exchange(0);
return CELL_OK;
@ -1918,7 +1965,38 @@ s32 cellSpursUnsetGlobalExceptionEventHandler(vm::ptr<CellSpurs> spurs)
/// Get internal information of a SPURS instance
s32 cellSpursGetInfo(vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursInfo> info)
{
UNIMPLEMENTED_FUNC(cellSpurs);
cellSpurs.trace("cellSpursGetInfo(spurs=*0x%x, info=*0x%x)", spurs, info);
if (!spurs || !info)
return CELL_SPURS_CORE_ERROR_NULL_POINTER;
if (!spurs.aligned())
return CELL_SPURS_CORE_ERROR_ALIGN;
const auto flags = spurs->flags;
info->nSpus = spurs->nSpus;
info->spuThreadGroupPriority = spurs->spuPriority;
info->ppuThreadPriority = spurs->ppuPriority;
info->exitIfNoWork = !!(flags & SAF_EXIT_IF_NO_WORK);
info->spurs2 = !!(flags & SAF_SECOND_VERSION);
info->spuThreadGroup = spurs->spuTG;
std::memcpy(&info->spuThreads, &spurs->spus, sizeof(s32) * 8);
info->spursHandlerThread0 = spurs->ppu0;
info->spursHandlerThread1 = spurs->ppu1;
info->traceBufferSize = spurs->traceDataSize;
const auto trace_addr = vm::cast(spurs->traceBuffer.addr(), HERE);
info->traceBuffer = vm::addr_t{trace_addr & ~3};
info->traceMode = trace_addr & 3;
const u8 name_size = spurs->prefixSize;
std::memcpy(&info->namePrefix, spurs->prefix, name_size);
info->namePrefix[name_size] = '\0';
info->namePrefixLength = name_size;
// TODO: Should call sys_spu_thread_group_syscall_253 for specific SPU group types
info->deadlineMeetCounter = 0;
info->deadlineMissCounter = 0;
return CELL_OK;
}
@ -2251,7 +2329,7 @@ s32 _spurs::add_workload(vm::ptr<CellSpurs> spurs, vm::ptr<u32> wid, vm::cptr<vo
}
u32 wnum;
const u32 wmax = spurs->flags1 & SF1_32_WORKLOADS ? 0x20u : 0x10u; // TODO: check if can be changed
const u32 wmax = spurs->flags1 & SF1_32_WORKLOADS ? CELL_SPURS_MAX_WORKLOAD2 : CELL_SPURS_MAX_WORKLOAD; // TODO: check if can be changed
spurs->wklEnabled.atomic_op([spurs, wmax, &wnum](be_t<u32>& value)
{
wnum = std::countl_one<u32>(value); // found empty position
@ -2426,9 +2504,73 @@ s32 cellSpursAddWorkloadWithAttribute(vm::ptr<CellSpurs> spurs, vm::ptr<u32> wid
}
/// Request workload shutdown
s32 cellSpursShutdownWorkload()
s32 cellSpursShutdownWorkload(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid)
{
UNIMPLEMENTED_FUNC(cellSpurs);
cellSpurs.trace("cellSpursShutdownWorkload(spurs=*0x%x, wid=0x%x)", spurs, wid);
if (!spurs)
return CELL_SPURS_POLICY_MODULE_ERROR_NULL_POINTER;
if (!spurs.aligned())
return CELL_SPURS_POLICY_MODULE_ERROR_ALIGN;
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;
u32 state_new;
while (true)
{
const u32 value = ppu_lwarx(ppu, vm::get_addr(&spurs->wklState(wid & -4)));
union
{
le_t<u32> _u32;
u8 _u8[4];
} data{value};
const u32 state = data._u8[wid % 4];
if (state <= SPURS_WKL_STATE_PREPARING)
{
// Cleanly leave the function without traces of reservation
ppu.raddr = 0;
return CELL_SPURS_POLICY_MODULE_ERROR_STAT;
}
if (state == SPURS_WKL_STATE_SHUTTING_DOWN || state == SPURS_WKL_STATE_REMOVABLE)
{
ppu.raddr = 0;
return CELL_OK;
}
state_new = spurs->wklStatus(wid) ? SPURS_WKL_STATE_SHUTTING_DOWN : SPURS_WKL_STATE_REMOVABLE;
data._u8[wid % 4] = state_new;
if (ppu_stwcx(ppu, vm::get_addr(&spurs->wklState(wid & -4)), data._u32))
{
break;
}
}
if (state_new == SPURS_WKL_STATE_SHUTTING_DOWN)
{
spurs->sysSrvMsgUpdateWorkload = -1;
spurs->sysSrvMessage = 0;
return CELL_OK;
}
auto [res, rtime] = vm::reservation_lock(vm::get_addr(&spurs->wklEvent(wid)), 1, vm::dma_lockb);
const auto old = spurs->wklEvent(wid).fetch_or(1);
res.release(rtime + (old & 1 ? 0 : 128));
if (old & 0x12 && !(old & 1) && sys_event_port_send(spurs->eventPort, 0, 0, (1u << 31) >> wid))
{
return CELL_SPURS_CORE_ERROR_STAT;
}
return CELL_OK;
}
@ -2562,7 +2704,7 @@ s32 cellSpursReadyCountStore(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid,
return CELL_SPURS_POLICY_MODULE_ERROR_ALIGN;
}
if (wid >= (spurs->flags1 & SF1_32_WORKLOADS ? 0x20u : 0x10u) || value > 0xffu)
if (wid >= (spurs->flags1 & SF1_32_WORKLOADS ? CELL_SPURS_MAX_WORKLOAD2 : CELL_SPURS_MAX_WORKLOAD) || value > 0xffu)
{
return CELL_SPURS_POLICY_MODULE_ERROR_INVAL;
}
@ -2598,7 +2740,7 @@ s32 cellSpursReadyCountSwap(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid,
return CELL_SPURS_POLICY_MODULE_ERROR_ALIGN;
}
if (wid >= (spurs->flags1 & SF1_32_WORKLOADS ? 0x20u : 0x10u) || swap > 0xffu)
if (wid >= (spurs->flags1 & SF1_32_WORKLOADS ? CELL_SPURS_MAX_WORKLOAD2 : CELL_SPURS_MAX_WORKLOAD) || swap > 0xffu)
{
return CELL_SPURS_POLICY_MODULE_ERROR_INVAL;
}
@ -2636,7 +2778,7 @@ s32 cellSpursReadyCountCompareAndSwap(ppu_thread& ppu, vm::ptr<CellSpurs> spurs,
return CELL_SPURS_POLICY_MODULE_ERROR_ALIGN;
}
if (wid >= (spurs->flags1 & SF1_32_WORKLOADS ? 0x20u : 0x10u) || (swap | compare) > 0xffu)
if (wid >= (spurs->flags1 & SF1_32_WORKLOADS ? CELL_SPURS_MAX_WORKLOAD2 : CELL_SPURS_MAX_WORKLOAD) || (swap | compare) > 0xffu)
{
return CELL_SPURS_POLICY_MODULE_ERROR_INVAL;
}
@ -2676,7 +2818,7 @@ s32 cellSpursReadyCountAdd(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid, v
return CELL_SPURS_POLICY_MODULE_ERROR_ALIGN;
}
if (wid >= (spurs->flags1 & SF1_32_WORKLOADS ? 0x20u : 0x10u))
if (wid >= (spurs->flags1 & SF1_32_WORKLOADS ? CELL_SPURS_MAX_WORKLOAD2 : CELL_SPURS_MAX_WORKLOAD))
{
return CELL_SPURS_POLICY_MODULE_ERROR_INVAL;
}
@ -2748,9 +2890,9 @@ s32 cellSpursGetWorkloadData(vm::ptr<CellSpurs> spurs, vm::ptr<u64> data, u32 wi
}
/// Get workload information
s32 cellSpursGetWorkloadInfo()
s32 cellSpursGetWorkloadInfo(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid, vm::ptr<CellSpursWorkloadInfo> info)
{
UNIMPLEMENTED_FUNC(cellSpurs);
cellSpurs.todo("cellSpursGetWorkloadInfo(spurs=*0x%x, wid=0x%x, info=*0x%x)", spurs, wid, info);
return CELL_OK;
}
@ -2783,7 +2925,7 @@ s32 _cellSpursWorkloadFlagReceiver(vm::ptr<CellSpurs> spurs, u32 wid, u32 is_set
return CELL_SPURS_POLICY_MODULE_ERROR_ALIGN;
}
if (wid >= (spurs->flags1 & SF1_32_WORKLOADS ? 0x20u : 0x10u))
if (wid >= (spurs->flags1 & SF1_32_WORKLOADS ? CELL_SPURS_MAX_WORKLOAD2 : CELL_SPURS_MAX_WORKLOAD))
{
return CELL_SPURS_POLICY_MODULE_ERROR_INVAL;
}
@ -4245,6 +4387,39 @@ s32 _cellSpursTasksetAttributeInitialize(vm::ptr<CellSpursTasksetAttribute> attr
return CELL_OK;
}
s32 _spurs::check_job_chain_attribute(u32 sdkVer, vm::cptr<u64> jcEntry, u16 sizeJobDescr, u16 maxGrabbedJob
, u64 priorities, u32 maxContention, u8 autoSpuCount, u32 tag1, u32 tag2
, u8 isFixedMemAlloc, u32 maxSizeJob, u32 initSpuCount)
{
if (!jcEntry)
return CELL_SPURS_JOB_ERROR_NULL_POINTER;
if (!jcEntry.aligned())
return CELL_SPURS_JOB_ERROR_ALIGN;
if (!maxGrabbedJob || maxGrabbedJob > 0x10u)
return CELL_SPURS_JOB_ERROR_INVAL;
// Tag 31 is not allowed from version 1.90 for some reason
if (u32 max_tag = sdkVer < 0x19000 ? 31 : 30; tag1 > max_tag || tag2 > max_tag)
return CELL_SPURS_JOB_ERROR_INVAL;
// Test if any of the value >= CELL_SPURS_MAX_PRIORITY
if (priorities & 0xf0f0f0f0f0f0f0f0)
return CELL_SPURS_JOB_ERROR_INVAL;
if (sizeJobDescr % 0x80 && sizeJobDescr != 64u)
return CELL_SPURS_JOB_ERROR_INVAL;
if (autoSpuCount && initSpuCount > 0xffu)
return CELL_SPURS_JOB_ERROR_INVAL;
if (maxSizeJob <= 0xffu || maxSizeJob > 0x400u || maxSizeJob % 0x80)
return CELL_SPURS_JOB_ERROR_INVAL;
return CELL_OK;
}
s32 cellSpursCreateJobChainWithAttribute()
{
UNIMPLEMENTED_FUNC(cellSpurs);
@ -4276,13 +4451,13 @@ s32 cellSpursKickJobChain(ppu_thread& ppu, vm::ptr<CellSpursJobChain> jobChain,
const u32 wid = jobChain->workloadId;
const auto spurs = +jobChain->spurs;
if (wid >= 32u)
if (wid >= CELL_SPURS_MAX_WORKLOAD2)
return CELL_SPURS_JOB_ERROR_INVAL;
if (jobChain->val2D > 1)
return CELL_SPURS_JOB_ERROR_PERM;
if (jobChain->val24)
if (jobChain->autoReadyCount)
ppu_execute<&cellSpursReadyCountStore>(ppu, spurs, wid, numReadyCount);
else
ppu_execute<&cellSpursReadyCountCompareAndSwap>(ppu, spurs, wid, +vm::var<u32>{}, 0, 1);
@ -4297,15 +4472,49 @@ s32 cellSpursKickJobChain(ppu_thread& ppu, vm::ptr<CellSpursJobChain> jobChain,
return err;
}
s32 _cellSpursJobChainAttributeInitialize()
s32 _cellSpursJobChainAttributeInitialize(u32 jmRevsion, u32 sdkRevision, vm::ptr<CellSpursJobChainAttribute> attr, vm::cptr<u64> jobChainEntry, u16 sizeJobDescriptor, u16 maxGrabbedJob
, vm::cptr<u8[8]> priorityTable, u32 maxContention, b8 autoRequestSpuCount, u32 tag1, u32 tag2, b8 isFixedMemAlloc, u32 maxSizeJobDescriptor, u32 initialRequestSpuCount)
{
UNIMPLEMENTED_FUNC(cellSpurs);
cellSpurs.trace("_cellSpursJobChainAttributeInitialize(jmRevsion=0x%x, sdkRevision=0x%x, attr=*0x%x, jobChainEntry=*0x%x, sizeJobDescriptor=0x%x, maxGrabbedJob=0x%x, priorityTable=*0x%x"
", maxContention=%u, autoRequestSpuCount=%s, tag1=0x%x, tag2=0x%x, isFixedMemAlloc=%s, maxSizeJobDescriptor=0x%x, initialRequestSpuCount=%u)",
jmRevsion, sdkRevision, attr, jobChainEntry, sizeJobDescriptor, maxGrabbedJob, priorityTable, maxContention, autoRequestSpuCount, tag1, tag2, isFixedMemAlloc, maxSizeJobDescriptor, initialRequestSpuCount);
if (!attr)
return CELL_SPURS_JOB_ERROR_NULL_POINTER;
if (!attr.aligned())
return CELL_SPURS_JOB_ERROR_ALIGN;
const u64 prio = std::bit_cast<u64>(*priorityTable);
if (auto err = _spurs::check_job_chain_attribute(sdkRevision, jobChainEntry, sizeJobDescriptor, maxGrabbedJob, prio, maxContention
, autoRequestSpuCount, tag1, tag2, isFixedMemAlloc, maxSizeJobDescriptor, initialRequestSpuCount))
{
return err;
}
attr->jmVer = jmRevsion;
attr->sdkVer = sdkRevision;
attr->jobChainEntry = jobChainEntry;
attr->sizeJobDescriptor = sizeJobDescriptor;
attr->maxGrabbedJob = maxGrabbedJob;
std::memcpy(&attr->priorities, &prio, 8);
attr->maxContention = maxContention;
attr->autoSpuCount = autoRequestSpuCount;
attr->tag1 = tag1;
attr->tag2 = tag2;
attr->isFixedMemAlloc = isFixedMemAlloc;
attr->maxSizeJobDescriptor = maxSizeJobDescriptor;
attr->initSpuCount = initialRequestSpuCount;
attr->haltOnError = 0;
attr->name = vm::null;
attr->jobMemoryCheck = false;
return CELL_OK;
}
s32 cellSpursGetJobChainId(vm::ptr<CellSpursJobChain> jobChain, vm::ptr<u32> id)
{
cellSpurs.trace("cellSpursGetJobChainId(jobChain=*0x%x, id=*0x%x", jobChain, id);
cellSpurs.trace("cellSpursGetJobChainId(jobChain=*0x%x, id=*0x%x)", jobChain, id);
if (!jobChain || !id)
return CELL_SPURS_JOB_ERROR_NULL_POINTER;
@ -4317,27 +4526,109 @@ s32 cellSpursGetJobChainId(vm::ptr<CellSpursJobChain> jobChain, vm::ptr<u32> id)
return CELL_OK;
}
s32 cellSpursJobChainSetExceptionEventHandler()
s32 cellSpursJobChainSetExceptionEventHandler(vm::ptr<CellSpursJobChain> jobChain, vm::ptr<CellSpursJobChainExceptionEventHandler> handler, vm::ptr<void> arg)
{
UNIMPLEMENTED_FUNC(cellSpurs);
cellSpurs.trace("cellSpursJobChainSetExceptionEventHandler(jobChain=*0x%x, handler=*0x%x, arg=*0x%x)", jobChain, handler, arg);
if (!jobChain || !handler)
return CELL_SPURS_JOB_ERROR_NULL_POINTER;
if (!jobChain.aligned())
return CELL_SPURS_JOB_ERROR_ALIGN;
if (jobChain->workloadId >= CELL_SPURS_MAX_WORKLOAD2)
return CELL_SPURS_JOB_ERROR_INVAL;
if (jobChain->exceptionEventHandler)
return CELL_SPURS_JOB_ERROR_BUSY;
jobChain->exceptionEventHandlerArgument = arg;
jobChain->exceptionEventHandler.set(handler.addr());
return CELL_OK;
}
s32 cellSpursJobChainUnsetExceptionEventHandler()
s32 cellSpursJobChainUnsetExceptionEventHandler(vm::ptr<CellSpursJobChain> jobChain)
{
UNIMPLEMENTED_FUNC(cellSpurs);
cellSpurs.trace("cellSpursJobChainUnsetExceptionEventHandler(jobChain=*0x%x)", jobChain);
if (!jobChain)
return CELL_SPURS_JOB_ERROR_NULL_POINTER;
if (!jobChain.aligned())
return CELL_SPURS_JOB_ERROR_ALIGN;
if (jobChain->workloadId >= CELL_SPURS_MAX_WORKLOAD2)
return CELL_SPURS_JOB_ERROR_INVAL;
jobChain->exceptionEventHandler = vm::null;
jobChain->exceptionEventHandlerArgument = vm::null;
return CELL_OK;
}
s32 cellSpursGetJobChainInfo()
s32 cellSpursGetJobChainInfo(ppu_thread& ppu, vm::ptr<CellSpursJobChain> jobChain, vm::ptr<CellSpursJobChainInfo> info)
{
UNIMPLEMENTED_FUNC(cellSpurs);
cellSpurs.trace("cellSpursGetJobChainInfo(jobChain=*0x%x, info=*0x%x)", jobChain, info);
if (!jobChain || !info)
return CELL_SPURS_JOB_ERROR_NULL_POINTER;
if (!jobChain.aligned())
return CELL_SPURS_JOB_ERROR_ALIGN;
const u32 wid = jobChain->workloadId;
if (wid >= CELL_SPURS_MAX_WORKLOAD2)
return CELL_SPURS_JOB_ERROR_INVAL;
vm::var<CellSpursWorkloadInfo> wklInfo;
if (auto err = ppu_execute<&cellSpursGetWorkloadInfo>(ppu, +jobChain->spurs, wid, +wklInfo))
{
if (err + 0u == CELL_SPURS_POLICY_MODULE_ERROR_SRCH)
{
return CELL_SPURS_JOB_ERROR_INVAL;
}
return err;
}
CellSpursJobChain data;
// Read the commands queue atomically
if (!do_atomic_128_load(ppu, jobChain.addr(), &data))
{
return 0;
}
info->linkRegister[0] = +data.linkRegister[0];
info->linkRegister[1] = +data.linkRegister[1];
info->linkRegister[2] = +data.linkRegister[2];
std::memcpy(&info->urgentCommandSlot, &data.urgentCmds, sizeof(info->urgentCommandSlot));
info->programCounter = +data.pc;
info->idWorkload = wid;
info->maxSizeJobDescriptor = (data.val2C & 0x70u) * 8 + 0x100;
info->isHalted.set(data.isHalted); // Boolean truncation (non-zero becomes 1)
info->autoReadyCount.set(data.autoReadyCount);
info->isFixedMemAlloc = !!(data.val2C & 0x80);
info->name = wklInfo->nameInstance;
info->statusCode = jobChain->error;
info->cause = jobChain->cause;
info->exceptionEventHandler = +jobChain->exceptionEventHandler;
info->exceptionEventHandlerArgument = +jobChain->exceptionEventHandlerArgument;
return CELL_OK;
}
s32 cellSpursJobChainGetSpursAddress()
s32 cellSpursJobChainGetSpursAddress(vm::ptr<CellSpursJobChain> jobChain, vm::pptr<CellSpurs> spurs)
{
UNIMPLEMENTED_FUNC(cellSpurs);
cellSpurs.trace("cellSpursJobChainGetSpursAddress(jobChain=*0x%x, spurs=*0x%x)", jobChain, spurs);
if (!jobChain || !spurs)
return CELL_SPURS_JOB_ERROR_NULL_POINTER;
if (!jobChain.aligned())
return CELL_SPURS_JOB_ERROR_ALIGN;
*spurs = +jobChain->spurs;
return CELL_OK;
}
@ -4352,7 +4643,7 @@ s32 cellSpursJobGuardInitialize(vm::ptr<CellSpursJobChain> jobChain, vm::ptr<Cel
if (!jobChain.aligned() || !jobGuard.aligned())
return CELL_SPURS_JOB_ERROR_ALIGN;
if (jobChain->workloadId >= 32)
if (jobChain->workloadId >= CELL_SPURS_MAX_WORKLOAD2)
return CELL_SPURS_JOB_ERROR_INVAL;
std::memset(jobGuard.get_ptr(), 0, jobGuard.size());
@ -4365,27 +4656,70 @@ s32 cellSpursJobGuardInitialize(vm::ptr<CellSpursJobChain> jobChain, vm::ptr<Cel
return CELL_OK;
}
s32 cellSpursJobChainAttributeSetName()
s32 cellSpursJobChainAttributeSetName(vm::ptr<CellSpursJobChainAttribute> attr, vm::cptr<char> name)
{
UNIMPLEMENTED_FUNC(cellSpurs);
cellSpurs.trace("cellSpursJobChainAttributeSetName(attr=*0x%x, name=*0x%x %s)", attr, name, name);
if (!attr || !name)
return CELL_SPURS_JOB_ERROR_NULL_POINTER;
if (!attr.aligned())
return CELL_SPURS_JOB_ERROR_ALIGN;
attr->name = name;
return CELL_OK;
}
s32 cellSpursShutdownJobChain()
s32 cellSpursShutdownJobChain(ppu_thread& ppu,vm::ptr<CellSpursJobChain> jobChain)
{
UNIMPLEMENTED_FUNC(cellSpurs);
cellSpurs.trace("cellSpursShutdownJobChain(jobChain=*0x%x)", jobChain);
if (!jobChain)
return CELL_SPURS_JOB_ERROR_NULL_POINTER;
if (!jobChain.aligned())
return CELL_SPURS_JOB_ERROR_ALIGN;
const u32 wid = jobChain->workloadId;
if (wid >= CELL_SPURS_MAX_WORKLOAD2)
return CELL_SPURS_JOB_ERROR_INVAL;
const auto err = ppu_execute<&cellSpursShutdownWorkload>(ppu, +jobChain->spurs, wid);
if (err + 0u == CELL_SPURS_POLICY_MODULE_ERROR_STAT)
{
return CELL_SPURS_JOB_ERROR_STAT;
}
return err;
}
s32 cellSpursJobChainAttributeSetHaltOnError(vm::ptr<CellSpursJobChainAttribute> attr)
{
cellSpurs.trace("cellSpursJobChainAttributeSetHaltOnError(attr=*0x%x)", attr);
if (!attr)
return CELL_SPURS_JOB_ERROR_NULL_POINTER;
if (!attr.aligned())
return CELL_SPURS_JOB_ERROR_ALIGN;
attr->haltOnError = true;
return CELL_OK;
}
s32 cellSpursJobChainAttributeSetHaltOnError()
s32 cellSpursJobChainAttributeSetJobTypeMemoryCheck(vm::ptr<CellSpursJobChainAttribute> attr)
{
UNIMPLEMENTED_FUNC(cellSpurs);
return CELL_OK;
}
cellSpurs.trace("cellSpursJobChainAttributeSetJobTypeMemoryCheck(attr=*0x%x)", attr);
s32 cellSpursJobChainAttributeSetJobTypeMemoryCheck()
{
UNIMPLEMENTED_FUNC(cellSpurs);
if (!attr)
return CELL_SPURS_JOB_ERROR_NULL_POINTER;
if (!attr.aligned())
return CELL_SPURS_JOB_ERROR_ALIGN;
attr->jobMemoryCheck = true;
return CELL_OK;
}
@ -4470,7 +4804,7 @@ s32 cellSpursRunJobChain(ppu_thread& ppu, vm::ptr<CellSpursJobChain> jobChain)
const u32 wid = jobChain->workloadId;
if (wid >= 32u)
if (wid >= CELL_SPURS_MAX_WORKLOAD2)
return CELL_SPURS_JOB_ERROR_INVAL;
if (jobChain->val2D <= 1)
@ -4489,10 +4823,19 @@ s32 cellSpursRunJobChain(ppu_thread& ppu, vm::ptr<CellSpursJobChain> jobChain)
return err;
}
s32 cellSpursJobChainGetError()
s32 cellSpursJobChainGetError(vm::ptr<CellSpursJobChain> jobChain, vm::pptr<void> cause)
{
UNIMPLEMENTED_FUNC(cellSpurs);
return CELL_OK;
cellSpurs.trace("cellSpursJobChainGetError(jobChain=*0x%x, cause=*0x%x)", jobChain, cause);
if (!jobChain)
return CELL_SPURS_JOB_ERROR_NULL_POINTER;
if (!jobChain.aligned())
return CELL_SPURS_JOB_ERROR_ALIGN;
const s32 error = jobChain->error;
*cause = (error ? jobChain->cause : vm::null);
return error;
}
s32 cellSpursGetJobPipelineInfo()
@ -4501,9 +4844,36 @@ s32 cellSpursGetJobPipelineInfo()
return CELL_OK;
}
s32 cellSpursJobSetMaxGrab()
s32 cellSpursJobSetMaxGrab(vm::ptr<CellSpursJobChain> jobChain, u32 maxGrabbedJob)
{
UNIMPLEMENTED_FUNC(cellSpurs);
cellSpurs.trace("cellSpursJobSetMaxGrab(jobChain=*0x%x, maxGrabbedJob=*0x%x)", jobChain, maxGrabbedJob);
if (!jobChain)
return CELL_SPURS_JOB_ERROR_NULL_POINTER;
if (!jobChain.aligned())
return CELL_SPURS_JOB_ERROR_ALIGN;
if (!maxGrabbedJob || maxGrabbedJob > 0x10u)
return CELL_SPURS_JOB_ERROR_INVAL;
const auto spurs = jobChain->spurs;
// All of these are ERROR_STAT checks unexpectedly
if (!spurs || !spurs.aligned())
return CELL_SPURS_JOB_ERROR_STAT;
const u32 wid = jobChain->workloadId;
if (wid >= CELL_SPURS_MAX_WORKLOAD2)
return CELL_SPURS_JOB_ERROR_STAT;
if ((spurs->wklEnabled & (0x80000000u >> wid)) == 0u)
return CELL_SPURS_JOB_ERROR_STAT;
auto [res, rtime] = vm::reservation_lock(jobChain.addr(), 128, vm::dma_lockb);
jobChain->maxGrabbedJob.release(static_cast<u16>(maxGrabbedJob));
res.store(rtime + 128);
return CELL_OK;
}
@ -4520,10 +4890,10 @@ s32 cellSpursAddUrgentCommand(ppu_thread& ppu, vm::ptr<CellSpursJobChain> jobCha
if (!jobChain)
return CELL_SPURS_JOB_ERROR_NULL_POINTER;
if (!jobChain.aligned(128))
if (!jobChain.aligned())
return CELL_SPURS_JOB_ERROR_ALIGN;
if (jobChain->workloadId >= 32)
if (jobChain->workloadId >= CELL_SPURS_MAX_WORKLOAD2)
return CELL_SPURS_JOB_ERROR_INVAL;
for (u32 i = 0;;)
@ -4570,10 +4940,17 @@ s32 cellSpursAddUrgentCommand(ppu_thread& ppu, vm::ptr<CellSpursJobChain> jobCha
return CELL_OK;
}
s32 cellSpursAddUrgentCall()
s32 cellSpursAddUrgentCall(ppu_thread& ppu, vm::ptr<CellSpursJobChain> jobChain, vm::ptr<u64> commandList)
{
UNIMPLEMENTED_FUNC(cellSpurs);
return CELL_OK;
cellSpurs.trace("cellSpursAddUrgentCall(jobChain=*0x%x, commandList=*0x%x)", jobChain, commandList);
if (!commandList)
return CELL_SPURS_JOB_ERROR_NULL_POINTER;
if (!commandList.aligned())
return CELL_SPURS_JOB_ERROR_ALIGN;
return cellSpursAddUrgentCommand(ppu, jobChain, commandList.addr() | CELL_SPURS_JOB_OPCODE_CALL);
}
s32 cellSpursBarrierInitialize(vm::ptr<CellSpursTaskset> taskset, vm::ptr<CellSpursBarrier> barrier, u32 total)
@ -4589,7 +4966,7 @@ s32 cellSpursBarrierInitialize(vm::ptr<CellSpursTaskset> taskset, vm::ptr<CellSp
if (!total || total > 128u)
return CELL_SPURS_TASK_ERROR_INVAL;
if (taskset->wid >= 32u)
if (taskset->wid >= CELL_SPURS_MAX_WORKLOAD2)
return CELL_SPURS_TASK_ERROR_INVAL;
std::memset(barrier.get_ptr(), 0, barrier.size());

View File

@ -295,25 +295,25 @@ CHECK_SIZE_ALIGN(CellSpursWorkloadFlag, 16, 16);
struct CellSpursInfo
{
be_t<s32> nSpus;
be_t<s32> spuThreadGroupPriority;
be_t<s32> ppuThreadPriority;
bool exitIfNoWork;
bool spurs2;
u8 padding24[2];
vm::bptr<void> traceBuffer;
be_t<u32> padding32;
be_t<u64> traceBufferSize;
be_t<u32> traceMode;
be_t<u32> spuThreadGroup;
be_t<u32> spuThreads[8];
be_t<u64> spursHandlerThread0;
be_t<u64> spursHandlerThread1;
char namePrefix[16];
be_t<u32> namePrefixLength;
be_t<u32> deadlineMissCounter;
be_t<u32> deadlineMeetCounter;
u8 padding[164];
be_t<s32> nSpus; // 0x00
be_t<s32> spuThreadGroupPriority; // 0x04
be_t<s32> ppuThreadPriority; // 0x08
b8 exitIfNoWork; // 0x0C
b8 spurs2; // 0x0D
u8 padding24[2]; // 0x0E
vm::bptr<void> traceBuffer; // 0x10
be_t<u32> padding32; // 0x14
be_t<u64> traceBufferSize; // 0x18
be_t<u32> traceMode; // 0x20
be_t<u32> spuThreadGroup; // 0x24
be_t<u32> spuThreads[8]; // 0x28
be_t<u64> spursHandlerThread0; // 0x48
be_t<u64> spursHandlerThread1; // 0x50
char namePrefix[16]; // 0x58
be_t<u32> namePrefixLength; // 0x68
be_t<u32> deadlineMissCounter; // 0x6C
be_t<u32> deadlineMeetCounter; // 0x70
u8 padding[164]; // 0x74
};
CHECK_SIZE(CellSpursInfo, 280);
@ -325,7 +325,7 @@ struct alignas(8) CellSpursAttribute
be_t<u32> nSpus; // 0x8
be_t<s32> spuPriority; // 0xC
be_t<s32> ppuPriority; // 0x10
bool exitIfNoWork; // 0x14
b8 exitIfNoWork; // 0x14
char prefix[15]; // 0x15 (not a NTS)
be_t<u32> prefixSize; // 0x24
be_t<u32> flags; // 0x28 (SpursAttrFlags)
@ -433,21 +433,97 @@ struct alignas(16) CellSpursTracePacket
CHECK_SIZE_ALIGN(CellSpursTracePacket, 16, 16);
struct CellSpursJobChain;
struct CellSpursExceptionInfo;
using CellSpursJobChainExceptionEventHandler = void(vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursJobChain> jobChain, vm::cptr<CellSpursExceptionInfo> info
, vm::cptr<void> eaJobBinary, u32 lsAddrJobBinary, vm::ptr<void> arg);
struct alignas(128) CellSpursJobChain
{
u8 unk0[0x24]; // 0x0
u8 val24; // 0x24
u8 unk1[0x7]; // 0x25
u8 val2C; // 0x2C
u8 val2D; // 0x2D
u8 val2E; // 0x2E
u8 val2F; // 0x2F
atomic_be_t<u64> urgentCmds[4]; // 0x30
u8 unk2[0x24]; // 0x50
be_t<u32> workloadId; // 0x74
be_t<u32> reserved; // 0x78
vm::bptr<CellSpurs> spurs; // 0x7C
u8 unk3[0x90]; // 0x80
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
atomic_be_t<u64> urgentCmds[4]; // 0x30
u8 unk2[0x22]; // 0x50
atomic_be_t<u16> maxGrabbedJob; // 0x72
be_t<u32> workloadId; // 0x74
vm::bptr<CellSpurs, u64> spurs; // 0x78
be_t<s32> error; // 0x80
be_t<u32> unk3; // 0x84
vm::bptr<void, u64> cause; // 0x88
u8 unk4[0x8]; // 0x90
vm::bptr<CellSpursJobChainExceptionEventHandler, u64> exceptionEventHandler; // 0x98
vm::bptr<void, u64> exceptionEventHandlerArgument; // 0xA0
u8 unk5[0x100 - 0xA8];
};
struct CellSpursJobChainInfo
{
be_t<u64> urgentCommandSlot[4]; // 0x00
vm::bcptr<u64> programCounter; // 0x20
vm::bcptr<u64> linkRegister[3]; // 0x24
vm::bcptr<void> cause; // 0x30
be_t<u32> statusCode; // 0x34
be_t<u32> maxSizeJobDescriptor; // 0x38
be_t<u32> idWorkload; // 0x3C
b8 autoReadyCount; // 0x40
b8 isHalted; // 0x41
b8 isFixedMemAlloc; // 0x42
u8 padding8; // 0x43
u16 maxGrabbedJob; // 0x44
u16 padding16; // 0x46
vm::bcptr<char> name; // 0x48
vm::bptr<CellSpursJobChainExceptionEventHandler> exceptionEventHandler; // 0x4C
vm::bptr<void> exceptionEventHandlerArgument; // 0x50
};
struct alignas(8) CellSpursJobChainAttribute
{
be_t<u32> jmVer; // 0x00
be_t<u32> sdkVer; // 0x04
vm::bcptr<u64> jobChainEntry; // 0x08
be_t<u16> sizeJobDescriptor; // 0x0C
be_t<u32> maxGrabbedJob; // 0x0E
u8 priorities[8]; // 0x10
be_t<u32> maxContention; // 0x18
b8 autoSpuCount; // 0x1C
u8 padding[3]; // 0x1D
be_t<u32> tag1; // 0x20
be_t<u32> tag2; // 0x24
b8 isFixedMemAlloc; // 0x28
u8 padding1[3]; // 0x29
be_t<u32> maxSizeJobDescriptor; // 0x2C
be_t<u32> initSpuCount; // 0x30
be_t<u32> haltOnError; // 0x34
vm::bcptr<char> name; // 0x38
b8 jobMemoryCheck; // 0x3C
};
struct CellSpursWorkloadInfo
{
be_t<u64> data; // 0x00
u8 priority[8]; // 0x08
vm::bcptr<void> policyModule; // 0x10
be_t<u32> sizePolicyModule; // 0x14
vm::bcptr<char> nameClass; // 0x18
vm::bcptr<char> nameInstance; // 0x1C
u8 contention; // 0x20
u8 minContention; // 0x21
u8 maxContention; // 0x22
u8 readyCount; // 0x23
u8 idleSpuRequest; // 0x24
u8 hasSignal; // 0x25
u8 padding[2]; // 0x26
vm::bptr<void> shutdownCompletionEventHook; // 0x28
vm::bptr<void> shutdownCompletionEventHookArgument; // 0x2C
};
struct alignas(128) CellSpursJobGuard
@ -630,6 +706,18 @@ struct alignas(128) CellSpurs
}
}
u8 wklStatus(u32 wid)
{
if (wid & 0x10)
{
return atomic_storage<u8>::load(wklStatus2[wid & 0xf]);
}
else
{
return atomic_storage<u8>::load(wklStatus1[wid & 0xf]);
}
}
atomic_t<u8>& wklEvent(u32 wid)
{
if (wid & 0x10)