SPURS: System service workload - initial commit

This commit is contained in:
S Gopal Rajagopal 2015-01-01 01:51:22 +05:30
parent 52b342464b
commit 6664116042
5 changed files with 561 additions and 103 deletions

View file

@ -101,7 +101,7 @@ s64 spursInit(
}
spurs->m.xCC = 0;
spurs->m.xCD = 0;
spurs->m.xCE = 0;
spurs->m.sysSrvMsgUpdateTrace = 0;
for (u32 i = 0; i < 8; i++)
{
spurs->m.xC0[i] = -1;
@ -225,8 +225,7 @@ s64 spursInit(
// the system service message bit for this SPU is set.
if (mgmt->spurs->m.sysSrvMessage.read_relaxed() & (1 << mgmt->spuNum))
{
// Not sure what this does. Possibly Mark the SPU as in use.
mgmt->x1EB = 0;
mgmt->spuIdling = 0;
if (!isPoll || mgmt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID)
{
// Clear the message bit
@ -239,7 +238,7 @@ s64 spursInit(
u16 maxWeight = 0;
for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++)
{
u8 x1EC = mgmt->x1EC & (0x8000 >> i);
u8 runnable = mgmt->wklRunnable1 & (0x8000 >> i);
u8 wklSignal = mgmt->spurs->m.wklSignal1.read_relaxed() & (0x8000 >> i);
u8 wklFlag = mgmt->spurs->m.wklFlag.flag.read_relaxed() == 0 ? mgmt->spurs->m.wklFlagReceiver.read_relaxed() == i ? 1 : 0 : 0;
u8 readyCount = mgmt->spurs->m.wklReadyCount1[i].read_relaxed() > CELL_SPURS_MAX_SPU ? CELL_SPURS_MAX_SPU : mgmt->spurs->m.wklReadyCount1[i].read_relaxed();
@ -249,11 +248,11 @@ s64 spursInit(
// For a workload to be considered for scheduling:
// 1. Its priority must not be 0
// 2. The number of SPUs used by it must be less than the max contention for that workload
// 3. The bit in 0x1EC for the wokload must be set
// 3. The workload should be in runnable state
// 4. The number of SPUs allocated to it must be less than the number of SPUs requested (i.e. readyCount)
// OR the workload must be signalled
// OR the workload flag is 0 and the workload is configured as the wokload flag receiver
if (x1EC && mgmt->priority[i] != 0 && mgmt->spurs->m.wklMaxContention[i].read_relaxed() > contention[i])
if (runnable && mgmt->priority[i] != 0 && mgmt->spurs->m.wklMaxContention[i].read_relaxed() > contention[i])
{
if (wklFlag || wklSignal || (readyCount != 0 && requestCount > contention[i]))
{
@ -287,7 +286,7 @@ s64 spursInit(
}
// Not sure what this does. Possibly mark the SPU as idle/in use.
mgmt->x1EB = wklSelectedId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID ? 1 : 0;
mgmt->spuIdling = wklSelectedId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID ? 1 : 0;
if (!isPoll || wklSelectedId == mgmt->wklCurrentId)
{
@ -391,7 +390,7 @@ s64 spursInit(
if (mgmt->spurs->m.sysSrvMessage.read_relaxed() & (1 << mgmt->spuNum))
{
// Not sure what this does. Possibly Mark the SPU as in use.
mgmt->x1EB = 0;
mgmt->spuIdling = 0;
if (!isPoll || mgmt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID)
{
// Clear the message bit
@ -405,7 +404,7 @@ s64 spursInit(
for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD2; i++)
{
auto j = i & 0x0F;
u8 x1ECx1EE = i < CELL_SPURS_MAX_WORKLOAD ? mgmt->x1EC & (0x8000 >> j) : mgmt->x1EE & (0x8000 >> j);
u8 runnable = i < CELL_SPURS_MAX_WORKLOAD ? mgmt->wklRunnable1 & (0x8000 >> j) : mgmt->wklRunnable2 & (0x8000 >> j);
u8 priority = i < CELL_SPURS_MAX_WORKLOAD ? mgmt->priority[j] & 0x0F : mgmt->priority[j] >> 4;
u8 maxContention = i < CELL_SPURS_MAX_WORKLOAD ? mgmt->spurs->m.wklMaxContention[j].read_relaxed() & 0x0F : mgmt->spurs->m.wklMaxContention[j].read_relaxed() >> 4;
u8 wklSignal = i < CELL_SPURS_MAX_WORKLOAD ? mgmt->spurs->m.wklSignal1.read_relaxed() & (0x8000 >> j) : mgmt->spurs->m.wklSignal2.read_relaxed() & (0x8000 >> j);
@ -415,11 +414,11 @@ s64 spursInit(
// For a workload to be considered for scheduling:
// 1. Its priority must be greater than 0
// 2. The number of SPUs used by it must be less than the max contention for that workload
// 3. The bit in 0x1EC/0x1EE for the wokload must be set
// 3. The workload should be in runnable state
// 4. The number of SPUs allocated to it must be less than the number of SPUs requested (i.e. readyCount)
// OR the workload must be signalled
// OR the workload flag is 0 and the workload is configured as the wokload receiver
if (x1ECx1EE && priority > 0 && maxContention > contention[i])
if (runnable && priority > 0 && maxContention > contention[i])
{
if (wklFlag || wklSignal || readyCount > contention[i])
{
@ -445,7 +444,7 @@ s64 spursInit(
}
// Not sure what this does. Possibly mark the SPU as idle/in use.
mgmt->x1EB = wklSelectedId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID ? 1 : 0;
mgmt->spuIdling = wklSelectedId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID ? 1 : 0;
if (!isPoll || wklSelectedId == mgmt->wklCurrentId)
{
@ -653,7 +652,7 @@ s64 spursInit(
bool do_break = false;
for (u32 i = 0; i < 16; i++)
{
if (spurs->m.wklStat1[i].read_relaxed() == 2 &&
if (spurs->m.wklState1[i].read_relaxed() == 2 &&
spurs->m.wklInfo1[i].priority.ToBE() != 0 &&
spurs->m.wklMaxContention[i].read_relaxed() & 0xf
)
@ -671,7 +670,7 @@ s64 spursInit(
}
if (spurs->m.flags1 & SF1_32_WORKLOADS) for (u32 i = 0; i < 16; i++)
{
if (spurs->m.wklStat2[i].read_relaxed() == 2 &&
if (spurs->m.wklState2[i].read_relaxed() == 2 &&
spurs->m.wklInfo2[i].priority.ToBE() != 0 &&
spurs->m.wklMaxContention[i].read_relaxed() & 0xf0
)
@ -756,7 +755,7 @@ s64 spursInit(
}
}
spurs->m.unk22 = 0;
spurs->m.traceBuffer = 0;
// can also use cellLibprof if available (omitted)
// some unknown subroutine
@ -1439,13 +1438,16 @@ s32 spursAddWorkload(
{
assert((spurs->m.wklCurrentContention[wnum] & 0xf) == 0);
assert((spurs->m.wklPendingContention[wnum] & 0xf) == 0);
spurs->m.wklStat1[wnum].write_relaxed(1);
spurs->m.wklD1[wnum] = 0;
spurs->m.wklE1[wnum] = 0;
spurs->m.wklState1[wnum].write_relaxed(1);
spurs->m.wklStatus1[wnum] = 0;
spurs->m.wklEvent1[wnum] = 0;
spurs->m.wklInfo1[wnum].addr = pm;
spurs->m.wklInfo1[wnum].arg = data;
spurs->m.wklInfo1[wnum].size = size;
spurs->m.wklInfo1[wnum].priority = *(be_t<u64>*)priorityTable;
for (u32 i = 0; i < 8; i++)
{
spurs->m.wklInfo1[wnum].priority[i] = priorityTable[i];
}
spurs->m.wklH1[wnum].nameClass = nameClass;
spurs->m.wklH1[wnum].nameInstance = nameInstance;
memset(spurs->m.wklF1[wnum].unk0, 0, 0x20); // clear struct preserving semaphore id
@ -1454,7 +1456,7 @@ s32 spursAddWorkload(
{
spurs->m.wklF1[wnum].hook = hook;
spurs->m.wklF1[wnum].hookArg = hookArg;
spurs->m.wklE1[wnum] |= 2;
spurs->m.wklEvent1[wnum] |= 2;
}
if ((spurs->m.flags1 & SF1_32_WORKLOADS) == 0)
{
@ -1467,13 +1469,16 @@ s32 spursAddWorkload(
{
assert((spurs->m.wklCurrentContention[index] & 0xf0) == 0);
assert((spurs->m.wklPendingContention[index] & 0xf0) == 0);
spurs->m.wklStat2[index].write_relaxed(1);
spurs->m.wklD2[index] = 0;
spurs->m.wklE2[index] = 0;
spurs->m.wklState2[index].write_relaxed(1);
spurs->m.wklStatus2[index] = 0;
spurs->m.wklEvent2[index] = 0;
spurs->m.wklInfo2[index].addr = pm;
spurs->m.wklInfo2[index].arg = data;
spurs->m.wklInfo2[index].size = size;
spurs->m.wklInfo2[index].priority = *(be_t<u64>*)priorityTable;
for (u32 i = 0; i < 8; i++)
{
spurs->m.wklInfo2[index].priority[i] = priorityTable[i];
}
spurs->m.wklH2[index].nameClass = nameClass;
spurs->m.wklH2[index].nameInstance = nameInstance;
memset(spurs->m.wklF2[index].unk0, 0, 0x20); // clear struct preserving semaphore id
@ -1482,7 +1487,7 @@ s32 spursAddWorkload(
{
spurs->m.wklF2[index].hook = hook;
spurs->m.wklF2[index].hookArg = hookArg;
spurs->m.wklE2[index] |= 2;
spurs->m.wklEvent2[index] |= 2;
}
spurs->m.wklIdleSpuCountOrReadyCount2[wnum].write_relaxed(0);
}
@ -1539,8 +1544,8 @@ s32 spursAddWorkload(
});
assert(res_wkl <= 31);
spurs->wklStat(wnum).exchange(2);
spurs->m.xBD.exchange(0xff);
spurs->wklState(wnum).exchange(2);
spurs->m.sysSrvMsgUpdateWorkload.exchange(0xff);
spurs->m.sysSrvMessage.exchange(0xff);
return CELL_OK;
}
@ -1871,7 +1876,7 @@ s64 cellSpursReadyCountStore(vm::ptr<CellSpurs> spurs, u32 wid, u32 value)
{
return CELL_SPURS_POLICY_MODULE_ERROR_SRCH;
}
if (spurs->m.exception.ToBE() || spurs->wklStat(wid).read_relaxed() != 2)
if (spurs->m.exception.ToBE() || spurs->wklState(wid).read_relaxed() != 2)
{
return CELL_SPURS_POLICY_MODULE_ERROR_STAT;
}
@ -3364,6 +3369,190 @@ s64 cellSpursSemaphoreGetTasksetAddress()
#endif
}
bool spursIsLibProfLoaded()
{
return false;
}
void spursTraceStatusUpdate(vm::ptr<CellSpurs> spurs)
{
LV2_LOCK(0);
if (spurs->m.xCC != 0)
{
spurs->m.xCD = 1;
spurs->m.sysSrvMsgUpdateTrace = (1 << spurs->m.nSpus) - 1;
spurs->m.sysSrvMessage.write_relaxed(0xFF);
sys_semaphore_wait(spurs->m.semPrv, 0);
}
}
s64 spursTraceInitialize(vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTraceInfo> buffer, u32 size, u32 mode, u32 updateStatus)
{
if (!spurs || !buffer)
{
return CELL_SPURS_CORE_ERROR_NULL_POINTER;
}
if (spurs.addr() % CellSpurs::align || buffer.addr() % CellSpursTraceInfo::align)
{
return CELL_SPURS_CORE_ERROR_ALIGN;
}
if (size < CellSpursTraceInfo::size || mode & ~(CELL_SPURS_TRACE_MODE_FLAG_MASK))
{
return CELL_SPURS_CORE_ERROR_INVAL;
}
if (spurs->m.traceBuffer != 0)
{
return CELL_SPURS_CORE_ERROR_STAT;
}
spurs->m.traceDataSize = size - CellSpursTraceInfo::size;
for (u32 i = 0; i < 8; i++)
{
buffer->spu_thread[i] = spurs->m.spus[i];
buffer->count[i] = 0;
}
buffer->spu_thread_grp = spurs->m.spuTG;
buffer->nspu = spurs->m.nSpus;
spurs->m.traceBuffer = buffer.addr() | (mode & CELL_SPURS_TRACE_MODE_FLAG_WRAP_BUFFER ? 1 : 0);
spurs->m.traceMode = mode;
u32 spuTraceDataCount = (spurs->m.traceDataSize / CellSpursTracePacket::size) / spurs->m.nSpus;
for (u32 i = 0, j = 8; i < 6; i++)
{
spurs->m.x908[i] = j;
j += spuTraceDataCount;
}
spurs->m.sysSrvTraceControl = 0;
if (updateStatus)
{
spursTraceStatusUpdate(spurs);
}
return CELL_OK;
}
s64 cellSpursTraceInitialize(vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTraceInfo> buffer, u32 size, u32 mode)
{
if (spursIsLibProfLoaded())
{
return CELL_SPURS_CORE_ERROR_STAT;
}
return spursTraceInitialize(spurs, buffer, size, mode, 1);
}
s64 spursTraceStart(vm::ptr<CellSpurs> spurs, u32 updateStatus)
{
if (!spurs)
{
return CELL_SPURS_CORE_ERROR_NULL_POINTER;
}
if (spurs.addr() % CellSpurs::align)
{
return CELL_SPURS_CORE_ERROR_ALIGN;
}
if (!spurs->m.traceBuffer)
{
return CELL_SPURS_CORE_ERROR_STAT;
}
spurs->m.sysSrvTraceControl = 1;
if (updateStatus)
{
spursTraceStatusUpdate(spurs);
}
return CELL_OK;
}
s64 cellSpursTraceStart(vm::ptr<CellSpurs> spurs)
{
if (!spurs)
{
return CELL_SPURS_CORE_ERROR_NULL_POINTER;
}
if (spurs.addr() % CellSpurs::align)
{
return CELL_SPURS_CORE_ERROR_ALIGN;
}
return spursTraceStart(spurs, spurs->m.traceMode & CELL_SPURS_TRACE_MODE_FLAG_SYNCHRONOUS_START_STOP);
}
s64 spursTraceStop(vm::ptr<CellSpurs> spurs, u32 updateStatus)
{
if (!spurs)
{
return CELL_SPURS_CORE_ERROR_NULL_POINTER;
}
if (spurs.addr() % CellSpurs::align)
{
return CELL_SPURS_CORE_ERROR_ALIGN;
}
if (!spurs->m.traceBuffer)
{
return CELL_SPURS_CORE_ERROR_STAT;
}
spurs->m.sysSrvTraceControl = 2;
if (updateStatus)
{
spursTraceStatusUpdate(spurs);
}
return CELL_OK;
}
s64 cellSpursTraceStop(vm::ptr<CellSpurs> spurs)
{
if (!spurs)
{
return CELL_SPURS_CORE_ERROR_NULL_POINTER;
}
if (spurs.addr() % CellSpurs::align)
{
return CELL_SPURS_CORE_ERROR_ALIGN;
}
return spursTraceStop(spurs, spurs->m.traceMode & CELL_SPURS_TRACE_MODE_FLAG_SYNCHRONOUS_START_STOP);
}
s64 cellSpursTraceFinalize(vm::ptr<CellSpurs> spurs)
{
if (!spurs)
{
return CELL_SPURS_CORE_ERROR_NULL_POINTER;
}
if (spurs.addr() % CellSpurs::align)
{
return CELL_SPURS_CORE_ERROR_ALIGN;
}
if (!spurs->m.traceBuffer)
{
return CELL_SPURS_CORE_ERROR_STAT;
}
spurs->m.sysSrvTraceControl = 0;
spurs->m.traceMode = 0;
spurs->m.traceBuffer = 0;
spursTraceStatusUpdate(spurs);
return CELL_OK;
}
void cellSpurs_init(Module *pxThis)
{
cellSpurs = pxThis;
@ -3521,5 +3710,11 @@ void cellSpurs_init(Module *pxThis)
REG_FUNC(cellSpurs, _cellSpursSemaphoreInitialize);
REG_FUNC(cellSpurs, cellSpursSemaphoreGetTasksetAddress);
// Trace
REG_FUNC(cellSpurs, cellSpursTraceInitialize);
REG_FUNC(cellSpurs, cellSpursTraceStart);
REG_FUNC(cellSpurs, cellSpursTraceStop);
REG_FUNC(cellSpurs, cellSpursTraceFinalize);
// TODO: some trace funcs
}

View file

@ -114,34 +114,6 @@ enum RangeofEventQueuePortNumbers
CELL_SPURS_DYNAMIC_PORT_RANGE_BOTTOM = 63,
};
enum SPURSTraceTypes
{
CELL_SPURS_TRACE_TAG_LOAD = 0x2a,
CELL_SPURS_TRACE_TAG_MAP = 0x2b,
CELL_SPURS_TRACE_TAG_START = 0x2c,
CELL_SPURS_TRACE_TAG_STOP = 0x2d,
CELL_SPURS_TRACE_TAG_USER = 0x2e,
CELL_SPURS_TRACE_TAG_GUID = 0x2f,
};
// SPURS task defines.
enum TaskConstants
{
CELL_SPURS_MAX_TASK = 128,
CELL_SPURS_TASK_TOP = 0x3000,
CELL_SPURS_TASK_BOTTOM = 0x40000,
CELL_SPURS_MAX_TASK_NAME_LENGTH = 32,
CELL_SPURS_TASK_ATTRIBUTE_REVISION = 1,
CELL_SPURS_TASKSET_ATTRIBUTE_REVISION = 1,
CELL_SPURS_TASK_EXECUTION_CONTEXT_SIZE = 1024,
};
class SPURSManager;
class SPURSManagerEventFlag;
class SPURSManagerTaskset;
struct CellSpurs;
enum SpursAttrFlags : u32
{
SAF_NONE = 0x0,
@ -168,6 +140,68 @@ enum SpursFlags1 : u8
SF1_EXIT_IF_NO_WORK = 0x80,
};
enum SpursWorkloadConstants
{
// Workload states
SPURS_WKL_STATE_NON_EXISTENT = 0,
SPURS_WKL_STATE_PREPARING = 1,
SPURS_WKL_STATE_RUNNABLE = 2,
SPURS_WKL_STATE_SHUTTING_DOWN = 3,
SPURS_WKL_STATE_REMOVABLE = 4,
SPURS_WKL_STATE_INVALID = 5,
};
enum CellSpursModulePollStatus
{
CELL_SPURS_MODULE_POLL_STATUS_READYCOUNT = 1,
CELL_SPURS_MODULE_POLL_STATUS_SIGNAL = 2,
CELL_SPURS_MODULE_POLL_STATUS_FLAG = 4
};
enum SpursTraceConstants
{
// Trace tag types
CELL_SPURS_TRACE_TAG_KERNEL = 0x20,
CELL_SPURS_TRACE_TAG_SERVICE = 0x21,
CELL_SPURS_TRACE_TAG_TASK = 0x22,
CELL_SPURS_TRACE_TAG_JOB = 0x23,
CELL_SPURS_TRACE_TAG_OVIS = 0x24,
CELL_SPURS_TRACE_TAG_LOAD = 0x2a,
CELL_SPURS_TRACE_TAG_MAP = 0x2b,
CELL_SPURS_TRACE_TAG_START = 0x2c,
CELL_SPURS_TRACE_TAG_STOP = 0x2d,
CELL_SPURS_TRACE_TAG_USER = 0x2e,
CELL_SPURS_TRACE_TAG_GUID = 0x2f,
// Service incident
CELL_SPURS_TRACE_SERVICE_INIT = 0x01,
CELL_SPURS_TRACE_SERVICE_WAIT = 0x02,
CELL_SPURS_TRACE_SERVICE_EXIT = 0x03,
// Trace mode flags
CELL_SPURS_TRACE_MODE_FLAG_WRAP_BUFFER = 0x1,
CELL_SPURS_TRACE_MODE_FLAG_SYNCHRONOUS_START_STOP = 0x2,
CELL_SPURS_TRACE_MODE_FLAG_MASK = 0x3,
};
// SPURS task constants
enum SpursTaskConstants
{
CELL_SPURS_MAX_TASK = 128,
CELL_SPURS_TASK_TOP = 0x3000,
CELL_SPURS_TASK_BOTTOM = 0x40000,
CELL_SPURS_MAX_TASK_NAME_LENGTH = 32,
CELL_SPURS_TASK_ATTRIBUTE_REVISION = 1,
CELL_SPURS_TASKSET_ATTRIBUTE_REVISION = 1,
CELL_SPURS_TASK_EXECUTION_CONTEXT_SIZE = 1024,
};
class SPURSManager;
class SPURSManagerEventFlag;
class SPURSManagerTaskset;
struct CellSpurs;
struct CellSpursAttribute
{
static const uint align = 8;
@ -215,12 +249,6 @@ struct CellSpursWorkloadFlag
typedef void(*CellSpursShutdownCompletionEventHook)(vm::ptr<CellSpurs>, u32 wid, vm::ptr<void> arg);
enum CellSpursModulePollStatus {
CELL_SPURS_MODULE_POLL_STATUS_READYCOUNT = 1,
CELL_SPURS_MODULE_POLL_STATUS_SIGNAL = 2,
CELL_SPURS_MODULE_POLL_STATUS_FLAG = 4
};
// Core CellSpurs structures
struct CellSpurs
{
@ -259,7 +287,7 @@ struct CellSpurs
be_t<u64> arg; // spu argument
be_t<u32> size;
atomic_t<u8> uniqueId; // The unique id is the same for all workloads with the same addr
be_t<u64> priority;
be_t<u8> priority[8];
};
static_assert(sizeof(WorkloadInfo) == 0x20, "Wrong WorkloadInfo size");
@ -294,36 +322,41 @@ struct CellSpurs
CellSpursWorkloadFlag wklFlag; // 0x60
atomic_t<u16> wklSignal1; // 0x70 (bitset for 0..15 wids)
atomic_t<u8> sysSrvMessage; // 0x72
u8 sysSrvIdling; // 0x73
u8 spuIdling; // 0x73
u8 flags1; // 0x74 Type is SpursFlags1
u8 sysSrvTraceControl; // 0x75
u8 nSpus; // 0x76
atomic_t<u8> wklFlagReceiver; // 0x77
atomic_t<u16> wklSignal2; // 0x78 (bitset for 16..32 wids)
u8 x7A[6]; // 0x7A
atomic_t<u8> wklStat1[0x10]; // 0x80 - Workload state (16*u8) - State enum {non_exitent, preparing, runnable, shutting_down, removable, invalid}
u8 wklD1[0x10]; // 0x90 - Workload status (16*u8)
u8 wklE1[0x10]; // 0xA0 - Workload event (16*u8)
atomic_t<u8> wklState1[0x10]; // 0x80 SPURS_WKL_STATE_*
u8 wklStatus1[0x10]; // 0x90
u8 wklEvent1[0x10]; // 0xA0
atomic_t<u32> wklMskA; // 0xB0 - System service - Available workloads (32*u1)
atomic_t<u32> wklMskB; // 0xB4 - System service - Available module id
u8 xB8[5]; // 0xB8 - 0xBC - Syetem service exit barrier
atomic_t<u8> xBD; // 0xBD - System service message - update workload
u8 xBE[2]; // 0xBE - 0xBF - System service message - terminate
atomic_t<u8> sysSrvMsgUpdateWorkload; // 0xBD
u8 xBE[2]; // 0xBE
u8 sysSrvMsgTerminate; // 0xBF
u8 xC0[8]; // 0xC0 - System workload
u8 xC8; // 0xC8 - System service - on spu
u8 sysSrvOnSpu; // 0xC8
u8 spuPort; // 0xC9 - SPU port for system service
u8 xCA; // 0xCA
u8 xCB; // 0xCB
u8 xCC; // 0xCC
u8 xCD; // 0xCD
u8 xCE; // 0xCE - System service message - update trace
u8 sysSrvMsgUpdateTrace; // 0xCE
u8 xCF; // 0xCF
atomic_t<u8> wklStat2[0x10]; // 0xD0 - Workload state (16*u8)
u8 wklD2[0x10]; // 0xE0 - Workload status (16*u8)
u8 wklE2[0x10]; // 0xF0 - Workload event (16*u8)
atomic_t<u8> wklState2[0x10]; // 0xD0 SPURS_WKL_STATE_*
u8 wklStatus2[0x10]; // 0xE0
u8 wklEvent2[0x10]; // 0xF0
_sub_str1 wklF1[0x10]; // 0x100
be_t<u64> unk22; // 0x900 - SPURS trace buffer
u8 unknown7[0x980 - 0x908]; // 0x908 - Per SPU trace info ??? (8*u32) 0x950 - SPURS trace mode (u32)
be_t<u64> traceBuffer; // 0x900
be_t<u32> x908[6]; // 0x908 - Indices to traceData (a guess)
u8 unknown7[0x948 - 0x920]; // 0x920
be_t<u64> traceDataSize; // 0x948
be_t<u32> traceMode; // 0x950
u8 unknown8[0x980 - 0x954]; // 0x954
be_t<u64> semPrv; // 0x980
be_t<u32> unk11; // 0x988
be_t<u32> unk12; // 0x98C
@ -371,15 +404,15 @@ struct CellSpurs
} c;
};
__forceinline atomic_t<u8>& wklStat(const u32 wid)
__forceinline atomic_t<u8>& wklState(const u32 wid)
{
if (wid & 0x10)
{
return m.wklStat2[wid & 0xf];
return m.wklState2[wid & 0xf];
}
else
{
return m.wklStat1[wid & 0xf];
return m.wklState1[wid & 0xf];
}
}
@ -526,25 +559,21 @@ struct CellSpursExceptionInfo
struct CellSpursTraceInfo
{
be_t<u32> spu_thread[8];
be_t<u32> count[8];
be_t<u32> spu_thread_grp;
be_t<u32> nspu;
//u8 padding[];
};
static const u32 size = 0x80;
static const u32 align = 16;
struct CellTraceHeader
{
u8 tag;
u8 length;
u8 cpu;
u8 thread;
be_t<u32> time;
be_t<u32> spu_thread[8]; // 0x00
be_t<u32> count[8]; // 0x20
be_t<u32> spu_thread_grp; // 0x40
be_t<u32> nspu; // 0x44
//u8 padding[];
};
struct CellSpursTracePacket
{
struct header_struct
static const u32 size = 16;
struct
{
u8 tag;
u8 length;
@ -553,23 +582,29 @@ struct CellSpursTracePacket
be_t<u32> time;
} header;
struct data_struct
union
{
struct load_struct
struct
{
be_t<u32> incident;
be_t<u32> reserved;
} service;
struct
{
be_t<u32> ea;
be_t<u16> ls;
be_t<u16> size;
} load;
struct map_struct
struct
{
be_t<u32> offset;
be_t<u16> ls;
be_t<u16> size;
} map;
struct start_struct
struct
{
s8 module[4];
be_t<u16> level;
@ -578,6 +613,7 @@ struct CellSpursTracePacket
be_t<u64> user;
be_t<u64> guid;
be_t<u64> stop;
} data;
};
@ -771,12 +807,15 @@ struct SpursKernelMgmtData {
be_t<u32> selectWorkloadAddr; // 0x1E4
u8 x1E8; // 0x1E8
u8 x1E9; // 0x1E9
u8 x1EA; // 0x1EA
u8 x1EB; // 0x1EB - This might be spuIdling
be_t<u16> x1EC; // 0x1EC - This might be wklEnable1
be_t<u16> x1EE; // 0x1EE - This might be wklEnable2
u8 x1F0[0x220 - 0x1F0]; // 0x1F0
u8 wklUniqueId[0x10]; // 0x220
u8 sysSrvInitialised; // 0x1EA
u8 spuIdling; // 0x1EB
be_t<u16> wklRunnable1; // 0x1EC
be_t<u16> wklRunnable2; // 0x1EE
u8 x1F0[0x210 - 0x1F0]; // 0x1F0
be_t<u64> traceBuffer; // 0x210
be_t<u32> traceMsgCount; // 0x218
be_t<u32> traceMaxCount; // 0x21C
u8 wklUniqueId[0x10]; // 0x220
};
s64 spursAttachLv2EventQueue(vm::ptr<CellSpurs> spurs, u32 queue, vm::ptr<u8> port, s32 isDynamic, bool wasCreated);

220
rpcs3/cellSpursSpu.cpp Normal file
View file

@ -0,0 +1,220 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/Cell/SPUThread.h"
#include "Emu/SysCalls/Modules/cellSpurs.h"
/// Output trace information
void cellSpursModulePutTrace(CellSpursTracePacket * packet, unsigned tag) {
// TODO: Implement this
}
/// Check for execution right requests
unsigned cellSpursModulePollStatus(CellSpursModulePollStatus * status) {
// TODO: Implement this
return 0;
}
void spursSysServiceCleanup(SPUThread & spu, SpursKernelMgmtData * mgmt) {
// TODO: Implement this
}
void spursSysServiceUpdateTrace(SPUThread & spu, SpursKernelMgmtData * mgmt, u32 arg2, u32 arg3, u32 arg4) {
// TODO: Implement this
}
void spursSysServiceUpdateEvent(SPUThread & spu, SpursKernelMgmtData * mgmt, u32 wklShutdownMask) {
u32 wklNotifyMask = 0;
for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) {
if (wklShutdownMask & (0x80000000 >> i)) {
mgmt->spurs->m.wklEvent1[i] |= 0x01;
if (mgmt->spurs->m.wklEvent1[i] & 0x02 || mgmt->spurs->m.wklEvent1[i] & 0x10) {
wklNotifyMask |= 0x80000000 >> i;
}
}
}
for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) {
if (wklShutdownMask & (0x8000 >> i)) {
mgmt->spurs->m.wklEvent2[i] |= 0x01;
if (mgmt->spurs->m.wklEvent2[i] & 0x02 || mgmt->spurs->m.wklEvent2[i] & 0x10) {
wklNotifyMask |= 0x8000 >> i;
}
}
}
if (wklNotifyMask) {
// TODO: sys_spu_thread_send_event(mgmt->spurs->m.spuPort, 0, wklNotifyMask);
}
}
/// Update workload information in the LS from main memory
void spursSysServiceUpdateWorkload(SPUThread & spu, SpursKernelMgmtData * mgmt) {
u32 wklShutdownMask = 0;
mgmt->wklRunnable1 = 0;
for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) {
mgmt->priority[i] = mgmt->spurs->m.wklInfo1[i].priority[mgmt->spuNum] == 0 ? 0 : 0x10 - mgmt->spurs->m.wklInfo1[i].priority[mgmt->spuNum];
mgmt->wklUniqueId[i] = mgmt->spurs->m.wklInfo1[i].uniqueId.read_relaxed();
auto wklStatus = mgmt->spurs->m.wklStatus1[i];
if (mgmt->spurs->m.wklState1[i].read_relaxed() == SPURS_WKL_STATE_RUNNABLE) {
mgmt->spurs->m.wklStatus1[i] |= 1 << mgmt->spuNum;
mgmt->wklRunnable1 |= 0x8000 >> i;
} else {
mgmt->spurs->m.wklStatus1[i] &= ~(1 << mgmt->spuNum);
}
if (mgmt->spurs->m.wklState1[i].read_relaxed() == SPURS_WKL_STATE_SHUTTING_DOWN) {
if (((wklStatus & (1 << mgmt->spuNum)) != 0) && ((mgmt->spurs->m.wklStatus1[i] & (1 << mgmt->spuNum)) == 0)) {
mgmt->spurs->m.wklState1[i].write_relaxed(SPURS_WKL_STATE_REMOVABLE);
wklShutdownMask |= 0x80000000 >> i;
}
}
}
if (mgmt->spurs->m.flags1 & SF1_32_WORKLOADS) {
mgmt->wklRunnable2 = 0;
for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) {
if (mgmt->spurs->m.wklInfo2[i].priority[mgmt->spuNum]) {
mgmt->priority[i] |= (0x10 - mgmt->spurs->m.wklInfo2[i].priority[mgmt->spuNum]) << 4;
}
auto wklStatus = mgmt->spurs->m.wklStatus2[i];
if (mgmt->spurs->m.wklState2[i].read_relaxed() == SPURS_WKL_STATE_RUNNABLE) {
mgmt->spurs->m.wklStatus2[i] |= 1 << mgmt->spuNum;
mgmt->wklRunnable2 |= 0x8000 >> i;
} else {
mgmt->spurs->m.wklStatus2[i] &= ~(1 << mgmt->spuNum);
}
if (mgmt->spurs->m.wklState2[i].read_relaxed() == SPURS_WKL_STATE_SHUTTING_DOWN) {
if (((wklStatus & (1 << mgmt->spuNum)) != 0) && ((mgmt->spurs->m.wklStatus2[i] & (1 << mgmt->spuNum)) == 0)) {
mgmt->spurs->m.wklState2[i].write_relaxed(SPURS_WKL_STATE_REMOVABLE);
wklShutdownMask |= 0x8000 >> i;
}
}
}
}
if (wklShutdownMask) {
spursSysServiceUpdateEvent(spu, mgmt, wklShutdownMask);
}
}
/// Process any messages
void spursSysServiceProcessMessages(SPUThread & spu, SpursKernelMgmtData * mgmt) {
if (mgmt->spurs->m.sysSrvMsgUpdateWorkload.read_relaxed() & (1 << mgmt->spuNum)) {
mgmt->spurs->m.sysSrvMsgUpdateWorkload &= ~(1 << mgmt->spuNum);
spursSysServiceUpdateWorkload(spu, mgmt);
}
if (mgmt->spurs->m.sysSrvMsgUpdateTrace & (1 << mgmt->spuNum)) {
spursSysServiceUpdateTrace(spu, mgmt, 1, 0, 0);
}
if (mgmt->spurs->m.sysSrvMsgTerminate & (1 << mgmt->spuNum)) {
mgmt->spurs->m.sysSrvOnSpu &= ~(1 << mgmt->spuNum);
// TODO: Rest of the terminate processing
}
}
void spursSysServiceExitIfRequired() {
// TODO: Implement this
}
/// Main function for the system service workload
void spursSysServiceWorkloadMain(SPUThread & spu, u32 pollStatus) {
auto mgmt = vm::get_ptr<SpursKernelMgmtData>(spu.ls_offset);
if (mgmt->spurs.addr() % CellSpurs::align) {
// TODO: Halt
}
// Initialise the system service if this is the first time its being started on this SPU
if (mgmt->sysSrvInitialised != 0) {
mgmt->sysSrvInitialised = 1;
if (mgmt->spurs->m.sysSrvOnSpu & (1 << mgmt->spuNum)) {
// TODO: Halt
}
mgmt->spurs->m.sysSrvOnSpu |= 1 << mgmt->spuNum;
mgmt->traceBuffer = 0;
mgmt->traceMsgCount = -1;
spursSysServiceUpdateTrace(spu, mgmt, 1, 1, 0);
spursSysServiceCleanup(spu, mgmt);
// Trace - SERVICE: INIT
CellSpursTracePacket pkt;
memset(&pkt, 0, sizeof(pkt));
pkt.header.tag = CELL_SPURS_TRACE_TAG_SERVICE;
pkt.data.service.incident = CELL_SPURS_TRACE_SERVICE_INIT;
cellSpursModulePutTrace(&pkt, mgmt->dmaTagId);
}
// Trace - START: Module='SYS '
CellSpursTracePacket pkt;
memset(&pkt, 0, sizeof(pkt));
pkt.header.tag = CELL_SPURS_TRACE_TAG_START;
memcpy(pkt.data.start.module, "SYS ", 4);
pkt.data.start.level = 1; // Policy module
pkt.data.start.ls = 0xA00 >> 2;
cellSpursModulePutTrace(&pkt, mgmt->dmaTagId);
while (true) {
spursSysServiceProcessMessages(spu, mgmt);
if (cellSpursModulePollStatus(nullptr)) {
// Trace - SERVICE: EXIT
CellSpursTracePacket pkt;
memset(&pkt, 0, sizeof(pkt));
pkt.header.tag = CELL_SPURS_TRACE_TAG_SERVICE;
pkt.data.service.incident = CELL_SPURS_TRACE_SERVICE_EXIT;
cellSpursModulePutTrace(&pkt, mgmt->dmaTagId);
// Trace - STOP: GUID
memset(&pkt, 0, sizeof(pkt));
pkt.header.tag = CELL_SPURS_TRACE_TAG_STOP;
pkt.data.stop = 0; // TODO: Put GUID of the sys service workload here
cellSpursModulePutTrace(&pkt, mgmt->dmaTagId);
break;
}
if (mgmt->spuIdling == 0) {
continue;
}
// Trace - SERVICE: WAIT
CellSpursTracePacket pkt;
memset(&pkt, 0, sizeof(pkt));
pkt.header.tag = CELL_SPURS_TRACE_TAG_SERVICE;
pkt.data.service.incident = CELL_SPURS_TRACE_SERVICE_WAIT;
cellSpursModulePutTrace(&pkt, mgmt->dmaTagId);
spursSysServiceExitIfRequired();
}
}
/// Entry point of the system service workload
void spursSysServiceWorkloadEntry(SPUThread & spu) {
auto mgmt = vm::get_ptr<SpursKernelMgmtData>(spu.ls_offset + spu.GPR[3]._u32[3]);
auto arg = spu.GPR[4]._u64[1];
auto pollStatus = spu.GPR[5]._u32[3];
spu.GPR[1]._u32[3] = 0x3FFD0;
*(vm::ptr<u32>::make(spu.GPR[1]._u32[3])) = 0x3FFF0;
memset(vm::get_ptr<void>(spu.ls_offset + 0x3FFE0), 0, 32);
LV2_LOCK(0);
if (mgmt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) {
spursSysServiceWorkloadMain(spu, pollStatus);
} else {
// TODO: If we reach here it means the current workload was preempted to start the
// system service workload. Need to implement this.
}
// TODO: Ensure that this function always returns to the SPURS kernel
return;
}

View file

@ -54,6 +54,7 @@
<ClCompile Include="..\Utilities\SSemaphore.cpp" />
<ClCompile Include="..\Utilities\StrFmt.cpp" />
<ClCompile Include="..\Utilities\Thread.cpp" />
<ClCompile Include="cellSpursSpu.cpp" />
<ClCompile Include="Crypto\aes.cpp" />
<ClCompile Include="Crypto\ec.cpp" />
<ClCompile Include="Crypto\key_vault.cpp" />

View file

@ -653,6 +653,9 @@
<ClCompile Include="Emu\ARMv7\Modules\sceLibm.cpp">
<Filter>Emu\CPU\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="cellSpursSpu.cpp">
<Filter>Emu\SysCalls\Modules</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Crypto\aes.h">