SPURS: Implement some portions of taskset policy module

This commit is contained in:
S Gopal Rajagopal 2015-01-26 20:15:58 +05:30
parent 430aa9af89
commit 2e2f92f4f6
3 changed files with 170 additions and 9 deletions

View File

@ -1702,7 +1702,7 @@ s64 _cellSpursEventFlagInitialize(vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTas
#ifdef PRX_DEBUG
return GetCurrentPPUThread().FastCall2(libsre + 0x1564C, libsre_rtoc);
#else
if (taskset.addr() == 0 || spurs.addr() == 0)
if (taskset.addr() == 0 && spurs.addr() == 0)
{
return CELL_SPURS_TASK_ERROR_NULL_POINTER;
}
@ -3365,7 +3365,7 @@ s64 cellSpursGetTasksetInfo()
s64 _cellSpursTasksetAttributeInitialize(vm::ptr<CellSpursTasksetAttribute> attribute, u32 revision, u32 sdk_version, u64 args, vm::ptr<const u8> priority, u32 max_contention)
{
cellSpurs->Warning("%s(attribute=0x%x, revision=%u, skd_version=%u, args=0x%llx, priority=0x%x, max_contention=%u)",
cellSpurs->Warning("%s(attribute=0x%x, revision=%d, skd_version=%d, args=0x%llx, priority=0x%x, max_contention=%d)",
__FUNCTION__, attribute.addr(), revision, sdk_version, args, priority.addr(), max_contention);
#ifdef PRX_DEBUG

View File

@ -564,7 +564,7 @@ struct CellSpursEventFlag
be_t<u16> spuTaskPendingRecv; // 0x02 A bit is set to 1 when the condition of the SPU task using the slot are met and back to 0 when the SPU task unblocks
be_t<u16> ppuWaitMask; // 0x04 Wait mask for blocked PPU thread
u8 ppuWaitSlotAndMode; // 0x06 Top 4 bits: Wait slot number of the blocked PPU threa, Bottom 4 bits: Wait mode of the blocked PPU thread
u8 ppuPendingRecv; // 0x07 Set to 1 when the blocked PPU thread's conditions are met and back to 0 when the PPU thread is ublocked
u8 ppuPendingRecv; // 0x07 Set to 1 when the blocked PPU thread's conditions are met and back to 0 when the PPU thread is unblocked
be_t<u16> spuTaskUsedWaitSlots; // 0x08 A bit is set to 1 if the wait slot corresponding to the bit is used by an SPU task and 0 otherwise
be_t<u16> spuTaskWaitMode; // 0x0A A bit is set to 1 if the wait mode for the SPU task corresponding to the bit is AND and 0 otherwise
u8 spuPort; // 0x0C
@ -852,8 +852,9 @@ struct CellSpursTaskBinInfo
CellSpursTaskLsPattern lsPattern;
};
// The SPURS kernel data store. This resides at 0x00 of the LS.
struct SpursKernelMgmtData {
// The SPURS kernel data store. This resides at 0x100 of the LS.
struct SpursKernelMgmtData
{
u8 tempArea[0x80]; // 0x100
u8 wklLocContention[0x10]; // 0x180
u8 wklLocPendingContention[0x10]; // 0x190
@ -867,8 +868,7 @@ struct SpursKernelMgmtData {
be_t<u32> wklCurrentId; // 0x1DC
be_t<u32> yieldToKernelAddr; // 0x1E0
be_t<u32> selectWorkloadAddr; // 0x1E4
u8 x1E8; // 0x1E8
u8 x1E9; // 0x1E9
u8 moduleId[2]; // 0x1E8
u8 sysSrvInitialised; // 0x1EA
u8 spuIdling; // 0x1EB
be_t<u16> wklRunnable1; // 0x1EC
@ -880,5 +880,28 @@ struct SpursKernelMgmtData {
u8 wklUniqueId[0x10]; // 0x220
};
static_assert(sizeof(SpursKernelMgmtData) == 0x130, "Incorrect size for SpursKernelMgmtData");
// The SPURS taskset policy module data store. This resides at 0x2700 of the LS.
struct SpursTasksetPmMgmtData
{
u8 tempArea[0x80]; // 0x2700
u8 x2780[0x27B8 - 0x2780]; // 0x2780
vm::bptr<CellSpursTaskset, 1, u64> taskset; // 0x27B8
be_t<u32> kernelMgmt; // 0x27C0
be_t<u32> yieldAddr; // 0x27C4
be_t<u32> x27C8; // 0x27C8
be_t<u32> spuNum; // 0x27CC
be_t<u32> dmaTagId; // 0x27D0
be_t<u32> taskId; // 0x27D4
u8 x27D8[0x2840 - 0x27D8]; // 0x27D8
u8 moduleId[16]; // 0x2840
u8 x2850[0x2C80 - 0x2850]; // 0x2850
be_t<u128> contextSaveArea[50]; // 0x2C80
u8 x2FA0[0x3000 - 0x2FA0]; // 0x2FA0
};
static_assert(sizeof(SpursTasksetPmMgmtData) == 0x900, "Incorrect size for SpursTasksetPmMgmtData");
s64 spursAttachLv2EventQueue(vm::ptr<CellSpurs> spurs, u32 queue, vm::ptr<u8> port, s32 isDynamic, bool wasCreated);
s64 spursWakeUp(PPUThread& CPU, vm::ptr<CellSpurs> spurs);

View File

@ -33,6 +33,10 @@ void spursSysServiceWaitOrExit(SPUThread & spu, SpursKernelMgmtData * mgmt);
void spursSysServiceWorkloadMain(SPUThread & spu, u32 pollStatus);
void spursSysServiceWorkloadEntry(SPUThread & spu);
//
// SPURS taskset polict module functions
//
extern Module *cellSpurs;
//////////////////////////////////////////////////////////////////////////////
@ -378,8 +382,8 @@ void spursKernelMain(SPUThread & spu) {
}
if (!isSecond) {
mgmt->x1E8 = 0;
mgmt->x1E9 = 0;
mgmt->moduleId[0] = 0;
mgmt->moduleId[1] = 0;
}
// Run workload
@ -387,6 +391,7 @@ void spursKernelMain(SPUThread & spu) {
spu.GPR[3]._u32[3] = 0x100;
spu.GPR[4]._u64[1] = wkl.arg;
spu.GPR[5]._u32[3] = pollStatus;
spu.SetPc(0xA00);
switch (mgmt->wklCurrentAddr.addr()) {
case SPURS_IMG_ADDR_SYS_SRV_WORKLOAD:
spursSysServiceWorkloadEntry(spu);
@ -797,3 +802,136 @@ void spursSysServiceWorkloadEntry(SPUThread & spu) {
// TODO: Ensure that this function always returns to the SPURS kernel
return;
}
//////////////////////////////////////////////////////////////////////////////
// SPURS taskset policy module functions
//////////////////////////////////////////////////////////////////////////////
bool spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 * isWaiting) {
auto kernelMgmt = vm::get_ptr<SpursKernelMgmtData>(spu.ls_offset + 0x100);
auto mgmt = vm::get_ptr<SpursTasksetPmMgmtData>(spu.ls_offset + 0x2700);
// Verify taskset state is valid
for (auto i = 0; i < 4; i ++) {
if ((mgmt->taskset->m.waiting_set[i] & mgmt->taskset->m.running_set[i]) ||
(mgmt->taskset->m.ready_set[i] & mgmt->taskset->m.ready2_set[i]) ||
((mgmt->taskset->m.running_set[i] | mgmt->taskset->m.ready_set[i] |
mgmt->taskset->m.ready2_set[i] | mgmt->taskset->m.signal_received_set[i] |
mgmt->taskset->m.waiting_set[i]) & ~mgmt->taskset->m.enabled_set[i])) {
assert(0);
}
}
// TODO: Implement cases
s32 delta = 0;
switch (request + 1) {
case 0:
break;
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
default:
assert(0);
break;
}
// Set the ready count of the workload to the number of ready tasks
do {
s32 readyCount = kernelMgmt->wklCurrentId >= CELL_SPURS_MAX_WORKLOAD ?
kernelMgmt->spurs->m.wklIdleSpuCountOrReadyCount2[kernelMgmt->wklCurrentId & 0x0F].read_relaxed() :
kernelMgmt->spurs->m.wklReadyCount1[kernelMgmt->wklCurrentId].read_relaxed();
auto newReadyCount = readyCount + delta > 0xFF ? 0xFF : readyCount + delta < 0 ? 0 : readyCount + delta;
if (kernelMgmt->wklCurrentId >= CELL_SPURS_MAX_WORKLOAD) {
kernelMgmt->spurs->m.wklIdleSpuCountOrReadyCount2[kernelMgmt->wklCurrentId & 0x0F].write_relaxed(newReadyCount);
} else {
kernelMgmt->spurs->m.wklReadyCount1[kernelMgmt->wklCurrentId].write_relaxed(newReadyCount);
}
delta += readyCount;
} while (delta > 0);
// TODO: Implement return
return false;
}
void spursTasksetDispatch() {
}
void spursTasksetProcessPollStatus(SPUThread & spu, u32 pollStatus) {
if (pollStatus & CELL_SPURS_MODULE_POLL_STATUS_FLAG) {
spursTasksetProcessRequest(spu, 6, nullptr, nullptr);
}
}
bool spursTasksetShouldYield(SPUThread & spu) {
u32 pollStatus;
if (cellSpursModulePollStatus(spu, &pollStatus)) {
return true;
}
spursTasksetProcessPollStatus(spu, pollStatus);
return false;
}
void spursTasksetInit(SPUThread & spu, u32 pollStatus) {
auto mgmt = vm::get_ptr<SpursTasksetPmMgmtData>(spu.ls_offset + 0x2700);
auto kernelMgmt = vm::get_ptr<SpursKernelMgmtData>(spu.ls_offset + 0x100);
kernelMgmt->moduleId[0] = 'T';
kernelMgmt->moduleId[1] = 'K';
// Trace - START: Module='TKST'
CellSpursTracePacket pkt;
memset(&pkt, 0, sizeof(pkt));
pkt.header.tag = 0x52; // Its not clear what this tag means exactly but it seems similar to CELL_SPURS_TRACE_TAG_START
memcpy(pkt.data.start.module, "TKST", 4);
pkt.data.start.level = 2;
pkt.data.start.ls = 0xA00 >> 2;
cellSpursModulePutTrace(&pkt, mgmt->dmaTagId);
spursTasksetProcessPollStatus(spu, pollStatus);
}
void spursTasksetEntry(SPUThread & spu) {
auto mgmt = vm::get_ptr<SpursTasksetPmMgmtData>(spu.ls_offset + 0x2700);
// Check if the function was invoked by the SPURS kernel or because of a syscall
if (spu.PC != 0xA70) {
// Called from kernel
auto kernelMgmt = 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];
memset(mgmt, 0, sizeof(*mgmt));
mgmt->taskset.set(arg);
memcpy(mgmt->moduleId, "SPURSTASK MODULE", 16);
mgmt->kernelMgmt = spu.GPR[3]._u32[3];
mgmt->yieldAddr = 0xA70;
mgmt->spuNum = kernelMgmt->spuNum;
mgmt->dmaTagId = kernelMgmt->dmaTagId;
mgmt->taskId = 0xFFFFFFFF;
spursTasksetInit(spu, pollStatus);
// TODO: Dispatch
}
mgmt->contextSaveArea[0] = spu.GPR[0];
mgmt->contextSaveArea[1] = spu.GPR[1];
for (auto i = 0; i < 48; i++) {
mgmt->contextSaveArea[i + 2] = spu.GPR[80 + i];
}
// TODO: Process syscall
}