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