PS2SDK
PS2 Homebrew Libraries
sifrpc.c
Go to the documentation of this file.
1 /*
2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # (C)2001, Gustavo Scotti (gustavo@scotti.com)
7 # (c) 2003 Marcus R. Brown (mrbrown@0xd6.org)
8 # Licenced under Academic Free License version 2.0
9 # Review ps2sdk README & LICENSE files for further details.
10 */
11 
19 #include <tamtypes.h>
20 #include <ps2lib_err.h>
21 #include <kernel.h>
22 #include <sifcmd.h>
23 #include <sifrpc.h>
24 #include <iopcontrol.h>
25 
26 #define RPC_PACKET_SIZE 64
27 
29 #define PACKET_F_ALLOC 0x01
30 
31 static inline void rpc_packet_free(void *packet)
32 {
33  SifRpcRendPkt_t *rendpkt = (SifRpcRendPkt_t *)packet;
34 
35  rendpkt->rpc_id = 0;
36  rendpkt->rec_id &= (~PACKET_F_ALLOC);
37 }
38 
39 struct rpc_data
40 {
41  int pid;
42  void *pkt_table;
43  int pkt_table_len;
44  int unused1;
45  int unused2;
46  u8 *rdata_table;
47  int rdata_table_len;
48  u8 *client_table;
49  int client_table_len;
50  int rdata_table_idx;
51  void *active_queue;
52 } __attribute__((aligned(64)));
53 
54 extern struct rpc_data _sif_rpc_data;
55 
56 void *_rpc_get_packet(struct rpc_data *rpc_data);
57 void *_rpc_get_fpacket(struct rpc_data *rpc_data);
58 
59 #ifdef F__rpc_get_packet
60 void *_rpc_get_packet(struct rpc_data *rpc_data)
61 {
62  SifRpcPktHeader_t *packet;
63  int len;
64 
65  DI();
66 
67  len = rpc_data->pkt_table_len;
68  if (len > 0) {
69  int pid, rid;
70  packet = (SifRpcPktHeader_t *)rpc_data->pkt_table;
71 
72  for (rid = 0; rid < len; rid++, packet = (SifRpcPktHeader_t *)(((unsigned char *)packet) + RPC_PACKET_SIZE)) {
73  if (!(packet->rec_id & PACKET_F_ALLOC))
74  break;
75  }
76  if (rid == len) {
77  EI();
78  return NULL;
79  }
80 
81  pid = rpc_data->pid;
82  if (pid) {
83  rpc_data->pid = ++pid;
84  } else {
85  rpc_data->pid = pid + 2;
86  pid = 1;
87  }
88 
89  packet->rec_id = (rid << 16) | 0x04 | PACKET_F_ALLOC;
90  packet->rpc_id = pid;
91  packet->pkt_addr = packet;
92  EI();
93  return packet;
94  }
95  EI();
96  return NULL;
97 }
98 #endif
99 
100 #ifdef F__rpc_get_fpacket
101 void *_rpc_get_fpacket(struct rpc_data *rpc_data)
102 {
103  int index;
104 
105  index = rpc_data->rdata_table_idx % rpc_data->rdata_table_len;
106  rpc_data->rdata_table_idx = index + 1;
107 
108  return (void *)(rpc_data->rdata_table + (index * RPC_PACKET_SIZE));
109 }
110 #endif
111 
112 #ifdef F_sceSifBindRpc
113 int sceSifBindRpc(SifRpcClientData_t *cd, int sid, int mode)
114 {
115  ee_sema_t sema;
116  SifRpcBindPkt_t *bind;
117 
118  bind = (SifRpcBindPkt_t *)_rpc_get_packet(&_sif_rpc_data);
119  if (!bind)
120  return -E_SIF_PKT_ALLOC;
121 
122  cd->command = 0;
123  cd->server = NULL;
124  cd->hdr.pkt_addr = bind;
125  cd->hdr.rpc_id = bind->rpc_id;
126  cd->hdr.sema_id = -1;
127 
128  bind->sid = sid;
129  bind->pkt_addr = bind;
130  bind->cd = cd;
131 
132  if (mode & SIF_RPC_M_NOWAIT) {
133  if (!sceSifSendCmd(SIF_CMD_RPC_BIND, bind, RPC_PACKET_SIZE, NULL, NULL, 0)) {
134  rpc_packet_free(bind);
135  return -E_SIF_PKT_SEND;
136  }
137 
138  return 0;
139  }
140 
141  sema.max_count = 1;
142  sema.init_count = 0;
143  cd->hdr.sema_id = CreateSema(&sema);
144  if (cd->hdr.sema_id < 0) {
145  rpc_packet_free(bind);
146  return -E_LIB_SEMA_CREATE;
147  }
148 
149  if (!sceSifSendCmd(SIF_CMD_RPC_BIND, bind, RPC_PACKET_SIZE, NULL, NULL, 0)) {
150  rpc_packet_free(bind);
151  DeleteSema(cd->hdr.sema_id);
152  return -E_SIF_PKT_SEND;
153  }
154 
155  WaitSema(cd->hdr.sema_id);
156  DeleteSema(cd->hdr.sema_id);
157 
158  return 0;
159 }
160 #endif
161 
162 #ifdef F_sceSifCallRpc
163 int sceSifCallRpc(SifRpcClientData_t *cd, int rpc_number, int mode, void *sendbuf,
164  int ssize, void *recvbuf, int rsize, SifRpcEndFunc_t end_function, void *end_param)
165 {
166  ee_sema_t sema;
167  SifRpcCallPkt_t *call;
168 
169  call = (SifRpcCallPkt_t *)_rpc_get_packet(&_sif_rpc_data);
170  if (!call)
171  return -E_SIF_PKT_ALLOC;
172 
173  cd->hdr.pkt_addr = call;
174  cd->hdr.rpc_id = call->rpc_id;
175  cd->hdr.sema_id = -1;
176  cd->end_function = end_function;
177  cd->end_param = end_param;
178 
179  call->rpc_number = rpc_number;
180  call->send_size = ssize;
181  call->recvbuf = recvbuf;
182  call->recv_size = rsize;
183  call->rmode = 1;
184  call->pkt_addr = call;
185  call->cd = cd;
186  call->sd = cd->server;
187 
188  if (!(mode & SIF_RPC_M_NOWBDC)) {
189  if (ssize > 0)
190  sceSifWriteBackDCache(sendbuf, ssize);
191  if (rsize > 0)
192  sceSifWriteBackDCache(recvbuf, rsize);
193  }
194 
195  if (mode & SIF_RPC_M_NOWAIT) {
196  if (!end_function)
197  call->rmode = 0;
198 
199  if (!sceSifSendCmd(SIF_CMD_RPC_CALL, call, RPC_PACKET_SIZE, sendbuf, cd->buf, ssize)) {
200  rpc_packet_free(call);
201  return -E_SIF_PKT_SEND;
202  }
203 
204  return 0;
205  }
206 
207  sema.max_count = 1;
208  sema.init_count = 0;
209  cd->hdr.sema_id = CreateSema(&sema);
210  if (cd->hdr.sema_id < 0) {
211  rpc_packet_free(call);
212  return -E_LIB_SEMA_CREATE;
213  }
214 
215  if (!sceSifSendCmd(SIF_CMD_RPC_CALL, call, RPC_PACKET_SIZE, sendbuf, cd->buf, ssize)) {
216  rpc_packet_free(call);
217  DeleteSema(cd->hdr.sema_id);
218  return -E_SIF_PKT_SEND;
219  }
220 
221  WaitSema(cd->hdr.sema_id);
222  DeleteSema(cd->hdr.sema_id);
223 
224  return 0;
225 }
226 #endif
227 
228 #ifdef F_sceSifGetOtherData
229 int sceSifGetOtherData(SifRpcReceiveData_t *rd, void *src, void *dest, int size, int mode)
230 {
231  ee_sema_t sema;
232  SifRpcOtherDataPkt_t *other;
233 
234  other = (SifRpcOtherDataPkt_t *)_rpc_get_packet(&_sif_rpc_data);
235  if (!other)
236  return -E_SIF_PKT_ALLOC;
237 
238  rd->hdr.pkt_addr = other;
239  rd->hdr.rpc_id = other->rpc_id;
240  rd->hdr.sema_id = -1;
241 
242  other->src = src;
243  other->dest = dest;
244  other->size = size;
245  other->recvbuf = rd;
246 
247  if (mode & SIF_RPC_M_NOWAIT) {
248  if (!sceSifSendCmd(SIF_CMD_RPC_RDATA, other, RPC_PACKET_SIZE, NULL, NULL, 0)) {
249  rpc_packet_free(other);
250  return -E_SIF_PKT_SEND;
251  }
252 
253  return 0;
254  }
255 
256  sema.max_count = 1;
257  sema.init_count = 0;
258  rd->hdr.sema_id = CreateSema(&sema);
259  if (rd->hdr.sema_id < 0) {
260  rpc_packet_free(other);
261  return -E_LIB_SEMA_CREATE;
262  }
263 
264  if (!sceSifSendCmd(SIF_CMD_RPC_RDATA, other, RPC_PACKET_SIZE, NULL, NULL, 0)) {
265  rpc_packet_free(other);
266  DeleteSema(rd->hdr.sema_id);
267  return -E_SIF_PKT_SEND;
268  }
269 
270  WaitSema(rd->hdr.sema_id);
271  DeleteSema(rd->hdr.sema_id);
272 
273  return 0;
274 }
275 #endif
276 
277 #ifdef F_SifRpcMain
278 
279 /* The packets sent on EE RPC requests are allocated from this table. */
280 static u8 pkt_table[32][RPC_PACKET_SIZE] __attribute__((aligned(64)));
281 /* A ring buffer used to allocate packets sent on IOP requests. */
282 static u8 rdata_table[32][RPC_PACKET_SIZE] __attribute__((aligned(64)));
283 static u8 client_table[32][RPC_PACKET_SIZE] __attribute__((aligned(64)));
284 
285 struct rpc_data _sif_rpc_data;
286 
287 static int init = 0;
288 
289 
290 /* Command 0x80000008 */
291 static void _request_end(SifRpcRendPkt_t *request, void *data)
292 {
293  SifRpcClientData_t *cd = request->cd;
294 
295  (void)data;
296 
297  if (request->cid == SIF_CMD_RPC_CALL) {
298  if (cd->end_function)
299  cd->end_function(cd->end_param);
300  } else if (request->cid == SIF_CMD_RPC_BIND) {
301  cd->server = request->sd;
302  cd->buf = request->buf;
303  cd->cbuf = request->cbuf;
304  }
305 
306  if (cd->hdr.sema_id >= 0)
307  iSignalSema(cd->hdr.sema_id);
308 
309  rpc_packet_free(cd->hdr.pkt_addr);
310  cd->hdr.pkt_addr = NULL;
311 }
312 
313 static void *search_svdata(u32 sid, struct rpc_data *rpc_data)
314 {
315  SifRpcServerData_t *sd;
316  SifRpcDataQueue_t *queue = rpc_data->active_queue;
317 
318  if (!queue)
319  return NULL;
320 
321  while (queue) {
322  sd = queue->link;
323  while (sd) {
324  if ((u32)(sd->sid) == sid)
325  return sd;
326 
327  sd = sd->link;
328  }
329 
330  queue = queue->next;
331  }
332 
333  return NULL;
334 }
335 
336 /* Command 0x80000009 */
337 static void _request_bind(SifRpcBindPkt_t *bind, void *data)
338 {
339  SifRpcRendPkt_t *rend;
340  SifRpcServerData_t *sd;
341 
342  rend = _rpc_get_fpacket(data);
343  rend->pkt_addr = bind->pkt_addr;
344  rend->cd = bind->cd;
345  rend->cid = SIF_CMD_RPC_BIND;
346 
347  sd = search_svdata(bind->sid, data);
348  if (!sd) {
349  rend->sd = NULL;
350  rend->buf = NULL;
351  rend->cbuf = NULL;
352  } else {
353  rend->sd = sd;
354  rend->buf = sd->buf;
355  rend->cbuf = sd->cbuf;
356  }
357 
358  isceSifSendCmd(SIF_CMD_RPC_END, rend, RPC_PACKET_SIZE, NULL, NULL, 0);
359 }
360 
361 /* Command 0x8000000a */
362 static void _request_call(SifRpcCallPkt_t *request, void *data)
363 {
364  SifRpcServerData_t *sd = request->sd;
365  SifRpcDataQueue_t *base = sd->base;
366 
367  (void)data;
368 
369  if (base->start)
370  base->end->next = sd;
371  else
372  base->start = sd;
373 
374  base->end = sd;
375  sd->pkt_addr = request->pkt_addr;
376  sd->client = request->cd;
377  sd->rpc_number = request->rpc_number;
378  sd->size = request->send_size;
379  sd->recvbuf = request->recvbuf;
380  sd->rsize = request->recv_size;
381  sd->rmode = request->rmode;
382  sd->rid = request->rec_id;
383 
384  if (base->thread_id < 0 || base->active != 0)
385  return;
386 
387  iWakeupThread(base->thread_id);
388 }
389 
390 /* Command 0x8000000c */
391 static void _request_rdata(SifRpcOtherDataPkt_t *rdata, void *data)
392 {
393  SifRpcRendPkt_t *rend;
394 
395  rend = (SifRpcRendPkt_t *)_rpc_get_fpacket(data);
396  rend->pkt_addr = rdata->pkt_addr;
397  rend->cd = (SifRpcClientData_t *)rdata->recvbuf;
398  rend->cid = SIF_CMD_RPC_RDATA;
399 
400  isceSifSendCmd(SIF_CMD_RPC_END, rend, RPC_PACKET_SIZE, rdata->src, rdata->dest, rdata->size);
401 }
402 
403 void sceSifInitRpc(int mode)
404 {
405  u32 *cmdp;
406 
407  (void)mode;
408 
410  sceSifExitCmd();
411  init = 0;
412  }
413  if (init)
414  return;
415  init = 1;
416 
417  sceSifInitCmd();
418 
419  DI();
420  _sif_rpc_data.pid = 1;
421 
422  _sif_rpc_data.pkt_table = UNCACHED_SEG(pkt_table);
423  _sif_rpc_data.pkt_table_len = sizeof(pkt_table) / sizeof(pkt_table[0]);
424  _sif_rpc_data.rdata_table = UNCACHED_SEG(rdata_table);
425  _sif_rpc_data.rdata_table_len = sizeof(rdata_table) / sizeof(rdata_table[0]);
426  _sif_rpc_data.client_table = UNCACHED_SEG(client_table);
427  _sif_rpc_data.client_table_len = sizeof(client_table) / sizeof(client_table[0]);
428 
429  _sif_rpc_data.rdata_table_idx = 0;
430  struct rpc_data *rpc_data = (struct rpc_data *)(&_sif_rpc_data);
431 
432  int len = rpc_data->pkt_table_len;
433  if (len > 0) {
434  int rid;
435  SifRpcPktHeader_t *packet = (SifRpcPktHeader_t *)rpc_data->pkt_table;
436 
437  for (rid = 0; rid < len; rid++, packet = (SifRpcPktHeader_t *)(((unsigned char *)packet) + RPC_PACKET_SIZE)) {
438  rpc_packet_free(packet);
439  }
440  }
441 
442  sceSifAddCmdHandler(SIF_CMD_RPC_END, (void *)_request_end, &_sif_rpc_data);
443  sceSifAddCmdHandler(SIF_CMD_RPC_BIND, (void *)_request_bind, &_sif_rpc_data);
444  sceSifAddCmdHandler(SIF_CMD_RPC_CALL, (void *)_request_call, &_sif_rpc_data);
445  sceSifAddCmdHandler(SIF_CMD_RPC_RDATA, (void *)_request_rdata, &_sif_rpc_data);
446  EI();
447 
448  if (sceSifGetReg(SIF_SYSREG_RPCINIT))
449  return;
450 
451  cmdp = (u32 *)&((u8 *)_sif_rpc_data.pkt_table)[64];
452  cmdp[3] = 1;
453  sceSifSendCmd(SIF_CMD_INIT_CMD, cmdp, 16, NULL, NULL, 0);
454 
455  while (!sceSifGetSreg(SIF_SREG_RPCINIT))
456  ;
457  sceSifSetReg(SIF_SYSREG_RPCINIT, 1);
458 }
459 
460 void sceSifExitRpc(void)
461 {
462  sceSifExitCmd();
463  init = 0;
464 }
465 #endif
466 
467 #ifdef F_sceSifRegisterRpc
468 void sceSifRegisterRpc(SifRpcServerData_t *sd, int sid, SifRpcFunc_t func, void *buf,
469  SifRpcFunc_t cfunc, void *cbuf, SifRpcDataQueue_t *qd)
470 {
471  SifRpcServerData_t *server;
472 
473  DI();
474 
475  sd->link = NULL;
476  sd->next = NULL;
477  sd->sid = sid;
478  sd->func = func;
479  sd->buf = buf;
480  sd->cfunc = cfunc;
481  sd->cbuf = cbuf;
482  sd->base = qd;
483 
484  if (!(server = qd->link)) {
485  qd->link = sd;
486  } else {
487  while (server->link != NULL) {
488  server = server->link;
489  }
490 
491  server->link = sd;
492  }
493 
494  EI();
495 }
496 #endif
497 
498 #ifdef F_sceSifRemoveRpc
500 {
501  SifRpcServerData_t *server;
502 
503  DI();
504 
505  if ((server = qd->link) == sd) {
506  qd->link = server->link;
507  } else {
508  while (server != NULL) {
509  if (server->link == sd) {
510  server->link = sd->link;
511  break;
512  }
513 
514  server = server->link;
515  }
516  }
517 
518  EI();
519 
520  return server;
521 }
522 #endif
523 
524 #ifdef F_sceSifSetRpcQueue
525 void sceSifSetRpcQueue(SifRpcDataQueue_t *qd, int thread_id)
526 {
527  SifRpcDataQueue_t *queue = NULL;
528 
529  DI();
530 
531  qd->thread_id = thread_id;
532  qd->active = 0;
533  qd->link = NULL;
534  qd->start = NULL;
535  qd->end = NULL;
536  qd->next = NULL;
537 
538  if (_sif_rpc_data.active_queue == NULL) {
539  _sif_rpc_data.active_queue = qd;
540  } else {
541  queue = _sif_rpc_data.active_queue;
542 
543  while (queue->next != NULL)
544  queue = queue->next;
545 
546  queue->next = qd;
547  }
548 
549  EI();
550 }
551 #endif
552 
553 #ifdef F_sceSifRemoveRpcQueue
554 SifRpcDataQueue_t *sceSifRemoveRpcQueue(SifRpcDataQueue_t *qd)
555 {
556  SifRpcDataQueue_t *queue;
557 
558  DI();
559 
560  if ((queue = _sif_rpc_data.active_queue) == qd) {
561  _sif_rpc_data.active_queue = queue->next;
562  } else {
563  while (queue != NULL) {
564  if (queue->next == qd) {
565  queue->next = qd->next;
566  break;
567  }
568 
569  queue = queue->next;
570  }
571  }
572 
573  EI();
574 
575  return queue;
576 }
577 #endif
578 
579 #ifdef F_sceSifGetNextRequest
580 SifRpcServerData_t *sceSifGetNextRequest(SifRpcDataQueue_t *qd)
581 {
582  SifRpcServerData_t *sd;
583 
584  DI();
585 
586  sd = qd->start;
587  if (sd != NULL) {
588  qd->active = 1;
589  qd->start = sd->next;
590  } else {
591  qd->active = 0;
592  }
593 
594  EI();
595 
596  return sd;
597 }
598 #endif
599 
600 #ifdef F_sceSifExecRequest
601 static void *_rpc_get_fpacket2(struct rpc_data *rpc_data, int rid)
602 {
603  if (rid < 0 || rid < rpc_data->client_table_len)
604  return _rpc_get_fpacket(rpc_data);
605  else
606  return rpc_data->client_table + (rid * RPC_PACKET_SIZE);
607 }
608 void sceSifExecRequest(SifRpcServerData_t *sd)
609 {
610  SifDmaTransfer_t dmat;
611  SifRpcRendPkt_t *rend;
612  void *rec = NULL;
613 
614  rec = sd->func(sd->rpc_number, sd->buf, sd->size);
615 
616  if (sd->size)
617  sceSifWriteBackDCache(sd->buf, sd->size);
618 
619  if (sd->rsize)
620  sceSifWriteBackDCache(rec, sd->rsize);
621 
622  DI();
623 
624  if (sd->rid & 4)
625  rend = (SifRpcRendPkt_t *)
626  _rpc_get_fpacket2(&_sif_rpc_data, (sd->rid >> 16) & 0xffff);
627  else
628  rend = (SifRpcRendPkt_t *)
629  _rpc_get_fpacket(&_sif_rpc_data);
630 
631  EI();
632 
633  rend->cd = sd->client;
634  rend->cid = SIF_CMD_RPC_CALL;
635 
636  if (sd->rmode) {
637  if (!sceSifSendCmd(SIF_CMD_RPC_END, rend, RPC_PACKET_SIZE, rec, sd->recvbuf,
638  sd->rsize))
639  return;
640  }
641 
642  rend->rpc_id = 0;
643  rend->rec_id = 0;
644 
645  if (sd->rsize) {
646  dmat.src = rec;
647  dmat.dest = sd->recvbuf;
648  dmat.size = sd->rsize;
649  dmat.attr = 0;
650  } else {
651  dmat.src = rend;
652  dmat.dest = sd->pkt_addr;
653  dmat.size = 64;
654  dmat.attr = 0;
655  }
656 
657  while (!sceSifSetDma(&dmat, 1))
658  nopdelay();
659 }
660 #endif
661 
662 #ifdef F_sceSifRpcLoop
663 void sceSifRpcLoop(SifRpcDataQueue_t *qd)
664 {
665  while (1) {
666  SifRpcServerData_t *sd;
667 
668  while ((sd = sceSifGetNextRequest(qd)))
669  sceSifExecRequest(sd);
670 
671  SleepThread();
672  }
673 }
674 #endif
675 
676 #ifdef F_sceSifCheckStatRpc
677 int sceSifCheckStatRpc(SifRpcClientData_t *cd)
678 {
679  SifRpcPktHeader_t *packet = (SifRpcPktHeader_t *)cd->hdr.pkt_addr;
680 
681  if (!packet)
682  return 0;
683 
684  if (cd->hdr.rpc_id != (u32)(packet->rpc_id))
685  return 0;
686 
687  if (!(packet->rec_id & PACKET_F_ALLOC))
688  return 0;
689 
690  return 1;
691 }
692 #endif
kernel.h
ps2lib_err.h
SIF_RPC_M_NOWAIT
#define SIF_RPC_M_NOWAIT
Definition: sifrpc-common.h:23
PACKET_F_ALLOC
#define PACKET_F_ALLOC
Definition: sifrpc.c:29
request
Definition: thread.c:17
t_SifRpcOtherDataPkt
Definition: sifrpc-common.h:60
SIF_RPC_M_NOWBDC
#define SIF_RPC_M_NOWBDC
Definition: sifrpc-common.h:25
t_SifRpcReceiveData
Definition: sifrpc-common.h:145
iopcontrol.h
E_LIB_SEMA_CREATE
@ E_LIB_SEMA_CREATE
Definition: ps2lib_err.h:70
t_ee_sema
Definition: kernel.h:193
SIF_SREG_RPCINIT
#define SIF_SREG_RPCINIT
Definition: sifcmd-common.h:49
t_SifRpcPktHeader
Definition: sifrpc-common.h:38
qd
static SifRpcDataQueue_t qd
Definition: rpc_server.c:33
t_SifRpcRendPkt
Definition: sifrpc-common.h:46
tamtypes.h
HasIopRebootedSinceLastCall
static int HasIopRebootedSinceLastCall(void)
Definition: iopcontrol.h:47
t_SifDmaTransfer
Definition: sifdma.h:52
t_SifRpcServerData
Definition: sifrpc-common.h:98
t_SifRpcDataQueue
Definition: sifrpc-common.h:153
t_SifRpcBindPkt
Definition: sifrpc-common.h:73
E_SIF_PKT_ALLOC
@ E_SIF_PKT_ALLOC
Definition: ps2lib_err.h:82
t_SifRpcClientData
Definition: sifrpc-common.h:134
E_SIF_PKT_SEND
@ E_SIF_PKT_SEND
Definition: ps2lib_err.h:84
rpc_data
Definition: sifrpc.c:39
__attribute__
Definition: gif_registers.h:38
t_SifRpcCallPkt
Definition: sifrpc-common.h:83