//[module] SIFCMD //[processor] IOP //[type] ELF-IRX //[name] IOP_SIF_rpc_interface //[version] 0x101 //[memory map] //[handlers] //[entry point] sifcmd_start, sifcmd_stub //[made by] [RO]man (roman_ps2dev@hotmail.com) #include "kloadcore.h" #include "kintrman.h" #include "ksifman.h" #include "kthbase.h" #include "ksifcmd.h" #include "ksifman.h" #define _dprintf(fmt, args...) \ __printf("sifcmd: " fmt, ## args) int sifInitRpc=0; // CMD data char sif1_rcvBuffer[8*16]; //8 qwords char b[4*16]; //not used struct tag_cmd_common { char *sif1_rcvBuffer, //+00 *b, //+04 *saddr; //+08 SifCmdData *sysCmdBuffer; //+0C int sysCmdBufferSize; //+10 SifCmdData *cmdBuffer; //+14 int cmdBufferSize, //+18 *Sreg, //+1C systemStatusFlag; //+20 void (*func)(int); //+24 int param, //+28 _pad; //+2C } cmd_common; //=30 SifCmdData sysCmds[32]; int Sreg[32]; // RPC data int bufx[512], bufy[512]; struct tag_rpc_common{ int pid; RPC_PACKET *paddr; int size; RPC_PACKET *paddr2; int size2; void *next; int count; int base; void *queue; int _pad0, _pad1, _pad2; } rpc_common; int _start(); /////////////////////////////////////////////////////////////////////// //////////////////////////// CMD ////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// void cmd80000001_SET_SREG(SifCmdSRData *packet, struct tag_cmd_common *common) { common->Sreg[packet->rno]=packet->value; } /////////////////////////////////////////////////////////////////////// void cmd80000000_CHANGE_SADDR(SifCmdCSData *packet, struct tag_cmd_common *common) { common->saddr=packet->newaddr; } ///////////////////////////////////////////////////////////////////////[06] int SifGetSreg(int index){ return Sreg[index]; } ///////////////////////////////////////////////////////////////////////[07] int SifSetSreg(int index, unsigned int value){ return Sreg[index]=value; } /////////////////////////////////////////////////////////////////////// void *getCmdCommon(){ return &cmd_common; } /////////////////////////////////////////////////////////////////////// void cmd80000002_INIT_CMD(SifCmdCSData *packet, struct tag_cmd_common *common){ __printf("cmd80000002_INIT_CMD\n"); if (packet->hdr.opt==0){ iSetEventFlag(common->systemStatusFlag, 0x100); SifSetEEIOPflags(0x20000); common->saddr=packet->newaddr; }else iSetEventFlag(common->systemStatusFlag, 0x800); } ///////////////////////////////////////////////////////////////////////[02] int SifDeinitCmd(){ int x; DisableIntr(INT_DMA10, &x); ReleaseIntrHandler(INT_DMA10); SifDeinit(); return 0; } ///////////////////////////////////////////////////////////////////////[04] void SifInitCmd(){ __printf("iopSifInitCmd\n"); SifSetIOPEEflags(0x20000); WaitEventFlag(cmd_common.systemStatusFlag, 0x100, 0, 0); } ///////////////////////////////////////////////////////////////////////[05] void SifExitCmd(){ int x; DisableIntr(INT_DMA10, &x); ReleaseIntrHandler(INT_DMA10); } ///////////////////////////////////////////////////////////////////////[08] SifCmdData *SifSetCmdBuffer(SifCmdData *cmdBuffer, int size){ register SifCmdData *old; old=cmd_common.cmdBuffer; cmd_common.cmdBuffer=cmdBuffer; cmd_common.cmdBufferSize=size; return old; } ///////////////////////////////////////////////////////////////////////[09] SifCmdData *SifSetSysCmdBuffer(SifCmdData *sysCmdBuffer, int size){ register SifCmdData *old; old=cmd_common.sysCmdBuffer; cmd_common.sysCmdBuffer=sysCmdBuffer; cmd_common.sysCmdBufferSize=size; return old; } ///////////////////////////////////////////////////////////////////////[0A] void SifAddCmdHandler(int pos, cmdh_func f, void *data){ if (pos<0){ cmd_common.sysCmdBuffer[pos & 0x1FFFFFFF].func=f; cmd_common.sysCmdBuffer[pos & 0x1FFFFFFF].data=data; }else{ cmd_common.cmdBuffer [pos & 0x1FFFFFFF].func=f; cmd_common.cmdBuffer [pos & 0x1FFFFFFF].data=data; } } ///////////////////////////////////////////////////////////////////////[0B] void SifRemoveCmdHandler(unsigned int pos){ if (pos<0) cmd_common.sysCmdBuffer[pos & 0x1FFFFFFF].func=0; else cmd_common.cmdBuffer [pos & 0x1FFFFFFF].func=0; } /////////////////////////////////////////////////////////////////////// unsigned int sendCmd(unsigned int pos, int mode, SifCmdHdr *cp, int ps, void *src, void *dst, int size){ u32 x; struct sifman_DMA dma[2]; register int count, y; if (ps<16 || ps>112) return 0; count=0; if (size>0){ count=1; dma[0].addr=dst; dma[0].size=size; dma[0].attr=0; dma[0].data=src; cp->daddr=(u32)dst; cp->dsize=size; }else{ cp->daddr=0; cp->dsize=0; } count++; cp->psize=ps; cp->fcode=pos; dma[count-1].data=cp; dma[count-1].attr=SIF_DMA_INT_O; //calls SIF0 handler dma[count-1].size=ps; //on EE side after transfer;) dma[count-1].addr=cmd_common.saddr; if (mode & 1) //interrupt mode return SifSetDma(dma, count); else{ CpuSuspendIntr(&x); y=SifSetDma(dma, count); CpuResumeIntr(x); return y; } } ///////////////////////////////////////////////////////////////////////[0C] unsigned int SifSendCmd(unsigned int pos, void *cp, int ps, void *src, void *dst, int size){ return sendCmd(pos, 0, cp, ps, src, dst, size); } ///////////////////////////////////////////////////////////////////////[0D] unsigned int iSifSendCmd(unsigned int pos, void *cp, int ps, void *src, void *dst, int size){ return sendCmd(pos, 1, cp, ps, src, dst, size); } ///////////////////////////////////////////////////////////////////////[1A] void SifSet1CB(void *func, int param){ cmd_common.func =func; cmd_common.param=param; } ///////////////////////////////////////////////////////////////////////[1B] void SifReset1CB(){ cmd_common.func =0; cmd_common.param=0; } /////////////////////////////////////////////////////////////////////// int SIF1_handler(void *common){ int buf[112/4]; register int i, ps; register SifCmdData *scd; SifCmdHdr *packet; struct tag_cmd_common *c = (struct tag_cmd_common *)common; if (c->func) c->func(c->param); packet=(SifCmdHdr*)c->sif1_rcvBuffer; if ((ps=packet->psize & 0xFF)==0){ SifSetDChain(); return 1; } packet->psize=0; ps=(ps+3<0 ? ps+6 : ps+3)/4; for (i=0; ifcode<0){ if (packet->fcode & 0x7FFFFFFF>=c->sysCmdBufferSize) return 1; scd=&c->sysCmdBuffer[packet->fcode & 0x7FFFFFFF]; }else{ if (packet->fcode>=c->cmdBufferSize) return 1; scd=&c->cmdBuffer[packet->fcode]; } if (scd->func) scd->func(packet, scd->data); return 1; } /////////////////////////////////////////////////////////////////////// //////////////////////////// RPC ////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// RPC_PACKET *rpc_get_packet(struct tag_rpc_common *common){ u32 x; register int pid, i; RPC_PACKET *packet; CpuSuspendIntr(&x); for (i=0, packet=common->paddr; isize; i++) if (packet[i].rec_id & 2==0) goto found; for (i=0, packet=common->paddr2; isize2; i++) if (packet[i].rec_id & 2==0) goto found; CpuResumeIntr(x); return 0; found: packet[i].rec_id |= 2; pid=++common->pid; if (pid == 1) common->pid++; packet[i].pid=pid; packet[i].paddr=&packet[i]; CpuResumeIntr(x); return &packet[i]; } /////////////////////////////////////////////////////////////////////// void rpc_free_packet(RPC_PACKET *packet){ packet->pid = 0; packet->rec_id &= 0xFFFFFFFD; //~2 } /////////////////////////////////////////////////////////////////////// RPC_PACKET *rpc_get_fpacket(struct tag_rpc_common *common){ register int i; i=common->base % common->count; common->base=i+1; return (RPC_PACKET*)(((u8*)common->next)+i*64); } /////////////////////////////////////////////////////////////////////// void cmd80000008_END(RPC_PACKET_END *packet, struct tag_rpc_common *common){ if (packet->command==0x8000000A){ if (packet->client->func) packet->client->func(packet->client->param); }else if (packet->command==0x80000009){ packet->client->server=packet->server; packet->client->buff =packet->buff; packet->client->cbuff =packet->cbuff; } if (packet->client->hdr.tid>=0) iWakeupThread(packet->client->hdr.tid); rpc_free_packet(packet->client->hdr.pkt_addr); packet->client->hdr.pkt_addr=0; } /////////////////////////////////////////////////////////////////////// void cmd8000000C_RDATA(RPC_PACKET_RDATA *packet, struct tag_rpc_common *common){ RPC_PACKET_END *epacket; epacket = (RPC_PACKET_END *)rpc_get_fpacket(common); epacket->packet.paddr = packet->packet.paddr; epacket->command = 0x8000000C; epacket->client = packet->client; iSifSendCmd(0x80000008, epacket, 0x40, packet->src, packet->dst, packet->size); } ///////////////////////////////////////////////////////////////////////[17] int SifGetOtherData(struct sifcmd_RPC_RECEIVE_DATA *rd, void *src, void *dst, int size, int mode){ RPC_PACKET_RDATA *packet; if ((packet=(RPC_PACKET_RDATA *)rpc_get_packet(&rpc_common))==0) return -1; rd->hdr.pkt_addr=packet; rd->hdr.rpc_id =packet->packet.pid; packet->packet.paddr=packet; packet->client=(struct sifcmd_RPC_CLIENT_DATA*)rd; packet->src=src; packet->dst=dst; packet->size=size; if (mode & 1==0){ rd->hdr.tid=GetThreadId(); if (SifSendCmd(0x8000000C, packet, 0x40, 0, 0, 0)==0) return -2; SleepThread(); }else{ //async rd->hdr.tid=-1; if (SifSendCmd(0x8000000C, packet, 0x40, 0, 0, 0)==0) return -2; } return 0; } /////////////////////////////////////////////////////////////////////// struct sifcmd_RPC_SERVER_DATA *search_svdata(u32 command, struct tag_rpc_common *common){ struct sifcmd_RPC_SERVER_DATA *q; struct sifcmd_RPC_SERVER_DATA *s; for (q=common->queue; q; q=q->next) { for (s=q->link; s; s=s->link) { if (s->command==command) return s; } } return 0; } /////////////////////////////////////////////////////////////////////// void cmd80000009_BIND(RPC_PACKET_BIND *packet, struct tag_rpc_common *common){ RPC_PACKET_END *epacket; struct sifcmd_RPC_SERVER_DATA *s; epacket = (RPC_PACKET_END *)rpc_get_fpacket(common); epacket->packet.paddr=packet->packet.paddr; epacket->command=0x80000009; epacket->client=packet->client; s = search_svdata(packet->fno, common); if (s == NULL){ epacket->server=0; epacket->buff =0; epacket->cbuff =0; }else{ epacket->server=s; epacket->buff =s->buff; epacket->cbuff =s->cbuff; } iSifSendCmd(0x80000008, epacket, 0x40, 0, 0, 0); } ///////////////////////////////////////////////////////////////////////[0F] int SifBindRpc(struct sifcmd_RPC_CLIENT_DATA *client, unsigned int number, unsigned int mode) { RPC_PACKET_BIND *packet; client->command=0; client->server=0; packet = (RPC_PACKET_BIND *)rpc_get_packet(&rpc_common); if (packet==NULL) return -1; client->hdr.pkt_addr = packet; client->hdr.rpc_id = packet->packet.pid; packet->packet.paddr = packet; packet->client = client; packet->fno = number; if (mode & 1==0){ client->hdr.tid=GetThreadId(); if (SifSendCmd(0x80000009, packet, 0x40, 0, 0, 0)==0) return -2; SleepThread(); }else{ //async client->hdr.tid=-1; if (SifSendCmd(0x80000009, packet, 0x40, 0, 0, 0)==0) return -2; } return 0; } /////////////////////////////////////////////////////////////////////// void cmd8000000A_CALL(RPC_PACKET_CALL *packet, struct tag_rpc_common *common){ struct sifcmd_RPC_DATA_QUEUE *qd; qd = packet->server->base; if (qd->start==0) qd->start=packet->server; else qd->end->link=packet->server; qd->end=packet->server; packet->server->pkt_addr=packet->packet.packet.paddr; packet->server->client=packet->packet.client; packet->server->fno=packet->packet.fno; packet->server->size=packet->size; packet->server->receive=packet->receive; packet->server->rsize=packet->rsize; packet->server->rmode=packet->rmode; if ((qd->key>=0) && (qd->active==0)) iWakeupThread(qd->key); } ///////////////////////////////////////////////////////////////////////[10] int SifCallRpc(struct sifcmd_RPC_CLIENT_DATA *client, unsigned int fno, unsigned int mode, void *send, int ssize, void *receive, int rsize, void (*end_func)(void*), void *end_para){ RPC_PACKET_CALL *packet; if ((packet=(RPC_PACKET_CALL *)rpc_get_packet(&rpc_common))==0) return -1; client->hdr.pkt_addr=(void*)packet; client->func = end_func; client->param = end_para; client->hdr.rpc_id= packet->packet.packet.pid; packet->packet.packet.paddr = packet; packet->packet.client = client; packet->packet.fno = fno; packet->size = ssize; packet->receive= receive; packet->rsize = rsize; packet->server = client->server; if (mode & 1){ packet->rmode=(end_func!=0); client->hdr.tid=-1; if (SifSendCmd(0x8000000A, packet, 0x40, send, client->buff, ssize)) return 0; return -2; }else{ packet->rmode=1; client->hdr.tid=GetThreadId(); if (SifSendCmd(0x8000000A, packet, 0x40, send, client->buff, ssize)==0) return -2; SleepThread(); return 0; } } ///////////////////////////////////////////////////////////////////////[12] int SifCheckStatRpc(struct sifcmd_RPC_HEADER *rd){ RPC_PACKET *packet = (RPC_PACKET*)rd->pkt_addr; return (rd->pkt_addr && (rd->rpc_id==packet->pid) && (packet->rec_id & 2)); } ///////////////////////////////////////////////////////////////////////[13] void SifSetRpcQueue(struct sifcmd_RPC_DATA_QUEUE *qd, int key){ u32 x; register struct sifcmd_RPC_DATA_QUEUE *q, *i; CpuSuspendIntr(&x); qd->key=key; qd->active=0; qd->link=0; qd->start=0; qd->end=0; qd->next=0; q = (struct sifcmd_RPC_DATA_QUEUE *)&rpc_common.queue; if (q) { for (i=q->next; i; i=q->next) q=q->next; } rpc_common.queue = qd; CpuResumeIntr(x); } ///////////////////////////////////////////////////////////////////////[11] void SifRegisterRpc(struct sifcmd_RPC_SERVER_DATA *sd, u32 command, rpch_func func, void *buff, rpch_func cfunc, void *cbuff, struct sifcmd_RPC_DATA_QUEUE *qd) { u32 x; register struct sifcmd_RPC_DATA_QUEUE *q, *i; CpuSuspendIntr(&x); sd->command=command; sd->func=func; sd->buff=buff; sd->next=0; sd->link=0; sd->cfunc=cfunc; sd->cbuff=cbuff; sd->base=qd; if (qd->link==0) qd->link=sd; else{ for (q=qd->link, i=q->link; i; i=q->link) q=q->link; q->link=sd; } CpuResumeIntr(x); } ///////////////////////////////////////////////////////////////////////[18] struct sifcmd_RPC_SERVER_DATA *SifRemoveRpc(struct sifcmd_RPC_SERVER_DATA *sd, struct sifcmd_RPC_DATA_QUEUE *qd){ u32 x; register struct sifcmd_RPC_SERVER_DATA *s; CpuSuspendIntr(&x); if ((s=qd->link)==sd) qd->link=s->link; else for ( ; s; s=s->link) if (s->link==sd){ s->link=s->link->link; break; } CpuResumeIntr(x); return s; } ///////////////////////////////////////////////////////////////////////[19] struct sifcmd_RPC_DATA_QUEUE *SifRemoveRpcQueue(struct sifcmd_RPC_DATA_QUEUE *qd){ u32 x; register struct sifcmd_RPC_DATA_QUEUE *q; CpuSuspendIntr(&x); q=rpc_common.queue; if (q==qd) { rpc_common.queue=q->next; } else { for (; q; q=q->next) { if (q->next==qd){ q->next=q->next->next; break; } } } CpuResumeIntr(x); return q; } ///////////////////////////////////////////////////////////////////////[14] struct sifcmd_RPC_SERVER_DATA *SifGetNextRequest(struct sifcmd_RPC_DATA_QUEUE *qd){ u32 x; register struct sifcmd_RPC_SERVER_DATA *s; CpuSuspendIntr(&x); if ((s=qd->start)==0) qd->active=0; else{ qd->active=1; qd->start=qd->start->next; } CpuResumeIntr(x); return s; } ///////////////////////////////////////////////////////////////////////[15] void SifExecRequest(struct sifcmd_RPC_SERVER_DATA *sd){ u32 x; register int size, id, count, i; register void *buff; RPC_PACKET_END *epacket; struct sifman_DMA dma[2]; size=0; if (buff=sd->func(sd->fno, sd->buff, sd->size)) size=sd->rsize; CpuSuspendIntr(&x); epacket=(RPC_PACKET_END *)rpc_get_fpacket(&rpc_common); CpuResumeIntr(x); epacket->command=0x8000000A; epacket->client=sd->client; count=0; if (sd->rmode){ while (SifSendCmd(0x80000008, epacket, 0x40, buff, sd->receive, size)==0); return; }else{ epacket->packet.pid=0; epacket->packet.rec_id=0; if (size>0){ count=1; dma[count-1].data=buff; dma[count-1].size=size; dma[count-1].attr=0; dma[count-1].addr=sd->receive; } count++; dma[count-1].data=epacket; dma[count-1].size=0x40; dma[count-1].attr=0; dma[count-1].addr=sd->pkt_addr; do{ CpuSuspendIntr(&x); id=SifSetDma(dma, count); CpuResumeIntr(x); if (id) break; i=0xFFFF; do --i; while (i!=-1); } while (id==0); } } ///////////////////////////////////////////////////////////////////////[16] void SifRpcLoop(struct sifcmd_RPC_DATA_QUEUE *qd){ register struct sifcmd_RPC_SERVER_DATA *s; do{ if (s=SifGetNextRequest(qd)) SifExecRequest(s); else SleepThread(); } while (1); } ///////////////////////////////////////////////////////////////////////[0E] void SifInitRpc(int mode){ u32 x; _dprintf("%s\n", __FUNCTION__); SifInitCmd(); CpuSuspendIntr(&x); if (sifInitRpc){ CpuResumeIntr(x); }else{ sifInitRpc=1; rpc_common.paddr=(RPC_PACKET*)bufx; rpc_common.size=32; rpc_common.paddr2=0; rpc_common.size2=0; rpc_common.next=(RPC_PACKET*)bufy; rpc_common.count=32; rpc_common.base=0; rpc_common.pid=1; SifAddCmdHandler(0x80000008, (cmdh_func)cmd80000008_END, &rpc_common); SifAddCmdHandler(0x80000009, (cmdh_func)cmd80000009_BIND, &rpc_common); SifAddCmdHandler(0x8000000A, (cmdh_func)cmd8000000A_CALL, &rpc_common); SifAddCmdHandler(0x8000000C, (cmdh_func)cmd8000000C_RDATA, &rpc_common); CpuResumeIntr(x); ((SifCmdSRData*)bufx)->rno =0; ((SifCmdSRData*)bufx)->value=1; SifSendCmd(0x80000001, (void*)bufx, sizeof(SifCmdSRData), 0, 0, 0); } WaitEventFlag(GetSystemStatusFlag(), 0x800, 0, 0); } void _retonly() {} struct export sifcmd_stub={ 0x41C00000, 0, VER(1, 1), // 1.1 => 0x101 0, "sifcmd", (func)_start, // entrypoint (func)_retonly, (func)SifDeinitCmd, (func)_retonly, (func)SifInitCmd, (func)SifExitCmd, (func)SifGetSreg, (func)SifSetSreg, (func)SifSetCmdBuffer, (func)SifSetSysCmdBuffer, (func)SifAddCmdHandler, (func)SifRemoveCmdHandler, (func)SifSendCmd, (func)iSifSendCmd, (func)SifInitRpc, (func)SifBindRpc, (func)SifCallRpc, (func)SifRegisterRpc, (func)SifCheckStatRpc, (func)SifSetRpcQueue, (func)SifGetNextRequest, (func)SifExecRequest, (func)SifRpcLoop, (func)SifGetOtherData, (func)SifRemoveRpc, (func)SifRemoveRpcQueue, (func)SifSet1CB, (func)SifReset1CB, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, 0 }; //////////////////////////////entrypoint///////////////////////////////[00] int _start(){ register int *v, i; _dprintf("%s\n", __FUNCTION__); if (v=QueryBootMode(3)){ _dprintf("bootmode: %x\n", v[1]); if (v[1] & 1){ printf("%s No SIF service(sifcmd)\n", __FUNCTION__);return 1;} if (v[1] & 2){ printf("%s No SIFCMD/RPC service\n", __FUNCTION__); return 1;} } if (SifCheckInit()==0) SifInit(); if (RegisterLibraryEntries(&sifcmd_stub)) return 1; cmd_common.sif1_rcvBuffer=sif1_rcvBuffer; cmd_common.b=b; cmd_common.sysCmdBuffer=sysCmds; cmd_common.sysCmdBufferSize=32; cmd_common.saddr=0; cmd_common.cmdBuffer=0; cmd_common.cmdBufferSize=0; cmd_common.Sreg=Sreg; cmd_common.func=0; cmd_common.param=0; for (i=0; i<32; i++) { sysCmds[i].func=0; sysCmds[i].data=0; } for (i=0; i<32; i++) { Sreg[i]=0; } sysCmds[0].func=(cmdh_func)cmd80000000_CHANGE_SADDR; sysCmds[0].data=&cmd_common; sysCmds[1].func=(cmdh_func)cmd80000001_SET_SREG; sysCmds[1].data=&cmd_common; cmd_common.systemStatusFlag=GetSystemStatusFlag(); sysCmds[2].func=(cmdh_func)cmd80000002_INIT_CMD; sysCmds[2].data=&cmd_common; RegisterIntrHandler(INT_DMA10, 1, SIF1_handler, (void*)&cmd_common); EnableIntr(INT_DMA10 | IMODE_DMA_IQE); SifSetIOPrcvaddr((u32)sif1_rcvBuffer); return 0; }