2008-12-02 03:10:37 +00:00
|
|
|
#include "Iop_SifCmd.h"
|
2008-12-05 03:30:01 +00:00
|
|
|
#include "IopBios.h"
|
2009-04-28 01:20:03 +00:00
|
|
|
#include "../SIF.h"
|
2008-12-03 03:17:13 +00:00
|
|
|
#include "../Log.h"
|
2009-02-04 02:15:56 +00:00
|
|
|
#include "../StructCollectionStateFile.h"
|
|
|
|
#include <boost/lexical_cast.hpp>
|
2008-12-03 03:17:13 +00:00
|
|
|
|
|
|
|
using namespace Iop;
|
|
|
|
using namespace std;
|
|
|
|
|
2009-02-04 02:15:56 +00:00
|
|
|
#define LOG_NAME ("iop_sifcmd")
|
|
|
|
#define STATE_MODULES ("iop_sifcmd/modules.xml")
|
|
|
|
#define STATE_MODULE ("Module")
|
|
|
|
#define STATE_MODULE_SERVER_DATA_ADDRESS ("ServerDataAddress")
|
2008-12-03 03:17:13 +00:00
|
|
|
|
2008-12-15 02:57:21 +00:00
|
|
|
#define CUSTOM_RETURNFROMRPCINVOKE 0x666
|
|
|
|
|
|
|
|
#define MODULE_NAME "sifcmd"
|
|
|
|
#define MODULE_VERSION 0x101
|
|
|
|
|
2009-04-28 01:20:03 +00:00
|
|
|
#define FUNCTION_SIFSENDCMD "SifSendCmd"
|
2008-12-15 02:57:21 +00:00
|
|
|
#define FUNCTION_SIFINITRPC "SifInitRpc"
|
2009-04-28 01:20:03 +00:00
|
|
|
#define FUNCTION_SIFBINDRPC "SifBindRpc"
|
2008-12-15 02:57:21 +00:00
|
|
|
#define FUNCTION_SIFREGISTERRPC "SifRegisterRpc"
|
|
|
|
#define FUNCTION_SIFSETRPCQUEUE "SifSetRpcQueue"
|
|
|
|
#define FUNCTION_SIFRPCLOOP "SifRpcLoop"
|
|
|
|
#define FUNCTION_RETURNFROMRPCINVOKE "ReturnFromRpcInvoke"
|
2008-12-05 03:30:01 +00:00
|
|
|
|
2008-12-19 03:30:49 +00:00
|
|
|
#define INVOKE_PARAMS_SIZE 0x4000
|
2008-12-08 03:43:30 +00:00
|
|
|
#define TRAMPOLINE_SIZE 0x800
|
2008-12-05 03:30:01 +00:00
|
|
|
|
2008-12-08 03:43:30 +00:00
|
|
|
CSifCmd::CSifCmd(CIopBios& bios, CSifMan& sifMan, CSysmem& sysMem, uint8* ram) :
|
|
|
|
m_sifMan(sifMan),
|
|
|
|
m_bios(bios),
|
|
|
|
m_sysMem(sysMem),
|
|
|
|
m_ram(ram)
|
|
|
|
{
|
|
|
|
m_memoryBufferAddr = m_sysMem.AllocateMemory(INVOKE_PARAMS_SIZE + TRAMPOLINE_SIZE, 0);
|
|
|
|
m_invokeParamsAddr = m_memoryBufferAddr;
|
|
|
|
m_trampolineAddr = m_invokeParamsAddr + INVOKE_PARAMS_SIZE;
|
2008-12-15 02:57:21 +00:00
|
|
|
|
|
|
|
BuildExportTable();
|
2008-12-05 03:30:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CSifCmd::~CSifCmd()
|
|
|
|
{
|
2009-02-04 02:15:56 +00:00
|
|
|
ClearServers();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSifCmd::LoadState(CZipArchiveReader& archive)
|
|
|
|
{
|
|
|
|
ClearServers();
|
|
|
|
|
|
|
|
CStructCollectionStateFile modulesFile(*archive.BeginReadFile(STATE_MODULES));
|
2008-12-08 03:43:30 +00:00
|
|
|
{
|
2009-02-04 02:15:56 +00:00
|
|
|
for(CStructCollectionStateFile::StructIterator structIterator(modulesFile.GetStructBegin());
|
|
|
|
structIterator != modulesFile.GetStructEnd(); structIterator++)
|
|
|
|
{
|
|
|
|
const CStructFile& structFile(structIterator->second);
|
|
|
|
uint32 serverDataAddress = structFile.GetRegister32(STATE_MODULE_SERVER_DATA_ADDRESS);
|
|
|
|
SIFRPCSERVERDATA* serverData(reinterpret_cast<SIFRPCSERVERDATA*>(m_ram + serverDataAddress));
|
|
|
|
CSifDynamic* module = new CSifDynamic(*this, serverDataAddress);
|
|
|
|
m_servers.push_back(module);
|
|
|
|
m_sifMan.RegisterModule(serverData->serverId, module);
|
|
|
|
}
|
2008-12-08 03:43:30 +00:00
|
|
|
}
|
2009-02-04 02:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CSifCmd::SaveState(CZipArchiveWriter& archive)
|
|
|
|
{
|
|
|
|
CStructCollectionStateFile* modulesFile = new CStructCollectionStateFile(STATE_MODULES);
|
|
|
|
{
|
|
|
|
int moduleIndex = 0;
|
|
|
|
for(DynamicModuleList::iterator serverIterator(m_servers.begin());
|
|
|
|
serverIterator != m_servers.end(); serverIterator++)
|
|
|
|
{
|
|
|
|
CSifDynamic* module(*serverIterator);
|
|
|
|
string moduleName = string(STATE_MODULE) + boost::lexical_cast<string>(moduleIndex++);
|
|
|
|
CStructFile moduleStruct;
|
|
|
|
{
|
|
|
|
uint32 serverDataAddress = module->GetServerDataAddress();
|
|
|
|
moduleStruct.SetRegister32(STATE_MODULE_SERVER_DATA_ADDRESS, serverDataAddress);
|
|
|
|
}
|
|
|
|
modulesFile->InsertStruct(moduleName.c_str(), moduleStruct);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
archive.InsertFile(modulesFile);
|
2008-12-05 03:30:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string CSifCmd::GetId() const
|
|
|
|
{
|
2008-12-15 02:57:21 +00:00
|
|
|
return MODULE_NAME;
|
2008-12-05 03:30:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string CSifCmd::GetFunctionName(unsigned int functionId) const
|
|
|
|
{
|
|
|
|
switch(functionId)
|
|
|
|
{
|
2009-04-28 01:20:03 +00:00
|
|
|
case 12:
|
|
|
|
return FUNCTION_SIFSENDCMD;
|
|
|
|
break;
|
2008-12-05 03:30:01 +00:00
|
|
|
case 14:
|
|
|
|
return FUNCTION_SIFINITRPC;
|
|
|
|
break;
|
2009-04-28 01:20:03 +00:00
|
|
|
case 15:
|
|
|
|
return FUNCTION_SIFBINDRPC;
|
|
|
|
break;
|
2008-12-05 03:30:01 +00:00
|
|
|
case 17:
|
|
|
|
return FUNCTION_SIFREGISTERRPC;
|
|
|
|
break;
|
|
|
|
case 19:
|
|
|
|
return FUNCTION_SIFSETRPCQUEUE;
|
|
|
|
break;
|
|
|
|
case 22:
|
|
|
|
return FUNCTION_SIFRPCLOOP;
|
|
|
|
break;
|
2008-12-15 02:57:21 +00:00
|
|
|
case CUSTOM_RETURNFROMRPCINVOKE:
|
|
|
|
return FUNCTION_RETURNFROMRPCINVOKE;
|
|
|
|
break;
|
2008-12-05 03:30:01 +00:00
|
|
|
default:
|
|
|
|
return "unknown";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSifCmd::Invoke(CMIPS& context, unsigned int functionId)
|
|
|
|
{
|
|
|
|
switch(functionId)
|
|
|
|
{
|
2009-04-28 01:20:03 +00:00
|
|
|
case 12:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nV0 = SifSendCmd(
|
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0,
|
|
|
|
context.m_State.nGPR[CMIPS::A1].nV0,
|
|
|
|
context.m_State.nGPR[CMIPS::A2].nV0,
|
|
|
|
context.m_State.nGPR[CMIPS::A3].nV0,
|
|
|
|
context.m_pMemoryMap->GetWord(context.m_State.nGPR[CMIPS::SP].nV0 + 0x10),
|
|
|
|
context.m_pMemoryMap->GetWord(context.m_State.nGPR[CMIPS::SP].nV0 + 0x14));
|
|
|
|
break;
|
|
|
|
case 15:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nV0 = SifBindRpc(
|
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0,
|
|
|
|
context.m_State.nGPR[CMIPS::A1].nV0,
|
|
|
|
context.m_State.nGPR[CMIPS::A2].nV0);
|
|
|
|
break;
|
2008-12-05 03:30:01 +00:00
|
|
|
case 17:
|
|
|
|
SifRegisterRpc(context);
|
|
|
|
break;
|
2008-12-08 03:43:30 +00:00
|
|
|
case 19:
|
|
|
|
SifSetRpcQueue(context.m_State.nGPR[CMIPS::A0].nV0,
|
|
|
|
context.m_State.nGPR[CMIPS::A1].nV0);
|
|
|
|
break;
|
2008-12-05 03:30:01 +00:00
|
|
|
case 22:
|
|
|
|
SifRpcLoop(context.m_State.nGPR[CMIPS::A0].nV0);
|
|
|
|
break;
|
2008-12-15 02:57:21 +00:00
|
|
|
case CUSTOM_RETURNFROMRPCINVOKE:
|
|
|
|
ReturnFromRpcInvoke(context);
|
|
|
|
break;
|
2008-12-05 03:30:01 +00:00
|
|
|
default:
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Unknown function called (%d).\r\n",
|
|
|
|
functionId);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-04 02:15:56 +00:00
|
|
|
void CSifCmd::ClearServers()
|
|
|
|
{
|
|
|
|
for(DynamicModuleList::iterator serverIterator(m_servers.begin());
|
|
|
|
m_servers.end() != serverIterator; serverIterator++)
|
|
|
|
{
|
|
|
|
CSifDynamic* server(*serverIterator);
|
|
|
|
SIFRPCSERVERDATA* serverData(reinterpret_cast<SIFRPCSERVERDATA*>(m_ram + server->GetServerDataAddress()));
|
|
|
|
m_sifMan.UnregisterModule(serverData->serverId);
|
|
|
|
delete (*serverIterator);
|
|
|
|
}
|
|
|
|
m_servers.clear();
|
|
|
|
}
|
|
|
|
|
2008-12-15 02:57:21 +00:00
|
|
|
void CSifCmd::BuildExportTable()
|
|
|
|
{
|
|
|
|
uint32* exportTable = reinterpret_cast<uint32*>(m_ram + m_trampolineAddr);
|
|
|
|
*(exportTable++) = 0x41E00000;
|
|
|
|
*(exportTable++) = 0;
|
|
|
|
*(exportTable++) = MODULE_VERSION;
|
|
|
|
strcpy(reinterpret_cast<char*>(exportTable), MODULE_NAME);
|
|
|
|
exportTable += (strlen(MODULE_NAME) + 3) / 4;
|
|
|
|
|
|
|
|
{
|
|
|
|
m_returnFromRpcInvokeAddr = reinterpret_cast<uint8*>(exportTable) - m_ram;
|
|
|
|
CMIPSAssembler assembler(exportTable);
|
|
|
|
assembler.JR(CMIPS::RA);
|
|
|
|
assembler.ADDIU(CMIPS::R0, CMIPS::R0, CUSTOM_RETURNFROMRPCINVOKE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-08 03:43:30 +00:00
|
|
|
void CSifCmd::ProcessInvocation(uint32 serverDataAddr, uint32 methodId, uint32* params, uint32 size)
|
|
|
|
{
|
|
|
|
SIFRPCSERVERDATA* serverData = reinterpret_cast<SIFRPCSERVERDATA*>(&m_ram[serverDataAddr]);
|
|
|
|
SIFRPCDATAQUEUE* dataQueue = reinterpret_cast<SIFRPCDATAQUEUE*>(&m_ram[serverData->queueAddr]);
|
|
|
|
|
|
|
|
//Copy params
|
|
|
|
assert(size <= INVOKE_PARAMS_SIZE);
|
|
|
|
uint32 copySize = min<uint32>(size, INVOKE_PARAMS_SIZE);
|
|
|
|
memcpy(&m_ram[m_invokeParamsAddr], params, copySize);
|
|
|
|
CIopBios::THREAD& thread(m_bios.GetThread(dataQueue->threadId));
|
|
|
|
thread.context.epc = serverData->function;
|
|
|
|
thread.context.gpr[CMIPS::A0] = methodId;
|
|
|
|
thread.context.gpr[CMIPS::A1] = m_invokeParamsAddr;
|
|
|
|
thread.context.gpr[CMIPS::A2] = size;
|
2008-12-15 02:57:21 +00:00
|
|
|
thread.context.gpr[CMIPS::S0] = serverDataAddr;
|
|
|
|
thread.context.gpr[CMIPS::RA] = m_returnFromRpcInvokeAddr;
|
2008-12-08 03:43:30 +00:00
|
|
|
m_bios.WakeupThread(dataQueue->threadId, true);
|
2008-12-15 02:57:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CSifCmd::ReturnFromRpcInvoke(CMIPS& context)
|
|
|
|
{
|
|
|
|
SIFRPCSERVERDATA* serverData = reinterpret_cast<SIFRPCSERVERDATA*>(&m_ram[context.m_State.nGPR[CMIPS::S0].nV0]);
|
|
|
|
uint8* returnData = m_ram + context.m_State.nGPR[CMIPS::V0].nV0;
|
|
|
|
m_bios.SleepThread();
|
|
|
|
m_sifMan.SendCallReply(serverData->serverId, returnData);
|
2008-12-08 03:43:30 +00:00
|
|
|
}
|
|
|
|
|
2009-04-28 01:20:03 +00:00
|
|
|
uint32 CSifCmd::SifSendCmd(uint32 commandId, uint32 packetPtr, uint32 packetSize, uint32 srcExtraPtr, uint32 dstExtraPtr, uint32 sizeExtra)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "SifSendCmd(commandId = 0x%0.8X, packetPtr = 0x%0.8X, packetSize = 0x%0.8X, srcExtraPtr = 0x%0.8X, dstExtraPtr = 0x%0.8X, sizeExtra = 0x%0.8X);\r\n",
|
|
|
|
commandId, packetPtr, packetSize, srcExtraPtr, dstExtraPtr, sizeExtra);
|
|
|
|
|
|
|
|
assert(srcExtraPtr == 0);
|
|
|
|
assert(dstExtraPtr == 0);
|
|
|
|
assert(sizeExtra == 0);
|
2009-04-30 01:54:33 +00:00
|
|
|
assert(packetSize >= 0x10);
|
2009-04-28 01:20:03 +00:00
|
|
|
|
|
|
|
uint8* packetData = m_ram + packetPtr;
|
2009-04-30 01:54:33 +00:00
|
|
|
CSIF::PACKETHDR* header = reinterpret_cast<CSIF::PACKETHDR*>(packetData);
|
2009-04-28 01:20:03 +00:00
|
|
|
header->nCID = commandId;
|
|
|
|
header->nSize = packetSize;
|
|
|
|
header->nDest = 0;
|
2009-04-30 01:54:33 +00:00
|
|
|
m_sifMan.SendPacket(packetData, packetSize);
|
2009-04-28 01:20:03 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CSifCmd::SifBindRpc(uint32 clientDataAddress, uint32 rpcNumber, uint32 mode)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "SifBindRpc(clientData = 0x%0.8X, rpcNumber = 0x%0.8X, mode = 0x%0.8X);\r\n",
|
|
|
|
clientDataAddress, rpcNumber, mode);
|
|
|
|
//Set struct t_SifRpcServerData *server to 0
|
|
|
|
*reinterpret_cast<uint32*>(&m_ram[clientDataAddress + 0x24]) = rpcNumber;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-12-05 03:30:01 +00:00
|
|
|
void CSifCmd::SifRegisterRpc(CMIPS& context)
|
|
|
|
{
|
2008-12-08 03:43:30 +00:00
|
|
|
uint32 serverDataAddr = context.m_State.nGPR[CMIPS::A0].nV0;
|
|
|
|
uint32 serverId = context.m_State.nGPR[CMIPS::A1].nV0;
|
|
|
|
uint32 function = context.m_State.nGPR[CMIPS::A2].nV0;
|
|
|
|
uint32 buffer = context.m_State.nGPR[CMIPS::A3].nV0;
|
|
|
|
uint32 cfunction = context.m_pMemoryMap->GetWord(context.m_State.nGPR[CMIPS::SP].nV0 + 0x10);
|
|
|
|
uint32 cbuffer = context.m_pMemoryMap->GetWord(context.m_State.nGPR[CMIPS::SP].nV0 + 0x14);
|
|
|
|
uint32 queueAddr = context.m_pMemoryMap->GetWord(context.m_State.nGPR[CMIPS::SP].nV0 + 0x18);
|
2008-12-05 03:30:01 +00:00
|
|
|
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "SifRegisterRpc(serverData = 0x%0.8X, serverId = 0x%0.8X, function = 0x%0.8X, buffer = 0x%0.8X, cfunction = 0x%0.8X, cbuffer = 0x%0.8X, queue = 0x%0.8X);\r\n",
|
2008-12-08 03:43:30 +00:00
|
|
|
serverDataAddr, serverId, function, buffer, cfunction, cbuffer, queueAddr);
|
|
|
|
|
|
|
|
if(!(serverId & 0x80000000))
|
|
|
|
{
|
|
|
|
CSifDynamic* module = new CSifDynamic(*this, serverDataAddr);
|
|
|
|
m_servers.push_back(module);
|
|
|
|
m_sifMan.RegisterModule(serverId, module);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(serverDataAddr != 0)
|
|
|
|
{
|
|
|
|
SIFRPCSERVERDATA* serverData = reinterpret_cast<SIFRPCSERVERDATA*>(&m_ram[serverDataAddr]);
|
|
|
|
serverData->serverId = serverId;
|
|
|
|
serverData->function = function;
|
|
|
|
serverData->buffer = buffer;
|
|
|
|
serverData->cfunction = cfunction;
|
|
|
|
serverData->cbuffer = cbuffer;
|
|
|
|
serverData->queueAddr = queueAddr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(queueAddr != 0)
|
|
|
|
{
|
|
|
|
SIFRPCDATAQUEUE* dataQueue = reinterpret_cast<SIFRPCDATAQUEUE*>(&m_ram[queueAddr]);
|
|
|
|
assert(dataQueue->serverDataStart == 0);
|
|
|
|
dataQueue->serverDataStart = serverDataAddr;
|
|
|
|
}
|
2008-12-05 03:30:01 +00:00
|
|
|
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = 0;
|
|
|
|
}
|
|
|
|
|
2008-12-08 03:43:30 +00:00
|
|
|
void CSifCmd::SifSetRpcQueue(uint32 queueAddr, uint32 threadId)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "SifSetRpcQueue(queue = 0x%0.8X, threadId = %d);\r\n",
|
|
|
|
queueAddr, threadId);
|
|
|
|
|
|
|
|
if(queueAddr != 0)
|
|
|
|
{
|
|
|
|
SIFRPCDATAQUEUE* dataQueue = reinterpret_cast<SIFRPCDATAQUEUE*>(&m_ram[queueAddr]);
|
|
|
|
dataQueue->threadId = threadId;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-05 03:30:01 +00:00
|
|
|
void CSifCmd::SifRpcLoop(uint32 queueAddr)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "SifRpcLoop(queue = 0x%0.8X);\r\n",
|
|
|
|
queueAddr);
|
|
|
|
m_bios.SleepThread();
|
|
|
|
}
|