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};
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_SifBindRpc
113int SifBindRpc(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->client = cd;
131
132 if (mode & SIF_RPC_M_NOWAIT) {
133 if (!SifSendCmd(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 (!SifSendCmd(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_SifCallRpc
163int SifCallRpc(SifRpcClientData_t *cd, int rpc_number, int mode,
164 void *sendbuf, int ssize, void *recvbuf, int rsize,
165 SifRpcEndFunc_t endfunc, void *efarg)
166{
167 ee_sema_t sema;
168 SifRpcCallPkt_t *call;
169
170 call = (SifRpcCallPkt_t *)_rpc_get_packet(&_sif_rpc_data);
171 if (!call)
172 return -E_SIF_PKT_ALLOC;
173
174 cd->hdr.pkt_addr = call;
175 cd->hdr.rpc_id = call->rpc_id;
176 cd->hdr.sema_id = -1;
177 cd->end_function = endfunc;
178 cd->end_param = efarg;
179
180 call->rpc_number = rpc_number;
181 call->send_size = ssize;
182 call->receive = recvbuf;
183 call->recv_size = rsize;
184 call->rmode = 1;
185 call->pkt_addr = call;
186 call->client = cd;
187 call->server = cd->server;
188
189 if (!(mode & SIF_RPC_M_NOWBDC)) {
190 if (ssize > 0)
191 SifWriteBackDCache(sendbuf, ssize);
192 if (rsize > 0)
193 SifWriteBackDCache(recvbuf, rsize);
194 }
195
196 if (mode & SIF_RPC_M_NOWAIT) {
197 if (!endfunc)
198 call->rmode = 0;
199
200 if (!SifSendCmd(SIF_CMD_RPC_CALL, call, RPC_PACKET_SIZE, sendbuf, cd->buff, ssize)) {
201 rpc_packet_free(call);
202 return -E_SIF_PKT_SEND;
203 }
204
205 return 0;
206 }
207
208 sema.max_count = 1;
209 sema.init_count = 0;
210 cd->hdr.sema_id = CreateSema(&sema);
211 if (cd->hdr.sema_id < 0) {
212 rpc_packet_free(call);
213 return -E_LIB_SEMA_CREATE;
214 }
215
216 if (!SifSendCmd(SIF_CMD_RPC_CALL, call, RPC_PACKET_SIZE, sendbuf, cd->buff, ssize)) {
217 rpc_packet_free(call);
218 DeleteSema(cd->hdr.sema_id);
219 return -E_SIF_PKT_SEND;
220 }
221
222 WaitSema(cd->hdr.sema_id);
223 DeleteSema(cd->hdr.sema_id);
224
225 return 0;
226}
227#endif
228
229#ifdef F_SifRpcGetOtherData
230int SifRpcGetOtherData(SifRpcReceiveData_t *rd, void *src, void *dest,
231 int size, int mode)
232{
233 ee_sema_t sema;
235
236 other = (SifRpcOtherDataPkt_t *)_rpc_get_packet(&_sif_rpc_data);
237 if (!other)
238 return -E_SIF_PKT_ALLOC;
239
240 rd->hdr.pkt_addr = other;
241 rd->hdr.rpc_id = other->rpc_id;
242 rd->hdr.sema_id = -1;
243
244 other->src = src;
245 other->dest = dest;
246 other->size = size;
247 other->receive = rd;
248
249 if (mode & SIF_RPC_M_NOWAIT) {
250 if (!SifSendCmd(SIF_CMD_RPC_RDATA, other, RPC_PACKET_SIZE, NULL, NULL, 0)) {
251 rpc_packet_free(other);
252 return -E_SIF_PKT_SEND;
253 }
254
255 return 0;
256 }
257
258 sema.max_count = 1;
259 sema.init_count = 0;
260 rd->hdr.sema_id = CreateSema(&sema);
261 if (rd->hdr.sema_id < 0) {
262 rpc_packet_free(other);
263 return -E_LIB_SEMA_CREATE;
264 }
265
266 if (!SifSendCmd(SIF_CMD_RPC_RDATA, other, RPC_PACKET_SIZE, NULL, NULL, 0)) {
267 rpc_packet_free(other);
268 DeleteSema(rd->hdr.sema_id);
269 return -E_SIF_PKT_SEND;
270 }
271
272 WaitSema(rd->hdr.sema_id);
273 DeleteSema(rd->hdr.sema_id);
274
275 return 0;
276}
277#endif
278
279#ifdef F_SifRpcMain
280
281/* The packets sent on EE RPC requests are allocated from this table. */
282static u8 pkt_table[2048] __attribute__((aligned(64)));
283/* A ring buffer used to allocate packets sent on IOP requests. */
284static u8 rdata_table[2048] __attribute__((aligned(64)));
285static u8 client_table[2048] __attribute__((aligned(64)));
286
287struct rpc_data _sif_rpc_data = {
288 pid : 1,
289 pkt_table : pkt_table,
290 pkt_table_len : sizeof(pkt_table) / RPC_PACKET_SIZE,
291 rdata_table : rdata_table,
292 rdata_table_len : sizeof(rdata_table) / RPC_PACKET_SIZE,
293 client_table : client_table,
294 client_table_len : sizeof(client_table) / RPC_PACKET_SIZE,
295 rdata_table_idx : 0
296};
297
298static int init = 0;
299
300
301/* Command 0x80000008 */
302static void _request_end(SifRpcRendPkt_t *request, void *data)
303{
304 SifRpcClientData_t *client = request->client;
305
306 (void)data;
307
308 if (request->cid == SIF_CMD_RPC_CALL) {
309 if (client->end_function)
310 client->end_function(client->end_param);
311 } else if (request->cid == SIF_CMD_RPC_BIND) {
312 client->server = request->server;
313 client->buff = request->buff;
314 client->cbuff = request->cbuff;
315 }
316
317 if (client->hdr.sema_id >= 0)
318 iSignalSema(client->hdr.sema_id);
319
320 rpc_packet_free(client->hdr.pkt_addr);
321 client->hdr.pkt_addr = NULL;
322}
323
324static void *search_svdata(u32 sid, struct rpc_data *rpc_data)
325{
326 SifRpcServerData_t *server;
327 SifRpcDataQueue_t *queue = rpc_data->active_queue;
328
329 if (!queue)
330 return NULL;
331
332 while (queue) {
333 server = queue->link;
334 while (server) {
335 if ((u32)(server->sid) == sid)
336 return server;
337
338 server = server->link;
339 }
340
341 queue = queue->next;
342 }
343
344 return NULL;
345}
346
347/* Command 0x80000009 */
348static void _request_bind(SifRpcBindPkt_t *bind, void *data)
349{
350 SifRpcRendPkt_t *rend;
351 SifRpcServerData_t *server;
352
353 rend = _rpc_get_fpacket(data);
354 rend->pkt_addr = bind->pkt_addr;
355 rend->client = bind->client;
356 rend->cid = SIF_CMD_RPC_BIND;
357
358 server = search_svdata(bind->sid, data);
359 if (!server) {
360 rend->server = NULL;
361 rend->buff = NULL;
362 rend->cbuff = NULL;
363 } else {
364 rend->server = server;
365 rend->buff = server->buff;
366 rend->cbuff = server->cbuff;
367 }
368
369 iSifSendCmd(SIF_CMD_RPC_END, rend, RPC_PACKET_SIZE, NULL, NULL, 0);
370}
371
372/* Command 0x8000000a */
373static void _request_call(SifRpcCallPkt_t *request, void *data)
374{
375 SifRpcServerData_t *server = request->server;
376 SifRpcDataQueue_t *base = server->base;
377
378 (void)data;
379
380 if (base->start)
381 base->end->next = server;
382 else
383 base->start = server;
384
385 base->end = server;
386 server->pkt_addr = request->pkt_addr;
387 server->client = request->client;
388 server->rpc_number = request->rpc_number;
389 server->size = request->send_size;
390 server->receive = request->receive;
391 server->rsize = request->recv_size;
392 server->rmode = request->rmode;
393 server->rid = request->rec_id;
394
395 if (base->thread_id < 0 || base->active != 0)
396 return;
397
398 iWakeupThread(base->thread_id);
399}
400
401/* Command 0x8000000c */
402static void _request_rdata(SifRpcOtherDataPkt_t *rdata, void *data)
403{
404 SifRpcRendPkt_t *rend;
405
406 rend = (SifRpcRendPkt_t *)_rpc_get_fpacket(data);
407 rend->pkt_addr = rdata->pkt_addr;
408 rend->client = (SifRpcClientData_t *)rdata->receive;
409 rend->cid = SIF_CMD_RPC_RDATA;
410
411 iSifSendCmd(SIF_CMD_RPC_END, rend, RPC_PACKET_SIZE, rdata->src, rdata->dest, rdata->size);
412}
413
414void SifInitRpc(int mode)
415{
416 u32 *cmdp;
417
418 (void)mode;
419
420 static int _rb_count = 0;
421 if (_rb_count != _iop_reboot_count) {
422 _rb_count = _iop_reboot_count;
423 SifExitCmd();
424 init = 0;
425 }
426
427 if (init)
428 return;
429 init = 1;
430
431 SifInitCmd();
432
433 DI();
434 _sif_rpc_data.pkt_table = UNCACHED_SEG(_sif_rpc_data.pkt_table);
435 _sif_rpc_data.rdata_table = UNCACHED_SEG(_sif_rpc_data.rdata_table);
436 _sif_rpc_data.client_table = UNCACHED_SEG(_sif_rpc_data.client_table);
437
438 _sif_rpc_data.rdata_table_idx = 0;
439 struct rpc_data *rpc_data = (struct rpc_data *)(&_sif_rpc_data);
440
441 int len = rpc_data->pkt_table_len;
442 if (len > 0) {
443 int rid;
444 SifRpcPktHeader_t *packet = (SifRpcPktHeader_t *)rpc_data->pkt_table;
445
446 for (rid = 0; rid < len; rid++, packet = (SifRpcPktHeader_t *)(((unsigned char *)packet) + RPC_PACKET_SIZE)) {
447 rpc_packet_free(packet);
448 }
449 }
450
451 SifAddCmdHandler(SIF_CMD_RPC_END, (void *)_request_end, &_sif_rpc_data);
452 SifAddCmdHandler(SIF_CMD_RPC_BIND, (void *)_request_bind, &_sif_rpc_data);
453 SifAddCmdHandler(SIF_CMD_RPC_CALL, (void *)_request_call, &_sif_rpc_data);
454 SifAddCmdHandler(SIF_CMD_RPC_RDATA, (void *)_request_rdata, &_sif_rpc_data);
455 EI();
456
457 if (SifGetReg(SIF_SYSREG_RPCINIT))
458 return;
459
460 cmdp = (u32 *)&pkt_table[64];
461 cmdp[3] = 1;
462 SifSendCmd(SIF_CMD_INIT_CMD, cmdp, 16, NULL, NULL, 0);
463
464 while (!SifGetSreg(SIF_SREG_RPCINIT))
465 ;
466 SifSetReg(SIF_SYSREG_RPCINIT, 1);
467}
468
469void SifExitRpc(void)
470{
471 SifExitCmd();
472 init = 0;
473}
474#endif
475
476#ifdef F_SifRegisterRpc
478SifRegisterRpc(SifRpcServerData_t *sd,
479 int sid, SifRpcFunc_t func, void *buff, SifRpcFunc_t cfunc,
480 void *cbuff, SifRpcDataQueue_t *qd)
481{
482 SifRpcServerData_t *server;
483
484 DI();
485
486 sd->link = NULL;
487 sd->next = NULL;
488 sd->sid = sid;
489 sd->func = func;
490 sd->buff = buff;
491 sd->cfunc = cfunc;
492 sd->cbuff = cbuff;
493 sd->base = qd;
494
495 if (!(server = qd->link)) {
496 qd->link = sd;
497 } else {
498 while (server->link != NULL) {
499 server = server->link;
500 }
501
502 server->link = sd;
503 }
504
505 EI();
506
507 return server;
508}
509#endif
510
511#ifdef F_SifRemoveRpc
513SifRemoveRpc(SifRpcServerData_t *sd, SifRpcDataQueue_t *queue)
514{
515 SifRpcServerData_t *server;
516
517 DI();
518
519 if ((server = queue->link) == sd) {
520 queue->link = server->link;
521 } else {
522 while (server != NULL) {
523 if (server->link == sd) {
524 server->link = sd->link;
525 break;
526 }
527
528 server = server->link;
529 }
530 }
531
532 EI();
533
534 return server;
535}
536#endif
537
538#ifdef F_SifSetRpcQueue
540SifSetRpcQueue(SifRpcDataQueue_t *qd, int thread_id)
541{
542 SifRpcDataQueue_t *queue = NULL;
543
544 DI();
545
546 qd->thread_id = thread_id;
547 qd->active = 0;
548 qd->link = NULL;
549 qd->start = NULL;
550 qd->end = NULL;
551 qd->next = NULL;
552
553 if (_sif_rpc_data.active_queue == NULL) {
554 _sif_rpc_data.active_queue = qd;
555 } else {
556 queue = _sif_rpc_data.active_queue;
557
558 while (queue->next != NULL)
559 queue = queue->next;
560
561 queue->next = qd;
562 }
563
564 EI();
565
566 return queue;
567}
568#endif
569
570#ifdef F_SifRemoveRpcQueue
572SifRemoveRpcQueue(SifRpcDataQueue_t *qd)
573{
574 SifRpcDataQueue_t *queue;
575
576 DI();
577
578 if ((queue = _sif_rpc_data.active_queue) == qd) {
579 _sif_rpc_data.active_queue = queue->next;
580 } else {
581 while (queue != NULL) {
582 if (queue->next == qd) {
583 queue->next = qd->next;
584 break;
585 }
586
587 queue = queue->next;
588 }
589 }
590
591 EI();
592
593 return queue;
594}
595#endif
596
597#ifdef F_SifGetNextRequest
599SifGetNextRequest(SifRpcDataQueue_t *qd)
600{
601 SifRpcServerData_t *server;
602
603 DI();
604
605 server = qd->start;
606 if (server != NULL) {
607 qd->active = 1;
608 qd->start = server->next;
609 } else {
610 qd->active = 0;
611 }
612
613 EI();
614
615 return server;
616}
617#endif
618
619#ifdef F_SifExecRequest
620static void *_rpc_get_fpacket2(struct rpc_data *rpc_data, int rid)
621{
622 if (rid < 0 || rid < rpc_data->client_table_len)
623 return _rpc_get_fpacket(rpc_data);
624 else
625 return rpc_data->client_table + (rid * RPC_PACKET_SIZE);
626}
627
628void SifExecRequest(SifRpcServerData_t *sd)
629{
630 SifDmaTransfer_t dmat;
631 SifRpcRendPkt_t *rend;
632 void *rec = NULL;
633
634 rec = sd->func(sd->rpc_number, sd->buff, sd->size);
635
636 if (sd->size)
637 SifWriteBackDCache(sd->buff, sd->size);
638
639 if (sd->rsize)
640 SifWriteBackDCache(rec, sd->rsize);
641
642 DI();
643
644 if (sd->rid & 4)
645 rend = (SifRpcRendPkt_t *)
646 _rpc_get_fpacket2(&_sif_rpc_data, (sd->rid >> 16) & 0xffff);
647 else
648 rend = (SifRpcRendPkt_t *)
649 _rpc_get_fpacket(&_sif_rpc_data);
650
651 EI();
652
653 rend->client = sd->client;
654 rend->cid = SIF_CMD_RPC_CALL;
655
656 if (sd->rmode) {
657 if (!SifSendCmd(SIF_CMD_RPC_END, rend, RPC_PACKET_SIZE, rec, sd->receive,
658 sd->rsize))
659 return;
660 }
661
662 rend->rpc_id = 0;
663 rend->rec_id = 0;
664
665 if (sd->rsize) {
666 dmat.src = rec;
667 dmat.dest = sd->receive;
668 dmat.size = sd->rsize;
669 dmat.attr = 0;
670 } else {
671 dmat.src = rend;
672 dmat.dest = sd->pkt_addr;
673 dmat.size = 64;
674 dmat.attr = 0;
675 }
676
677 while (!SifSetDma(&dmat, 1))
678 nopdelay();
679}
680#endif
681
682#ifdef F_SifRpcLoop
683void SifRpcLoop(SifRpcDataQueue_t *qd)
684{
685 while (1) {
686 SifRpcServerData_t *server;
687
688 while ((server = SifGetNextRequest(qd)))
689 SifExecRequest(server);
690
691 SleepThread();
692 }
693}
694#endif
695
696#ifdef F_SifCheckStatRpc
697int SifCheckStatRpc(SifRpcClientData_t *cd)
698{
699 SifRpcPktHeader_t *packet = (SifRpcPktHeader_t *)cd->hdr.pkt_addr;
700
701 if (!packet)
702 return 0;
703
704 if (cd->hdr.rpc_id != (u32)(packet->rpc_id))
705 return 0;
706
707 if (!(packet->rec_id & PACKET_F_ALLOC))
708 return 0;
709
710 return 1;
711}
712#endif
#define SIF_SREG_RPCINIT
Definition sifcmd.h:49
#define SIF_RPC_M_NOWAIT
Definition sifrpc.h:24
#define SIF_RPC_M_NOWBDC
Definition sifrpc.h:26
#define PACKET_F_ALLOC
Definition sifrpc.c:28
@ 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