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 
25 #define RPC_PACKET_SIZE 64
26 
28 #define PACKET_F_ALLOC 0x01
29 
30 static inline void rpc_packet_free(void *packet)
31 {
32  SifRpcRendPkt_t *rendpkt = (SifRpcRendPkt_t *)packet;
33 
34  rendpkt->rpc_id = 0;
35  rendpkt->rec_id &= (~PACKET_F_ALLOC);
36 }
37 
38 struct rpc_data
39 {
40  int pid;
41  void *pkt_table;
42  int pkt_table_len;
43  int unused1;
44  int unused2;
45  u8 *rdata_table;
46  int rdata_table_len;
47  u8 *client_table;
48  int client_table_len;
49  int rdata_table_idx;
50  void *active_queue;
51 } __attribute__((aligned(64)));
52 
53 extern int _iop_reboot_count;
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[2048] __attribute__((aligned(64)));
281 /* A ring buffer used to allocate packets sent on IOP requests. */
282 static u8 rdata_table[2048] __attribute__((aligned(64)));
283 static u8 client_table[2048] __attribute__((aligned(64)));
284 
285 struct rpc_data _sif_rpc_data = {
286  pid : 1,
287  pkt_table : pkt_table,
288  pkt_table_len : sizeof(pkt_table) / RPC_PACKET_SIZE,
289  rdata_table : rdata_table,
290  rdata_table_len : sizeof(rdata_table) / RPC_PACKET_SIZE,
291  client_table : client_table,
292  client_table_len : sizeof(client_table) / RPC_PACKET_SIZE,
293  rdata_table_idx : 0
294 };
295 
296 static int init = 0;
297 
298 
299 /* Command 0x80000008 */
300 static void _request_end(SifRpcRendPkt_t *request, void *data)
301 {
302  SifRpcClientData_t *cd = request->cd;
303 
304  (void)data;
305 
306  if (request->cid == SIF_CMD_RPC_CALL) {
307  if (cd->end_function)
308  cd->end_function(cd->end_param);
309  } else if (request->cid == SIF_CMD_RPC_BIND) {
310  cd->server = request->sd;
311  cd->buf = request->buf;
312  cd->cbuf = request->cbuf;
313  }
314 
315  if (cd->hdr.sema_id >= 0)
316  iSignalSema(cd->hdr.sema_id);
317 
318  rpc_packet_free(cd->hdr.pkt_addr);
319  cd->hdr.pkt_addr = NULL;
320 }
321 
322 static void *search_svdata(u32 sid, struct rpc_data *rpc_data)
323 {
324  SifRpcServerData_t *sd;
325  SifRpcDataQueue_t *queue = rpc_data->active_queue;
326 
327  if (!queue)
328  return NULL;
329 
330  while (queue) {
331  sd = queue->link;
332  while (sd) {
333  if ((u32)(sd->sid) == sid)
334  return sd;
335 
336  sd = sd->link;
337  }
338 
339  queue = queue->next;
340  }
341 
342  return NULL;
343 }
344 
345 /* Command 0x80000009 */
346 static void _request_bind(SifRpcBindPkt_t *bind, void *data)
347 {
348  SifRpcRendPkt_t *rend;
349  SifRpcServerData_t *sd;
350 
351  rend = _rpc_get_fpacket(data);
352  rend->pkt_addr = bind->pkt_addr;
353  rend->cd = bind->cd;
354  rend->cid = SIF_CMD_RPC_BIND;
355 
356  sd = search_svdata(bind->sid, data);
357  if (!sd) {
358  rend->sd = NULL;
359  rend->buf = NULL;
360  rend->cbuf = NULL;
361  } else {
362  rend->sd = sd;
363  rend->buf = sd->buf;
364  rend->cbuf = sd->cbuf;
365  }
366 
367  isceSifSendCmd(SIF_CMD_RPC_END, rend, RPC_PACKET_SIZE, NULL, NULL, 0);
368 }
369 
370 /* Command 0x8000000a */
371 static void _request_call(SifRpcCallPkt_t *request, void *data)
372 {
373  SifRpcServerData_t *sd = request->sd;
374  SifRpcDataQueue_t *base = sd->base;
375 
376  (void)data;
377 
378  if (base->start)
379  base->end->next = sd;
380  else
381  base->start = sd;
382 
383  base->end = sd;
384  sd->pkt_addr = request->pkt_addr;
385  sd->client = request->cd;
386  sd->rpc_number = request->rpc_number;
387  sd->size = request->send_size;
388  sd->recvbuf = request->recvbuf;
389  sd->rsize = request->recv_size;
390  sd->rmode = request->rmode;
391  sd->rid = request->rec_id;
392 
393  if (base->thread_id < 0 || base->active != 0)
394  return;
395 
396  iWakeupThread(base->thread_id);
397 }
398 
399 /* Command 0x8000000c */
400 static void _request_rdata(SifRpcOtherDataPkt_t *rdata, void *data)
401 {
402  SifRpcRendPkt_t *rend;
403 
404  rend = (SifRpcRendPkt_t *)_rpc_get_fpacket(data);
405  rend->pkt_addr = rdata->pkt_addr;
406  rend->cd = (SifRpcClientData_t *)rdata->recvbuf;
407  rend->cid = SIF_CMD_RPC_RDATA;
408 
409  isceSifSendCmd(SIF_CMD_RPC_END, rend, RPC_PACKET_SIZE, rdata->src, rdata->dest, rdata->size);
410 }
411 
412 void sceSifInitRpc(int mode)
413 {
414  u32 *cmdp;
415 
416  (void)mode;
417 
418  static int _rb_count = 0;
419  if (_rb_count != _iop_reboot_count) {
420  _rb_count = _iop_reboot_count;
421  sceSifExitCmd();
422  init = 0;
423  }
424 
425  if (init)
426  return;
427  init = 1;
428 
429  sceSifInitCmd();
430 
431  DI();
432  _sif_rpc_data.pkt_table = UNCACHED_SEG(_sif_rpc_data.pkt_table);
433  _sif_rpc_data.rdata_table = UNCACHED_SEG(_sif_rpc_data.rdata_table);
434  _sif_rpc_data.client_table = UNCACHED_SEG(_sif_rpc_data.client_table);
435 
436  _sif_rpc_data.rdata_table_idx = 0;
437  struct rpc_data *rpc_data = (struct rpc_data *)(&_sif_rpc_data);
438 
439  int len = rpc_data->pkt_table_len;
440  if (len > 0) {
441  int rid;
442  SifRpcPktHeader_t *packet = (SifRpcPktHeader_t *)rpc_data->pkt_table;
443 
444  for (rid = 0; rid < len; rid++, packet = (SifRpcPktHeader_t *)(((unsigned char *)packet) + RPC_PACKET_SIZE)) {
445  rpc_packet_free(packet);
446  }
447  }
448 
449  sceSifAddCmdHandler(SIF_CMD_RPC_END, (void *)_request_end, &_sif_rpc_data);
450  sceSifAddCmdHandler(SIF_CMD_RPC_BIND, (void *)_request_bind, &_sif_rpc_data);
451  sceSifAddCmdHandler(SIF_CMD_RPC_CALL, (void *)_request_call, &_sif_rpc_data);
452  sceSifAddCmdHandler(SIF_CMD_RPC_RDATA, (void *)_request_rdata, &_sif_rpc_data);
453  EI();
454 
455  if (sceSifGetReg(SIF_SYSREG_RPCINIT))
456  return;
457 
458  cmdp = (u32 *)&pkt_table[64];
459  cmdp[3] = 1;
460  sceSifSendCmd(SIF_CMD_INIT_CMD, cmdp, 16, NULL, NULL, 0);
461 
462  while (!sceSifGetSreg(SIF_SREG_RPCINIT))
463  ;
464  sceSifSetReg(SIF_SYSREG_RPCINIT, 1);
465 }
466 
467 void sceSifExitRpc(void)
468 {
469  sceSifExitCmd();
470  init = 0;
471 }
472 #endif
473 
474 #ifdef F_sceSifRegisterRpc
475 void sceSifRegisterRpc(SifRpcServerData_t *sd, int sid, SifRpcFunc_t func, void *buf,
476  SifRpcFunc_t cfunc, void *cbuf, SifRpcDataQueue_t *qd)
477 {
478  SifRpcServerData_t *server;
479 
480  DI();
481 
482  sd->link = NULL;
483  sd->next = NULL;
484  sd->sid = sid;
485  sd->func = func;
486  sd->buf = buf;
487  sd->cfunc = cfunc;
488  sd->cbuf = cbuf;
489  sd->base = qd;
490 
491  if (!(server = qd->link)) {
492  qd->link = sd;
493  } else {
494  while (server->link != NULL) {
495  server = server->link;
496  }
497 
498  server->link = sd;
499  }
500 
501  EI();
502 }
503 #endif
504 
505 #ifdef F_sceSifRemoveRpc
507 {
508  SifRpcServerData_t *server;
509 
510  DI();
511 
512  if ((server = qd->link) == sd) {
513  qd->link = server->link;
514  } else {
515  while (server != NULL) {
516  if (server->link == sd) {
517  server->link = sd->link;
518  break;
519  }
520 
521  server = server->link;
522  }
523  }
524 
525  EI();
526 
527  return server;
528 }
529 #endif
530 
531 #ifdef F_sceSifSetRpcQueue
532 void sceSifSetRpcQueue(SifRpcDataQueue_t *qd, int thread_id)
533 {
534  SifRpcDataQueue_t *queue = NULL;
535 
536  DI();
537 
538  qd->thread_id = thread_id;
539  qd->active = 0;
540  qd->link = NULL;
541  qd->start = NULL;
542  qd->end = NULL;
543  qd->next = NULL;
544 
545  if (_sif_rpc_data.active_queue == NULL) {
546  _sif_rpc_data.active_queue = qd;
547  } else {
548  queue = _sif_rpc_data.active_queue;
549 
550  while (queue->next != NULL)
551  queue = queue->next;
552 
553  queue->next = qd;
554  }
555 
556  EI();
557 }
558 #endif
559 
560 #ifdef F_sceSifRemoveRpcQueue
561 SifRpcDataQueue_t *sceSifRemoveRpcQueue(SifRpcDataQueue_t *qd)
562 {
563  SifRpcDataQueue_t *queue;
564 
565  DI();
566 
567  if ((queue = _sif_rpc_data.active_queue) == qd) {
568  _sif_rpc_data.active_queue = queue->next;
569  } else {
570  while (queue != NULL) {
571  if (queue->next == qd) {
572  queue->next = qd->next;
573  break;
574  }
575 
576  queue = queue->next;
577  }
578  }
579 
580  EI();
581 
582  return queue;
583 }
584 #endif
585 
586 #ifdef F_sceSifGetNextRequest
587 SifRpcServerData_t *sceSifGetNextRequest(SifRpcDataQueue_t *qd)
588 {
589  SifRpcServerData_t *sd;
590 
591  DI();
592 
593  sd = qd->start;
594  if (sd != NULL) {
595  qd->active = 1;
596  qd->start = sd->next;
597  } else {
598  qd->active = 0;
599  }
600 
601  EI();
602 
603  return sd;
604 }
605 #endif
606 
607 #ifdef F_sceSifExecRequest
608 static void *_rpc_get_fpacket2(struct rpc_data *rpc_data, int rid)
609 {
610  if (rid < 0 || rid < rpc_data->client_table_len)
611  return _rpc_get_fpacket(rpc_data);
612  else
613  return rpc_data->client_table + (rid * RPC_PACKET_SIZE);
614 }
615 void sceSifExecRequest(SifRpcServerData_t *sd)
616 {
617  SifDmaTransfer_t dmat;
618  SifRpcRendPkt_t *rend;
619  void *rec = NULL;
620 
621  rec = sd->func(sd->rpc_number, sd->buf, sd->size);
622 
623  if (sd->size)
624  sceSifWriteBackDCache(sd->buf, sd->size);
625 
626  if (sd->rsize)
627  sceSifWriteBackDCache(rec, sd->rsize);
628 
629  DI();
630 
631  if (sd->rid & 4)
632  rend = (SifRpcRendPkt_t *)
633  _rpc_get_fpacket2(&_sif_rpc_data, (sd->rid >> 16) & 0xffff);
634  else
635  rend = (SifRpcRendPkt_t *)
636  _rpc_get_fpacket(&_sif_rpc_data);
637 
638  EI();
639 
640  rend->cd = sd->client;
641  rend->cid = SIF_CMD_RPC_CALL;
642 
643  if (sd->rmode) {
644  if (!sceSifSendCmd(SIF_CMD_RPC_END, rend, RPC_PACKET_SIZE, rec, sd->recvbuf,
645  sd->rsize))
646  return;
647  }
648 
649  rend->rpc_id = 0;
650  rend->rec_id = 0;
651 
652  if (sd->rsize) {
653  dmat.src = rec;
654  dmat.dest = sd->recvbuf;
655  dmat.size = sd->rsize;
656  dmat.attr = 0;
657  } else {
658  dmat.src = rend;
659  dmat.dest = sd->pkt_addr;
660  dmat.size = 64;
661  dmat.attr = 0;
662  }
663 
664  while (!sceSifSetDma(&dmat, 1))
665  nopdelay();
666 }
667 #endif
668 
669 #ifdef F_sceSifRpcLoop
670 void sceSifRpcLoop(SifRpcDataQueue_t *qd)
671 {
672  while (1) {
673  SifRpcServerData_t *sd;
674 
675  while ((sd = sceSifGetNextRequest(qd)))
676  sceSifExecRequest(sd);
677 
678  SleepThread();
679  }
680 }
681 #endif
682 
683 #ifdef F_sceSifCheckStatRpc
684 int sceSifCheckStatRpc(SifRpcClientData_t *cd)
685 {
686  SifRpcPktHeader_t *packet = (SifRpcPktHeader_t *)cd->hdr.pkt_addr;
687 
688  if (!packet)
689  return 0;
690 
691  if (cd->hdr.rpc_id != (u32)(packet->rpc_id))
692  return 0;
693 
694  if (!(packet->rec_id & PACKET_F_ALLOC))
695  return 0;
696 
697  return 1;
698 }
699 #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:28
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
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
_iop_reboot_count
int _iop_reboot_count
tamtypes.h
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:38
__attribute__
Definition: gif_registers.h:38
t_SifRpcCallPkt
Definition: sifrpc-common.h:83