2 BootMii - a Free Software replacement for the Nintendo/BroadOn bootloader.
5 Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
6 Copyright (C) 2009 Andre Heider "dhewg" <dhewg@wiibrew.org>
7 Copyright (C) 2009 John Kelley <wiidev@kelley.ca>
9 # This code is licensed to you under the terms of the GNU GPL, version 2;
10 # see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
13 #include "bootmii_ppc.h"
18 static volatile ipc_request *in_queue;
19 static volatile ipc_request *out_queue;
24 static int initialized = 0;
29 typedef const struct {
33 volatile ipc_request *ipc_in;
35 volatile ipc_request *ipc_out;
39 static ipc_infohdr *infohdr;
43 #define HW_REG_BASE 0xd000000
45 #define HW_IPC_PPCMSG (HW_REG_BASE + 0x000) //PPC to ARM
46 #define HW_IPC_PPCCTRL (HW_REG_BASE + 0x004)
47 #define HW_IPC_ARMMSG (HW_REG_BASE + 0x008) //ARM to PPC
49 #define IPC_CTRL_SEND 0x01
50 // Set by peer to acknowledge a message. Write one to clear.
51 #define IPC_CTRL_SENT 0x02
52 // Set by peer to send a message. Write one to clear.
53 #define IPC_CTRL_RECV 0x04
54 // Write one acknowledge a message. Cleared when peer writes one to IPC_CTRL_SENT.
55 #define IPC_CTRL_RECVD 0x08
56 // Enable interrupt when a message is received
57 #define IPC_CTRL_INT_RECV 0x10
58 // Enable interrupt when a sent message is acknowledged
59 #define IPC_CTRL_INT_SENT 0x20
61 static inline u16 peek_outtail(void)
63 return read32(HW_IPC_ARMMSG) & 0xFFFF;
65 static inline u16 peek_inhead(void)
67 return read32(HW_IPC_ARMMSG) >> 16;
70 static inline void poke_intail(u16 num)
72 mask32(HW_IPC_PPCMSG, 0xFFFF, num);
74 static inline void poke_outhead(u16 num)
76 mask32(HW_IPC_PPCMSG, 0xFFFF0000, num<<16);
79 int ipc_initialize(void)
82 infohdr = (ipc_infohdr*)(read32(0x13fffffc)|0x80000000);
83 sync_before_read((void*)infohdr, sizeof(ipc_infohdr));
85 printf("IPC: infoheader at %p %08x\n", infohdr);
87 if(memcmp(infohdr->magic, "IPC", 3)) {
88 printf("IPC: bad magic on info structure\n",infohdr);
91 if(infohdr->version != 1) {
92 printf("IPC: unknown IPC version %d\n",infohdr->version);
96 in_queue = (void*)(((u32)infohdr->ipc_in)|0x80000000);
97 out_queue = (void*)(((u32)infohdr->ipc_out)|0x80000000);
99 in_size = infohdr->ipc_in_size;
100 out_size = infohdr->ipc_out_size;
102 in_tail = read32(HW_IPC_PPCMSG) & 0xffff;
103 out_head = read32(HW_IPC_PPCMSG) >> 16;
105 printf("IPC: initial in tail: %d, out head: %d\n", in_tail, out_head);
113 void ipc_shutdown(void)
121 void ipc_vpost(u32 code, u32 tag, u32 num_args, va_list ap)
127 printf("IPC: not inited\n");
131 if(peek_inhead() == ((in_tail + 1)&(in_size-1))) {
132 printf("IPC: in queue full, spinning\n");
133 while(peek_inhead() == ((in_tail + 1)&(in_size-1))) {
136 printf("IPC: ARM might be stuck, still waiting for inhead %d != %d\n",
137 peek_inhead(), ((in_tail + 1)&(in_size-1)));
142 in_queue[in_tail].code = code;
143 in_queue[in_tail].tag = tag;
145 in_queue[in_tail].args[arg++] = va_arg(ap, u32);
147 sync_after_write((void*)&in_queue[in_tail], 32);
148 in_tail = (in_tail+1)&(in_size-1);
149 poke_intail(in_tail);
150 write32(HW_IPC_PPCCTRL, IPC_CTRL_SEND);
153 void ipc_post(u32 code, u32 tag, u32 num_args, ...)
158 va_start(ap, num_args);
160 ipc_vpost(code, tag, num_args, ap);
170 printf("IPC: not inited\n");
173 while(peek_inhead() != in_tail) {
176 printf("IPC: ARM might be stuck, still waiting for inhead %d == intail %d\n",
177 peek_inhead(), in_tail);
183 // last IPC message received, copied because we need to make space in the queue
184 ipc_request req_recv;
186 // since we're not using IRQs, we don't use the reception bell at all at the moment
187 ipc_request *ipc_receive(void)
189 while(peek_outtail() == out_head);
190 sync_before_read((void*)&out_queue[out_head], 32);
191 req_recv = out_queue[out_head];
192 out_head = (out_head+1)&(out_size-1);
193 poke_outhead(out_head);
198 void ipc_process_unhandled(volatile ipc_request *rep)
200 printf("IPC: Unhandled message: %08x %08x [%08x %08x %08x %08x %08x %08x]\n",
201 rep->code, rep->tag, rep->args[0], rep->args[1], rep->args[2], rep->args[3],
202 rep->args[4], rep->args[5]);
205 ipc_request *ipc_receive_tagged(u32 code, u32 tag)
209 while(rep->code != code || rep->tag != tag) {
210 ipc_process_unhandled(rep);
216 ipc_request *ipc_exchange(u32 code, u32 num_args, ...)
222 va_start(ap, num_args);
224 ipc_vpost(code, cur_tag, num_args, ap);
229 rep = ipc_receive_tagged(code, cur_tag);