patch to make enabling 64B L2 cache optional (tueidj)
[libogc.git] / libogc / ipc.c
blob06aa52226a5ef35dcffeb39c4c56e6de70f3a84b
1 /*-------------------------------------------------------------
3 ipc.c -- Interprocess Communication with Starlet
5 Copyright (C) 2008
6 Michael Wiedenbauer (shagkur)
7 Dave Murphy (WinterMute)
8 Hector Martin (marcan)
10 This software is provided 'as-is', without any express or implied
11 warranty. In no event will the authors be held liable for any
12 damages arising from the use of this software.
14 Permission is granted to anyone to use this software for any
15 purpose, including commercial applications, and to alter it and
16 redistribute it freely, subject to the following restrictions:
18 1. The origin of this software must not be misrepresented; you
19 must not claim that you wrote the original software. If you use
20 this software in a product, an acknowledgment in the product
21 documentation would be appreciated but is not required.
23 2. Altered source versions must be plainly marked as such, and
24 must not be misrepresented as being the original software.
26 3. This notice may not be removed or altered from any source
27 distribution.
29 -------------------------------------------------------------*/
31 #if defined(HW_RVL)
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdarg.h>
37 #include <ctype.h>
38 #include <malloc.h>
39 #include <time.h>
40 #include <gcutil.h>
41 #include "asm.h"
42 #include "processor.h"
43 #include "lwp.h"
44 #include "irq.h"
45 #include "ipc.h"
46 #include "cache.h"
47 #include "system.h"
48 #include "lwp_heap.h"
49 #include "lwp_wkspace.h"
51 //#define DEBUG_IPC
53 #define IPC_HEAP_SIZE 4096
54 #define IPC_REQUESTSIZE 64
55 #define IPC_NUMHEAPS 16
57 #define IOS_MAXFMT_PARAMS 32
59 #define IOS_OPEN 0x01
60 #define IOS_CLOSE 0x02
61 #define IOS_READ 0x03
62 #define IOS_WRITE 0x04
63 #define IOS_SEEK 0x05
64 #define IOS_IOCTL 0x06
65 #define IOS_IOCTLV 0x07
67 #define RELNCH_RELAUNCH 1
68 #define RELNCH_BACKGROUND 2
70 struct _ipcreq
71 { //ipc struct size: 32
72 u32 cmd; //0
73 s32 result; //4
74 union { //8
75 s32 fd;
76 u32 req_cmd;
78 union {
79 struct {
80 char *filepath;
81 u32 mode;
82 } open;
83 struct {
84 void *data;
85 u32 len;
86 } read, write;
87 struct {
88 s32 where;
89 s32 whence;
90 } seek;
91 struct {
92 u32 ioctl;
93 void *buffer_in;
94 u32 len_in;
95 void *buffer_io;
96 u32 len_io;
97 } ioctl;
98 struct {
99 u32 ioctl;
100 u32 argcin;
101 u32 argcio;
102 struct _ioctlv *argv;
103 } ioctlv;
104 u32 args[5];
107 ipccallback cb; //32
108 void *usrdata; //36
109 u32 relnch; //40
110 lwpq_t syncqueue; //44
111 u32 magic; //48 - used to avoid spurious responses, like from zelda.
112 u8 pad1[12]; //52 - 60
113 } ATTRIBUTE_PACKED;
115 struct _ipcreqres
117 u32 cnt_sent;
118 u32 cnt_queue;
119 u32 req_send_no;
120 u32 req_queue_no;
121 struct _ipcreq *reqs[16];
124 struct _ipcheap
126 void *membase;
127 u32 size;
128 heap_cntrl heap;
131 struct _ioctlvfmt_bufent
133 void *ipc_buf;
134 void *io_buf;
135 s32 copy_len;
138 struct _ioctlvfmt_cbdata
140 ipccallback user_cb;
141 void *user_data;
142 s32 num_bufs;
143 u32 hId;
144 struct _ioctlvfmt_bufent *bufs;
147 static u32 IPC_REQ_MAGIC;
149 static s32 _ipc_hid = -1;
150 static s32 _ipc_mailboxack = 1;
151 static u32 _ipc_relnchFl = 0;
152 static u32 _ipc_initialized = 0;
153 static u32 _ipc_clntinitialized = 0;
154 static u64 _ipc_spuriousresponsecnt = 0;
155 static struct _ipcreq *_ipc_relnchRpc = NULL;
157 static void *_ipc_bufferlo = NULL;
158 static void *_ipc_bufferhi = NULL;
159 static void *_ipc_currbufferlo = NULL;
160 static void *_ipc_currbufferhi = NULL;
162 static u32 _ipc_seed = 0xffffffff;
164 static struct _ipcreqres _ipc_responses;
166 static struct _ipcheap _ipc_heaps[IPC_NUMHEAPS] =
168 {NULL, 0, {}} // all other elements should be inited to zero, says C standard, so this should do
171 static vu32* const _ipcReg = (u32*)0xCD000000;
173 extern void __MaskIrq(u32 nMask);
174 extern void __UnmaskIrq(u32 nMask);
175 extern void* __SYS_GetIPCBufferLo(void);
176 extern void* __SYS_GetIPCBufferHi(void);
178 extern u32 gettick();
180 static __inline__ u32 IPC_ReadReg(u32 reg)
182 return _ipcReg[reg];
185 static __inline__ void IPC_WriteReg(u32 reg,u32 val)
187 _ipcReg[reg] = val;
190 static __inline__ void ACR_WriteReg(u32 reg,u32 val)
192 _ipcReg[reg>>2] = val;
195 static __inline__ void* __ipc_allocreq()
197 return iosAlloc(_ipc_hid,IPC_REQUESTSIZE);
200 static __inline__ void __ipc_freereq(void *ptr)
202 iosFree(_ipc_hid,ptr);
205 static __inline__ void __ipc_srand(u32 seed)
207 _ipc_seed = seed;
210 static __inline__ u32 __ipc_rand()
212 _ipc_seed = (214013*_ipc_seed) + 2531011;
213 return _ipc_seed;
216 static s32 __ioctlvfmtCB(s32 result,void *userdata)
218 ipccallback user_cb;
219 void *user_data;
220 struct _ioctlvfmt_cbdata *cbdata;
221 struct _ioctlvfmt_bufent *pbuf;
223 cbdata = (struct _ioctlvfmt_cbdata*)userdata;
225 // deal with data buffers
226 if(cbdata->bufs) {
227 pbuf = cbdata->bufs;
228 while(cbdata->num_bufs--) {
229 if(pbuf->ipc_buf) {
230 // copy data if needed
231 if(pbuf->io_buf && pbuf->copy_len)
232 memcpy(pbuf->io_buf, pbuf->ipc_buf, pbuf->copy_len);
233 // then free the buffer
234 iosFree(cbdata->hId, pbuf->ipc_buf);
236 pbuf++;
240 user_cb = cbdata->user_cb;
241 user_data = cbdata->user_data;
243 // free buffer list
244 __lwp_wkspace_free(cbdata->bufs);
246 // free callback data
247 __lwp_wkspace_free(cbdata);
249 // call the user callback
250 if(user_cb)
251 return user_cb(result, user_data);
253 return result;
256 static s32 __ipc_queuerequest(struct _ipcreq *req)
258 u32 cnt;
259 u32 level;
260 #ifdef DEBUG_IPC
261 printf("__ipc_queuerequest(0x%p)\n",req);
262 #endif
263 _CPU_ISR_Disable(level);
265 cnt = (_ipc_responses.cnt_queue - _ipc_responses.cnt_sent);
266 if(cnt>=16) {
267 _CPU_ISR_Restore(level);
268 return IPC_EQUEUEFULL;
271 _ipc_responses.reqs[_ipc_responses.req_queue_no] = req;
272 _ipc_responses.req_queue_no = ((_ipc_responses.req_queue_no+1)&0x0f);
273 _ipc_responses.cnt_queue++;
275 _CPU_ISR_Restore(level);
276 return IPC_OK;
279 static s32 __ipc_syncqueuerequest(struct _ipcreq *req)
281 u32 cnt;
282 #ifdef DEBUG_IPC
283 printf("__ipc_syncqueuerequest(0x%p)\n",req);
284 #endif
285 cnt = (_ipc_responses.cnt_queue - _ipc_responses.cnt_sent);
286 if(cnt>=16) {
287 return IPC_EQUEUEFULL;
290 _ipc_responses.reqs[_ipc_responses.req_queue_no] = req;
291 _ipc_responses.req_queue_no = ((_ipc_responses.req_queue_no+1)&0x0f);
292 _ipc_responses.cnt_queue++;
294 return IPC_OK;
297 static void __ipc_sendrequest()
299 u32 cnt;
300 u32 ipc_send;
301 struct _ipcreq *req;
302 #ifdef DEBUG_IPC
303 printf("__ipc_sendrequest()\n");
304 #endif
305 cnt = (_ipc_responses.cnt_queue - _ipc_responses.cnt_sent);
306 if(cnt>0) {
307 req = _ipc_responses.reqs[_ipc_responses.req_send_no];
308 if(req!=NULL) {
309 req->magic = IPC_REQ_MAGIC;
310 if(req->relnch&RELNCH_RELAUNCH) {
311 _ipc_relnchFl = 1;
312 _ipc_relnchRpc = req;
313 if(!(req->relnch&RELNCH_BACKGROUND))
314 _ipc_mailboxack--;
316 DCFlushRange(req,sizeof(struct _ipcreq));
318 IPC_WriteReg(0,MEM_VIRTUAL_TO_PHYSICAL(req));
319 _ipc_responses.req_send_no = ((_ipc_responses.req_send_no+1)&0x0f);
320 _ipc_responses.cnt_sent++;
321 _ipc_mailboxack--;
323 ipc_send = ((IPC_ReadReg(1)&0x30)|0x01);
324 IPC_WriteReg(1,ipc_send);
329 static void __ipc_replyhandler()
331 u32 ipc_ack,cnt;
332 struct _ipcreq *req = NULL;
333 ioctlv *v = NULL;
334 #ifdef DEBUG_IPC
335 printf("__ipc_replyhandler()\n");
336 #endif
337 req = (struct _ipcreq*)IPC_ReadReg(2);
338 if(req==NULL) return;
340 ipc_ack = ((IPC_ReadReg(1)&0x30)|0x04);
341 IPC_WriteReg(1,ipc_ack);
342 ACR_WriteReg(48,0x40000000);
344 req = MEM_PHYSICAL_TO_K0(req);
345 DCInvalidateRange(req,32);
347 if(req->magic==IPC_REQ_MAGIC) {
348 #ifdef DEBUG_IPC
349 printf("IPC res: cmd %08x rcmd %08x res %08x\n",req->cmd,req->req_cmd,req->result);
350 #endif
351 if(req->req_cmd==IOS_READ) {
352 if(req->read.data!=NULL) {
353 req->read.data = MEM_PHYSICAL_TO_K0(req->read.data);
354 if(req->result>0) DCInvalidateRange(req->read.data,req->result);
356 } else if(req->req_cmd==IOS_IOCTL) {
357 if(req->ioctl.buffer_io!=NULL) {
358 req->ioctl.buffer_io = MEM_PHYSICAL_TO_K0(req->ioctl.buffer_io);
359 DCInvalidateRange(req->ioctl.buffer_io,req->ioctl.len_io);
361 DCInvalidateRange(req->ioctl.buffer_in,req->ioctl.len_in);
362 } else if(req->req_cmd==IOS_IOCTLV) {
363 if(req->ioctlv.argv!=NULL) {
364 req->ioctlv.argv = MEM_PHYSICAL_TO_K0(req->ioctlv.argv);
365 DCInvalidateRange(req->ioctlv.argv,((req->ioctlv.argcin+req->ioctlv.argcio)*sizeof(struct _ioctlv)));
368 cnt = 0;
369 v = (ioctlv*)req->ioctlv.argv;
370 while(cnt<(req->ioctlv.argcin+req->ioctlv.argcio)) {
371 if(v[cnt].data!=NULL) {
372 v[cnt].data = MEM_PHYSICAL_TO_K0(v[cnt].data);
373 DCInvalidateRange(v[cnt].data,v[cnt].len);
375 cnt++;
377 if(_ipc_relnchFl && _ipc_relnchRpc==req) {
378 _ipc_relnchFl = 0;
379 if(_ipc_mailboxack<1) _ipc_mailboxack++;
384 if(req->cb!=NULL) {
385 req->cb(req->result,req->usrdata);
386 __ipc_freereq(req);
387 } else
388 LWP_ThreadSignal(req->syncqueue);
389 } else {
390 // NOTE: we really want to find out if this ever happens
391 // and take steps to prevent it beforehand (because it will
392 // clobber memory, among other things). I suggest leaving this in
393 // even in non-DEBUG mode. Maybe even cause a system halt.
394 // It is the responsibility of the loader to clear these things,
395 // but we want to find out if they happen so loaders can be fixed.
396 #ifdef DEBUG_IPC
397 printf("Received unknown IPC response (magic %08x):\n", req->magic);
398 printf(" CMD %08x RES %08x REQCMD %08x\n", req->cmd, req->result, req->req_cmd);
399 printf(" Args: %08x %08x %08x %08x %08x\n", req->args[0], req->args[1], req->args[2], req->args[3], req->args[4]);
400 printf(" CB %08x DATA %08x REL %08x QUEUE %08x\n", (u32)req->cb, (u32)req->usrdata, req->relnch, (u32)req->syncqueue);
401 #endif
402 _ipc_spuriousresponsecnt++;
404 ipc_ack = ((IPC_ReadReg(1)&0x30)|0x08);
405 IPC_WriteReg(1,ipc_ack);
408 static void __ipc_ackhandler()
410 u32 ipc_ack;
411 #ifdef DEBUG_IPC
412 printf("__ipc_ackhandler()\n");
413 #endif
414 ipc_ack = ((IPC_ReadReg(1)&0x30)|0x02);
415 IPC_WriteReg(1,ipc_ack);
416 ACR_WriteReg(48,0x40000000);
418 if(_ipc_mailboxack<1) _ipc_mailboxack++;
419 if(_ipc_mailboxack>0) {
420 if(_ipc_relnchFl){
421 _ipc_relnchRpc->result = 0;
422 _ipc_relnchFl = 0;
424 LWP_ThreadSignal(_ipc_relnchRpc->syncqueue);
426 ipc_ack = ((IPC_ReadReg(1)&0x30)|0x08);
427 IPC_WriteReg(1,ipc_ack);
429 __ipc_sendrequest();
434 static void __ipc_interrupthandler(u32 irq,void *ctx)
436 u32 ipc_int;
437 #ifdef DEBUG_IPC
438 printf("__ipc_interrupthandler(%d)\n",irq);
439 #endif
440 ipc_int = IPC_ReadReg(1);
441 if((ipc_int&0x0014)==0x0014) __ipc_replyhandler();
443 ipc_int = IPC_ReadReg(1);
444 if((ipc_int&0x0022)==0x0022) __ipc_ackhandler();
447 static s32 __ios_ioctlvformat_parse(const char *format,va_list args,struct _ioctlvfmt_cbdata *cbdata,s32 *cnt_in,s32 *cnt_io,struct _ioctlv **argv,s32 hId)
449 s32 ret,i;
450 void *pdata;
451 void *iodata;
452 char type,*ps;
453 s32 len,maxbufs = 0;
454 ioctlv *argp = NULL;
455 struct _ioctlvfmt_bufent *bufp;
457 if(hId == IPC_HEAP) hId = _ipc_hid;
458 if(hId < 0) return IPC_EINVAL;
460 maxbufs = strnlen(format,IOS_MAXFMT_PARAMS);
461 if(maxbufs>=IOS_MAXFMT_PARAMS) return IPC_EINVAL;
463 cbdata->hId = hId;
464 cbdata->bufs = __lwp_wkspace_allocate((sizeof(struct _ioctlvfmt_bufent)*(maxbufs+1)));
465 if(cbdata->bufs==NULL) return IPC_ENOMEM;
467 argp = iosAlloc(hId,(sizeof(struct _ioctlv)*(maxbufs+1)));
468 if(argp==NULL) {
469 __lwp_wkspace_free(cbdata->bufs);
470 return IPC_ENOMEM;
473 *argv = argp;
474 bufp = cbdata->bufs;
475 memset(argp,0,(sizeof(struct _ioctlv)*(maxbufs+1)));
476 memset(bufp,0,(sizeof(struct _ioctlvfmt_bufent)*(maxbufs+1)));
478 cbdata->num_bufs = 1;
479 bufp->ipc_buf = argp;
480 bufp++;
482 *cnt_in = 0;
483 *cnt_io = 0;
485 ret = IPC_OK;
486 while(*format) {
487 type = tolower((int)*format);
488 switch(type) {
489 case 'b':
490 pdata = iosAlloc(hId,sizeof(u8));
491 if(pdata==NULL) {
492 ret = IPC_ENOMEM;
493 goto free_and_error;
495 *(u8*)pdata = va_arg(args,u32);
496 argp->data = pdata;
497 argp->len = sizeof(u8);
498 bufp->ipc_buf = pdata;
499 cbdata->num_bufs++;
500 (*cnt_in)++;
501 argp++;
502 bufp++;
503 break;
504 case 'h':
505 pdata = iosAlloc(hId,sizeof(u16));
506 if(pdata==NULL) {
507 ret = IPC_ENOMEM;
508 goto free_and_error;
510 *(u16*)pdata = va_arg(args,u32);
511 argp->data = pdata;
512 argp->len = sizeof(u16);
513 bufp->ipc_buf = pdata;
514 cbdata->num_bufs++;
515 (*cnt_in)++;
516 argp++;
517 bufp++;
518 break;
519 case 'i':
520 pdata = iosAlloc(hId,sizeof(u32));
521 if(pdata==NULL) {
522 ret = IPC_ENOMEM;
523 goto free_and_error;
525 *(u32*)pdata = va_arg(args,u32);
526 argp->data = pdata;
527 argp->len = sizeof(u32);
528 bufp->ipc_buf = pdata;
529 cbdata->num_bufs++;
530 (*cnt_in)++;
531 argp++;
532 bufp++;
533 break;
534 case 'q':
535 pdata = iosAlloc(hId,sizeof(u64));
536 if(pdata==NULL) {
537 ret = IPC_ENOMEM;
538 goto free_and_error;
540 *(u64*)pdata = va_arg(args,u64);
541 argp->data = pdata;
542 argp->len = sizeof(u64);
543 bufp->ipc_buf = pdata;
544 cbdata->num_bufs++;
545 (*cnt_in)++;
546 argp++;
547 bufp++;
548 break;
549 case 'd':
550 argp->data = va_arg(args, void*);
551 argp->len = va_arg(args, u32);
552 (*cnt_in)++;
553 argp++;
554 break;
555 case 's':
556 ps = va_arg(args, char*);
557 len = strnlen(ps,256);
558 if(len>=256) {
559 ret = IPC_EINVAL;
560 goto free_and_error;
563 pdata = iosAlloc(hId,(len+1));
564 if(pdata==NULL) {
565 ret = IPC_ENOMEM;
566 goto free_and_error;
568 memcpy(pdata,ps,(len+1));
569 argp->data = pdata;
570 argp->len = (len+1);
571 bufp->ipc_buf = pdata;
572 cbdata->num_bufs++;
573 (*cnt_in)++;
574 argp++;
575 bufp++;
576 break;
577 case ':':
578 format++;
579 goto parse_io_params;
580 default:
581 ret = IPC_EINVAL;
582 goto free_and_error;
584 format++;
587 parse_io_params:
588 while(*format) {
589 type = tolower((int)*format);
590 switch(type) {
591 case 'b':
592 pdata = iosAlloc(hId,sizeof(u8));
593 if(pdata==NULL) {
594 ret = IPC_ENOMEM;
595 goto free_and_error;
597 iodata = va_arg(args,u8*);
598 *(u8*)pdata = *(u8*)iodata;
599 argp->data = pdata;
600 argp->len = sizeof(u8);
601 bufp->ipc_buf = pdata;
602 bufp->io_buf = iodata;
603 bufp->copy_len = sizeof(u8);
604 cbdata->num_bufs++;
605 (*cnt_io)++;
606 argp++;
607 bufp++;
608 break;
609 case 'h':
610 pdata = iosAlloc(hId,sizeof(u16));
611 if(pdata==NULL) {
612 ret = IPC_ENOMEM;
613 goto free_and_error;
615 iodata = va_arg(args,u16*);
616 *(u16*)pdata = *(u16*)iodata;
617 argp->data = pdata;
618 argp->len = sizeof(u16);
619 bufp->ipc_buf = pdata;
620 bufp->io_buf = iodata;
621 bufp->copy_len = sizeof(u16);
622 cbdata->num_bufs++;
623 (*cnt_io)++;
624 argp++;
625 bufp++;
626 break;
627 case 'i':
628 pdata = iosAlloc(hId,sizeof(u32));
629 if(pdata==NULL) {
630 ret = IPC_ENOMEM;
631 goto free_and_error;
633 iodata = va_arg(args,u32*);
634 *(u32*)pdata = *(u32*)iodata;
635 argp->data = pdata;
636 argp->len = sizeof(u32);
637 bufp->ipc_buf = pdata;
638 bufp->io_buf = iodata;
639 bufp->copy_len = sizeof(u32);
640 cbdata->num_bufs++;
641 (*cnt_io)++;
642 argp++;
643 bufp++;
644 break;
645 case 'q':
646 pdata = iosAlloc(hId,sizeof(u64));
647 if(pdata==NULL) {
648 ret = IPC_ENOMEM;
649 goto free_and_error;
651 iodata = va_arg(args,u64*);
652 *(u64*)pdata = *(u64*)iodata;
653 argp->data = pdata;
654 argp->len = sizeof(u64);
655 bufp->ipc_buf = pdata;
656 bufp->io_buf = iodata;
657 bufp->copy_len = sizeof(u64);
658 cbdata->num_bufs++;
659 (*cnt_io)++;
660 argp++;
661 bufp++;
662 break;
663 case 'd':
664 argp->data = va_arg(args, void*);
665 argp->len = va_arg(args, u32);
666 (*cnt_io)++;
667 argp++;
668 break;
669 default:
670 ret = IPC_EINVAL;
671 goto free_and_error;
673 format++;
675 return IPC_OK;
677 free_and_error:
678 for(i=0;i<cbdata->num_bufs;i++) {
679 if(cbdata->bufs[i].ipc_buf!=NULL) iosFree(hId,cbdata->bufs[i].ipc_buf);
681 __lwp_wkspace_free(cbdata->bufs);
682 return ret;
685 static s32 __ipc_asyncrequest(struct _ipcreq *req)
687 s32 ret;
688 u32 level;
690 ret = __ipc_queuerequest(req);
691 if(ret) __ipc_freereq(req);
692 else {
693 _CPU_ISR_Disable(level);
694 if(_ipc_mailboxack>0) __ipc_sendrequest();
695 _CPU_ISR_Restore(level);
697 return ret;
700 static s32 __ipc_syncrequest(struct _ipcreq *req)
702 s32 ret;
703 u32 level;
705 LWP_InitQueue(&req->syncqueue);
707 _CPU_ISR_Disable(level);
708 ret = __ipc_syncqueuerequest(req);
709 if(ret==0) {
710 if(_ipc_mailboxack>0) __ipc_sendrequest();
711 LWP_ThreadSleep(req->syncqueue);
712 ret = req->result;
714 _CPU_ISR_Restore(level);
716 LWP_CloseQueue(req->syncqueue);
717 return ret;
720 s32 iosCreateHeap(s32 size)
722 s32 i,ret;
723 s32 free;
724 u32 level;
725 u32 ipclo,ipchi;
726 #ifdef DEBUG_IPC
727 printf("iosCreateHeap(%d)\n",size);
728 #endif
729 _CPU_ISR_Disable(level);
731 i=0;
732 while(i<IPC_NUMHEAPS) {
733 if(_ipc_heaps[i].membase==NULL) break;
734 i++;
736 if(i>=IPC_NUMHEAPS) {
737 _CPU_ISR_Restore(level);
738 return IPC_ENOHEAP;
741 ipclo = (((u32)IPC_GetBufferLo()+0x1f)&~0x1f);
742 ipchi = (u32)IPC_GetBufferHi();
743 free = (ipchi - (ipclo + size));
744 if(free<0) return IPC_ENOMEM;
746 _ipc_heaps[i].membase = (void*)ipclo;
747 _ipc_heaps[i].size = size;
749 ret = __lwp_heap_init(&_ipc_heaps[i].heap,(void*)ipclo,size,PPC_CACHE_ALIGNMENT);
750 if(ret<=0) return IPC_ENOMEM;
752 IPC_SetBufferLo((void*)(ipclo+size));
753 _CPU_ISR_Restore(level);
754 return i;
757 void* iosAlloc(s32 hid,s32 size)
759 #ifdef DEBUG_IPC
760 printf("iosAlloc(%d,%d)\n",hid,size);
761 #endif
762 if(hid<0 || hid>=IPC_NUMHEAPS || size<=0) return NULL;
763 return __lwp_heap_allocate(&_ipc_heaps[hid].heap,size);
766 void iosFree(s32 hid,void *ptr)
768 #ifdef DEBUG_IPC
769 printf("iosFree(%d,0x%p)\n",hid,ptr);
770 #endif
771 if(hid<0 || hid>=IPC_NUMHEAPS || ptr==NULL) return;
772 __lwp_heap_free(&_ipc_heaps[hid].heap,ptr);
775 void* IPC_GetBufferLo()
777 return _ipc_currbufferlo;
780 void* IPC_GetBufferHi()
782 return _ipc_currbufferhi;
785 void IPC_SetBufferLo(void *bufferlo)
787 if(_ipc_bufferlo<=bufferlo) _ipc_currbufferlo = bufferlo;
790 void IPC_SetBufferHi(void *bufferhi)
792 if(bufferhi<=_ipc_bufferhi) _ipc_currbufferhi = bufferhi;
795 void __IPC_Init(void)
797 if(!_ipc_initialized) {
798 _ipc_bufferlo = _ipc_currbufferlo = __SYS_GetIPCBufferLo();
799 _ipc_bufferhi = _ipc_currbufferhi = __SYS_GetIPCBufferHi();
800 _ipc_initialized = 1;
804 u32 __IPC_ClntInit(void)
806 if(!_ipc_clntinitialized) {
807 _ipc_clntinitialized = 1;
809 // generate a random request magic
810 __ipc_srand(gettick());
811 IPC_REQ_MAGIC = __ipc_rand();
813 __IPC_Init();
815 _ipc_hid = iosCreateHeap(IPC_HEAP_SIZE);
816 IRQ_Request(IRQ_PI_ACR,__ipc_interrupthandler,NULL);
817 __UnmaskIrq(IM_PI_ACR);
818 IPC_WriteReg(1,56);
820 return IPC_OK;
823 void __IPC_Reinitialize(void)
825 u32 level;
827 _CPU_ISR_Disable(level);
829 IPC_WriteReg(1,56);
831 _ipc_mailboxack = 1;
832 _ipc_relnchFl = 0;
833 _ipc_relnchRpc = NULL;
835 _ipc_responses.req_queue_no = 0;
836 _ipc_responses.cnt_queue = 0;
837 _ipc_responses.req_send_no = 0;
838 _ipc_responses.cnt_sent = 0;
840 _CPU_ISR_Restore(level);
843 s32 IOS_Open(const char *filepath,u32 mode)
845 s32 ret;
846 struct _ipcreq *req;
848 if(filepath==NULL) return IPC_EINVAL;
850 req = __ipc_allocreq();
851 if(req==NULL) return IPC_ENOMEM;
853 req->cmd = IOS_OPEN;
854 req->cb = NULL;
855 req->relnch = 0;
857 DCFlushRange((void*)filepath,strnlen(filepath,IPC_MAXPATH_LEN) + 1);
859 req->open.filepath = (char*)MEM_VIRTUAL_TO_PHYSICAL(filepath);
860 req->open.mode = mode;
862 ret = __ipc_syncrequest(req);
864 if(req!=NULL) __ipc_freereq(req);
865 return ret;
868 s32 IOS_OpenAsync(const char *filepath,u32 mode,ipccallback ipc_cb,void *usrdata)
870 struct _ipcreq *req;
872 req = __ipc_allocreq();
873 if(req==NULL) return IPC_ENOMEM;
875 req->cmd = IOS_OPEN;
876 req->cb = ipc_cb;
877 req->usrdata = usrdata;
878 req->relnch = 0;
880 DCFlushRange((void*)filepath,strnlen(filepath,IPC_MAXPATH_LEN) + 1);
882 req->open.filepath = (char*)MEM_VIRTUAL_TO_PHYSICAL(filepath);
883 req->open.mode = mode;
885 return __ipc_asyncrequest(req);
888 s32 IOS_Close(s32 fd)
890 s32 ret;
891 struct _ipcreq *req;
893 req = __ipc_allocreq();
894 if(req==NULL) return IPC_ENOMEM;
896 req->cmd = IOS_CLOSE;
897 req->fd = fd;
898 req->cb = NULL;
899 req->relnch = 0;
901 ret = __ipc_syncrequest(req);
903 if(req!=NULL) __ipc_freereq(req);
904 return ret;
907 s32 IOS_CloseAsync(s32 fd,ipccallback ipc_cb,void *usrdata)
909 struct _ipcreq *req;
911 req = __ipc_allocreq();
912 if(req==NULL) return IPC_ENOMEM;
914 req->cmd = IOS_CLOSE;
915 req->fd = fd;
916 req->cb = ipc_cb;
917 req->usrdata = usrdata;
918 req->relnch = 0;
920 return __ipc_asyncrequest(req);
923 s32 IOS_Read(s32 fd,void *buf,s32 len)
925 s32 ret;
926 struct _ipcreq *req;
928 req = __ipc_allocreq();
929 if(req==NULL) return IPC_ENOMEM;
931 req->cmd = IOS_READ;
932 req->fd = fd;
933 req->cb = NULL;
934 req->relnch = 0;
936 DCInvalidateRange(buf,len);
937 req->read.data = (void*)MEM_VIRTUAL_TO_PHYSICAL(buf);
938 req->read.len = len;
940 ret = __ipc_syncrequest(req);
942 if(req!=NULL) __ipc_freereq(req);
943 return ret;
946 s32 IOS_ReadAsync(s32 fd,void *buf,s32 len,ipccallback ipc_cb,void *usrdata)
948 struct _ipcreq *req;
950 req = __ipc_allocreq();
951 if(req==NULL) return IPC_ENOMEM;
953 req->cmd = IOS_READ;
954 req->fd = fd;
955 req->cb = ipc_cb;
956 req->usrdata = usrdata;
957 req->relnch = 0;
959 DCInvalidateRange(buf,len);
960 req->read.data = (void*)MEM_VIRTUAL_TO_PHYSICAL(buf);
961 req->read.len = len;
963 return __ipc_asyncrequest(req);
966 s32 IOS_Write(s32 fd,const void *buf,s32 len)
968 s32 ret;
969 struct _ipcreq *req;
971 req = __ipc_allocreq();
972 if(req==NULL) return IPC_ENOMEM;
974 req->cmd = IOS_WRITE;
975 req->fd = fd;
976 req->cb = NULL;
977 req->relnch = 0;
979 DCFlushRange((void*)buf,len);
980 req->write.data = (void*)MEM_VIRTUAL_TO_PHYSICAL(buf);
981 req->write.len = len;
983 ret = __ipc_syncrequest(req);
985 if(req!=NULL) __ipc_freereq(req);
986 return ret;
989 s32 IOS_WriteAsync(s32 fd,const void *buf,s32 len,ipccallback ipc_cb,void *usrdata)
991 struct _ipcreq *req;
993 req = __ipc_allocreq();
994 if(req==NULL) return IPC_ENOMEM;
996 req->cmd = IOS_WRITE;
997 req->fd = fd;
998 req->cb = ipc_cb;
999 req->usrdata = usrdata;
1000 req->relnch = 0;
1002 DCFlushRange((void*)buf,len);
1003 req->write.data = (void*)MEM_VIRTUAL_TO_PHYSICAL(buf);
1004 req->write.len = len;
1006 return __ipc_asyncrequest(req);
1009 s32 IOS_Seek(s32 fd,s32 where,s32 whence)
1011 s32 ret;
1012 struct _ipcreq *req;
1014 req = __ipc_allocreq();
1015 if(req==NULL) return IPC_ENOMEM;
1017 req->cmd = IOS_SEEK;
1018 req->fd = fd;
1019 req->cb = NULL;
1020 req->relnch = 0;
1022 req->seek.where = where;
1023 req->seek.whence = whence;
1025 ret = __ipc_syncrequest(req);
1027 if(req!=NULL) __ipc_freereq(req);
1028 return ret;
1031 s32 IOS_SeekAsync(s32 fd,s32 where,s32 whence,ipccallback ipc_cb,void *usrdata)
1033 struct _ipcreq *req;
1035 req = __ipc_allocreq();
1036 if(req==NULL) return IPC_ENOMEM;
1038 req->cmd = IOS_SEEK;
1039 req->fd = fd;
1040 req->cb = ipc_cb;
1041 req->usrdata = usrdata;
1042 req->relnch = 0;
1044 req->seek.where = where;
1045 req->seek.whence = whence;
1047 return __ipc_asyncrequest(req);
1050 s32 IOS_Ioctl(s32 fd,s32 ioctl,void *buffer_in,s32 len_in,void *buffer_io,s32 len_io)
1052 s32 ret;
1053 struct _ipcreq *req;
1055 req = __ipc_allocreq();
1056 if(req==NULL) return IPC_ENOMEM;
1058 req->cmd = IOS_IOCTL;
1059 req->fd = fd;
1060 req->cb = NULL;
1061 req->relnch = 0;
1063 req->ioctl.ioctl = ioctl;
1064 req->ioctl.buffer_in = (void*)MEM_VIRTUAL_TO_PHYSICAL(buffer_in);
1065 req->ioctl.len_in = len_in;
1066 req->ioctl.buffer_io = (void*)MEM_VIRTUAL_TO_PHYSICAL(buffer_io);
1067 req->ioctl.len_io = len_io;
1069 DCFlushRange(buffer_in,len_in);
1070 DCFlushRange(buffer_io,len_io);
1072 ret = __ipc_syncrequest(req);
1074 if(req!=NULL) __ipc_freereq(req);
1075 return ret;
1078 s32 IOS_IoctlAsync(s32 fd,s32 ioctl,void *buffer_in,s32 len_in,void *buffer_io,s32 len_io,ipccallback ipc_cb,void *usrdata)
1080 struct _ipcreq *req;
1082 req = __ipc_allocreq();
1083 if(req==NULL) return IPC_ENOMEM;
1085 req->cmd = IOS_IOCTL;
1086 req->fd = fd;
1087 req->cb = ipc_cb;
1088 req->usrdata = usrdata;
1089 req->relnch = 0;
1091 req->ioctl.ioctl = ioctl;
1092 req->ioctl.buffer_in = (void*)MEM_VIRTUAL_TO_PHYSICAL(buffer_in);
1093 req->ioctl.len_in = len_in;
1094 req->ioctl.buffer_io = (void*)MEM_VIRTUAL_TO_PHYSICAL(buffer_io);
1095 req->ioctl.len_io = len_io;
1097 DCFlushRange(buffer_in,len_in);
1098 DCFlushRange(buffer_io,len_io);
1100 return __ipc_asyncrequest(req);
1103 s32 IOS_Ioctlv(s32 fd,s32 ioctl,s32 cnt_in,s32 cnt_io,ioctlv *argv)
1105 s32 i,ret;
1106 struct _ipcreq *req;
1108 req = __ipc_allocreq();
1109 if(req==NULL) return IPC_ENOMEM;
1111 req->cmd = IOS_IOCTLV;
1112 req->fd = fd;
1113 req->cb = NULL;
1114 req->relnch = 0;
1116 req->ioctlv.ioctl = ioctl;
1117 req->ioctlv.argcin = cnt_in;
1118 req->ioctlv.argcio = cnt_io;
1119 req->ioctlv.argv = (struct _ioctlv*)MEM_VIRTUAL_TO_PHYSICAL(argv);
1121 i = 0;
1122 while(i<cnt_in) {
1123 if(argv[i].data!=NULL && argv[i].len>0) {
1124 DCFlushRange(argv[i].data,argv[i].len);
1125 argv[i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[i].data);
1127 i++;
1130 i = 0;
1131 while(i<cnt_io) {
1132 if(argv[cnt_in+i].data!=NULL && argv[cnt_in+i].len>0) {
1133 DCFlushRange(argv[cnt_in+i].data,argv[cnt_in+i].len);
1134 argv[cnt_in+i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[cnt_in+i].data);
1136 i++;
1138 DCFlushRange(argv,((cnt_in+cnt_io)<<3));
1140 ret = __ipc_syncrequest(req);
1142 if(req!=NULL) __ipc_freereq(req);
1143 return ret;
1147 s32 IOS_IoctlvAsync(s32 fd,s32 ioctl,s32 cnt_in,s32 cnt_io,ioctlv *argv,ipccallback ipc_cb,void *usrdata)
1149 s32 i;
1150 struct _ipcreq *req;
1152 req = __ipc_allocreq();
1153 if(req==NULL) return IPC_ENOMEM;
1155 req->cmd = IOS_IOCTLV;
1156 req->fd = fd;
1157 req->cb = ipc_cb;
1158 req->usrdata = usrdata;
1159 req->relnch = 0;
1161 req->ioctlv.ioctl = ioctl;
1162 req->ioctlv.argcin = cnt_in;
1163 req->ioctlv.argcio = cnt_io;
1164 req->ioctlv.argv = (struct _ioctlv*)MEM_VIRTUAL_TO_PHYSICAL(argv);
1166 i = 0;
1167 while(i<cnt_in) {
1168 if(argv[i].data!=NULL && argv[i].len>0) {
1169 DCFlushRange(argv[i].data,argv[i].len);
1170 argv[i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[i].data);
1172 i++;
1175 i = 0;
1176 while(i<cnt_io) {
1177 if(argv[cnt_in+i].data!=NULL && argv[cnt_in+i].len>0) {
1178 DCFlushRange(argv[cnt_in+i].data,argv[cnt_in+i].len);
1179 argv[cnt_in+i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[cnt_in+i].data);
1181 i++;
1183 DCFlushRange(argv,((cnt_in+cnt_io)<<3));
1185 return __ipc_asyncrequest(req);
1188 s32 IOS_IoctlvFormat(s32 hId,s32 fd,s32 ioctl,const char *format,...)
1190 s32 ret;
1191 va_list args;
1192 s32 cnt_in,cnt_io;
1193 struct _ioctlv *argv;
1194 struct _ioctlvfmt_cbdata *cbdata;
1196 cbdata = __lwp_wkspace_allocate(sizeof(struct _ioctlvfmt_cbdata));
1197 if(cbdata==NULL) return IPC_ENOMEM;
1199 memset(cbdata,0,sizeof(struct _ioctlvfmt_cbdata));
1201 va_start(args,format);
1202 ret = __ios_ioctlvformat_parse(format,args,cbdata,&cnt_in,&cnt_io,&argv,hId);
1203 va_end(args);
1204 if(ret<0) {
1205 __lwp_wkspace_free(cbdata);
1206 return ret;
1209 ret = IOS_Ioctlv(fd,ioctl,cnt_in,cnt_io,argv);
1210 __ioctlvfmtCB(ret,cbdata);
1212 return ret;
1215 s32 IOS_IoctlvFormatAsync(s32 hId,s32 fd,s32 ioctl,ipccallback usr_cb,void *usr_data,const char *format,...)
1217 s32 ret;
1218 va_list args;
1219 s32 cnt_in,cnt_io;
1220 struct _ioctlv *argv;
1221 struct _ioctlvfmt_cbdata *cbdata;
1223 cbdata = __lwp_wkspace_allocate(sizeof(struct _ioctlvfmt_cbdata));
1224 if(cbdata==NULL) return IPC_ENOMEM;
1226 memset(cbdata,0,sizeof(struct _ioctlvfmt_cbdata));
1228 va_start(args,format);
1229 ret = __ios_ioctlvformat_parse(format,args,cbdata,&cnt_in,&cnt_io,&argv,hId);
1230 va_end(args);
1231 if(ret<0) {
1232 __lwp_wkspace_free(cbdata);
1233 return ret;
1236 cbdata->user_cb = usr_cb;
1237 cbdata->user_data = usr_data;
1238 return IOS_IoctlvAsync(fd,ioctl,cnt_in,cnt_io,argv,__ioctlvfmtCB,cbdata);
1241 s32 IOS_IoctlvReboot(s32 fd,s32 ioctl,s32 cnt_in,s32 cnt_io,ioctlv *argv)
1243 s32 i,ret;
1244 struct _ipcreq *req;
1246 req = __ipc_allocreq();
1247 if(req==NULL) return IPC_ENOMEM;
1249 req->cmd = IOS_IOCTLV;
1250 req->fd = fd;
1251 req->cb = NULL;
1252 req->relnch = RELNCH_RELAUNCH;
1254 req->ioctlv.ioctl = ioctl;
1255 req->ioctlv.argcin = cnt_in;
1256 req->ioctlv.argcio = cnt_io;
1257 req->ioctlv.argv = (struct _ioctlv*)MEM_VIRTUAL_TO_PHYSICAL(argv);
1259 i = 0;
1260 while(i<cnt_in) {
1261 if(argv[i].data!=NULL && argv[i].len>0) {
1262 DCFlushRange(argv[i].data,argv[i].len);
1263 argv[i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[i].data);
1265 i++;
1268 i = 0;
1269 while(i<cnt_io) {
1270 if(argv[cnt_in+i].data!=NULL && argv[cnt_in+i].len>0) {
1271 DCFlushRange(argv[cnt_in+i].data,argv[cnt_in+i].len);
1272 argv[cnt_in+i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[cnt_in+i].data);
1274 i++;
1276 DCFlushRange(argv,((cnt_in+cnt_io)<<3));
1278 ret = __ipc_syncrequest(req);
1280 if(req!=NULL) __ipc_freereq(req);
1281 return ret;
1284 s32 IOS_IoctlvRebootBackground(s32 fd,s32 ioctl,s32 cnt_in,s32 cnt_io,ioctlv *argv)
1286 s32 i,ret;
1287 struct _ipcreq *req;
1289 req = __ipc_allocreq();
1290 if(req==NULL) return IPC_ENOMEM;
1292 req->cmd = IOS_IOCTLV;
1293 req->result = 0;
1294 req->fd = fd;
1295 req->cb = NULL;
1296 req->relnch = RELNCH_BACKGROUND|RELNCH_RELAUNCH;
1298 req->ioctlv.ioctl = ioctl;
1299 req->ioctlv.argcin = cnt_in;
1300 req->ioctlv.argcio = cnt_io;
1301 req->ioctlv.argv = (struct _ioctlv*)MEM_VIRTUAL_TO_PHYSICAL(argv);
1303 i = 0;
1304 while(i<cnt_in) {
1305 if(argv[i].data!=NULL && argv[i].len>0) {
1306 DCFlushRange(argv[i].data,argv[i].len);
1307 argv[i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[i].data);
1309 i++;
1312 i = 0;
1313 while(i<cnt_io) {
1314 if(argv[cnt_in+i].data!=NULL && argv[cnt_in+i].len>0) {
1315 DCFlushRange(argv[cnt_in+i].data,argv[cnt_in+i].len);
1316 argv[cnt_in+i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[cnt_in+i].data);
1318 i++;
1320 DCFlushRange(argv,((cnt_in+cnt_io)<<3));
1322 ret = __ipc_syncrequest(req);
1324 if(req!=NULL) __ipc_freereq(req);
1325 return ret;
1328 #endif