PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
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
30static 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
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
53extern int _iop_reboot_count;
54extern struct rpc_data _sif_rpc_data;
55
56void *_rpc_get_packet(struct rpc_data *rpc_data);
57void *_rpc_get_fpacket(struct rpc_data *rpc_data);
58
59#ifdef F__rpc_get_packet
60void *_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
101void *_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
113int 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
163int 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
229int sceSifGetOtherData(SifRpcReceiveData_t *rd, void *src, void *dest, int size, int mode)
230{
231 ee_sema_t sema;
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. */
280static u8 pkt_table[2048] __attribute__((aligned(64)));
281/* A ring buffer used to allocate packets sent on IOP requests. */
282static u8 rdata_table[2048] __attribute__((aligned(64)));
283static u8 client_table[2048] __attribute__((aligned(64)));
284
285struct 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
296static int init = 0;
297
298
299/* Command 0x80000008 */
300static 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
322static void *search_svdata(u32 sid, struct rpc_data *rpc_data)
323{
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 */
346static void _request_bind(SifRpcBindPkt_t *bind, void *data)
347{
348 SifRpcRendPkt_t *rend;
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 */
371static 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 */
400static 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
412void 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
467void sceSifExitRpc(void)
468{
469 sceSifExitCmd();
470 init = 0;
471}
472#endif
473
474#ifdef F_sceSifRegisterRpc
475void 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
532void 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
561SifRpcDataQueue_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
587SifRpcServerData_t *sceSifGetNextRequest(SifRpcDataQueue_t *qd)
588{
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
608static 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}
615void 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
670void sceSifRpcLoop(SifRpcDataQueue_t *qd)
671{
672 while (1) {
674
675 while ((sd = sceSifGetNextRequest(qd)))
676 sceSifExecRequest(sd);
677
678 SleepThread();
679 }
680}
681#endif
682
683#ifdef F_sceSifCheckStatRpc
684int 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
#define PACKET_F_ALLOC
Definition sifrpc.c:28
typedef __attribute__
Definition tlbfunc.c:60
@ E_SIF_PKT_SEND
Definition ps2lib_err.h:84
@ E_SIF_PKT_ALLOC
Definition ps2lib_err.h:82
@ E_LIB_SEMA_CREATE
Definition ps2lib_err.h:70
#define SIF_SREG_RPCINIT
#define SIF_RPC_M_NOWAIT
#define SIF_RPC_M_NOWBDC