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