diff --git a/ipc.c b/ipc.c index e69de29..fa1c7b0 100644 --- a/ipc.c +++ b/ipc.c @@ -0,0 +1,209 @@ +#include +#include "types.h" +#include "irq.h" +#include "memory.h" +#include "utils.h" +#include "hollywood.h" +#include "gecko.h" +#include "ipcstruct.h" +#include "ipc.h" + +#define IPC_SLOW_SIZE 128 + +volatile ipc_request slow[IPC_SLOW_SIZE]; +u16 slow_head; +vu16 slow_tail; + +u16 in_head; +u16 out_tail; + +static inline void poke_outtail(u16 num) +{ + write16(HW_IPC_ARMMSG, num); +} +static inline void poke_inhead(u16 num) +{ + write16(HW_IPC_ARMMSG+2, num); +} + +static inline u16 peek_intail(void) +{ + return read16(HW_IPC_PPCMSG); +} +static inline u16 peek_outhead(void) +{ + return read16(HW_IPC_PPCMSG+2); +} + +void ipc_post(u32 code, u32 tag, u32 num_args, ...) +{ + int arg = 0; + va_list ap; + u32 cookie = irq_kill(); + + if(peek_outhead() == ((out_tail + 1)&(IPC_OUT_SIZE-1))) { + gecko_printf("IPC: out queue full, PPC slow/dead/DoSed\n"); + while(peek_outhead() == ((out_tail + 1)&(IPC_OUT_SIZE-1))); + } + ipc_out[out_tail].code = code; + ipc_out[out_tail].tag = tag; + if(num_args) { + va_start(ap, num_args); + while(num_args--) { + ipc_out[out_tail].args[arg++] = va_arg(ap, u32); + } + va_end(ap); + } + dc_flushrange((void*)&ipc_out[out_tail], 32); + out_tail = (out_tail+1)&(IPC_OUT_SIZE-1); + poke_outtail(out_tail); + write32(HW_IPC_ARMCTRL, IPC_CTRL_INT_RECV | IPC_CTRL_SEND); + + irq_restore(cookie); +} + +static int process_slow(volatile ipc_request *req) +{ + gecko_printf("IPC: process slow @ %p\n",req); + + gecko_printf("IPC: req %08x %08x [%08x %08x %08x %08x %08x %08x]\n", req->code, req->tag, + req->args[0], req->args[1], req->args[2], req->args[3], req->args[4], req->args[5]); + + gecko_printf("IPC: unknown SLOW request %02x-%04x\n", req->device, req->req); + return 1; +} + +static void process_in(void) +{ + volatile ipc_request *req = &ipc_in[in_head]; + + gecko_printf("IPC: process in %d @ %p\n",in_head,req); + + dc_invalidaterange((void*)req, 32); + + gecko_printf("IPC: req %08x %08x [%08x %08x %08x %08x %08x %08x]\n", req->code, req->tag, + req->args[0], req->args[1], req->args[2], req->args[3], req->args[4], req->args[5]); + + if(req->flags & IPC_FAST) { + switch(req->device) { + case IPC_DEV_SYS: + // handle fast SYS requests here + switch(req->req) { + case IPC_SYS_WRITE32: + write32(req->args[0], req->args[1]); + break; + case IPC_SYS_WRITE16: + write16(req->args[0], req->args[1]); + break; + case IPC_SYS_WRITE8: + write8(req->args[0], req->args[1]); + break; + case IPC_SYS_READ32: + ipc_post(req->code, req->tag, 1, read32(req->args[0])); + break; + case IPC_SYS_READ16: + ipc_post(req->code, req->tag, 1, read16(req->args[0])); + break; + case IPC_SYS_READ8: + ipc_post(req->code, req->tag, 1, read8(req->args[0])); + break; + case IPC_SYS_SET32: + set32(req->args[0], req->args[1]); + break; + case IPC_SYS_SET16: + set16(req->args[0], req->args[1]); + break; + case IPC_SYS_SET8: + set8(req->args[0], req->args[1]); + break; + case IPC_SYS_CLEAR32: + clear32(req->args[0], req->args[1]); + break; + case IPC_SYS_CLEAR16: + clear16(req->args[0], req->args[1]); + break; + case IPC_SYS_CLEAR8: + clear8(req->args[0], req->args[1]); + break; + case IPC_SYS_MASK32: + mask32(req->args[0], req->args[1], req->args[2]); + break; + case IPC_SYS_MASK16: + mask16(req->args[0], req->args[1], req->args[2]); + break; + case IPC_SYS_MASK8: + mask8(req->args[0], req->args[1], req->args[2]); + break; + default: + gecko_printf("IPC: unknown FAST SYS request %04x\n", req->req); + break; + } + break; + default: + gecko_printf("IPC: unknown FAST request %02x-%04x\n", req->device, req->req); + break; + } + } else { + if(slow_head == ((slow_tail + 1)&(IPC_SLOW_SIZE-1))) { + gecko_printf("IPC: Slowqueue overrun\n"); + panic(0x33); + } + slow[slow_tail] = *req; + slow_tail = (slow_tail+1)&(IPC_SLOW_SIZE-1); + } +} + +void ipc_irq(void) +{ + int donebell = 0; + gecko_printf("IPC: irq\n"); + while(read32(HW_IPC_ARMCTRL) & IPC_CTRL_RECV) { + write32(HW_IPC_ARMCTRL, IPC_CTRL_INT_RECV | IPC_CTRL_RECV); + int donereq = 0; + while(peek_intail() != in_head) { + process_in(); + in_head = (in_head+1)&(IPC_IN_SIZE-1); + poke_inhead(in_head); + donereq++; + } + if(!donereq) + gecko_printf("IPC bell but no reqs\n"); + donebell++; + } + if(!donebell) + gecko_printf("IPC IRQ but no bell!\n"); +} + +void ipc_initialize(void) +{ + write32(HW_IPC_ARMMSG, 0); + write32(HW_IPC_PPCMSG, 0); + write32(HW_IPC_PPCCTRL, IPC_CTRL_SENT|IPC_CTRL_RECV); + write32(HW_IPC_ARMCTRL, IPC_CTRL_SENT|IPC_CTRL_RECV); + slow_head = 0; + slow_tail = 0; + in_head = 0; + out_tail = 0; + irq_enable(IRQ_IPC); + write32(HW_IPC_ARMCTRL, IPC_CTRL_INT_RECV); +} +void ipc_shutdown(void) +{ + irq_disable(IRQ_IPC); +} + +void ipc_process_slow(void) +{ + while(1) { + while(slow_head != slow_tail) { + if(!process_slow(&slow[slow_head])) + return; + slow_head = (slow_head+1)&(IPC_SLOW_SIZE-1); + } + u32 cookie = irq_kill(); + if(slow_head == slow_tail) + irq_wait(); + irq_restore(cookie); + } +} + diff --git a/ipc.h b/ipc.h new file mode 100644 index 0000000..f97634d --- /dev/null +++ b/ipc.h @@ -0,0 +1,51 @@ +#ifndef __IPC_H__ +#define __IPC_H__ + +#include "types.h" + +#define IPC_FAST 0x01 +#define IPC_SLOW 0x00 + +#define IPC_DEV_SYS 0x00 + +#define IPC_SYS_JUMP 0x0000 +#define IPC_SYS_WRITE32 0x0100 +#define IPC_SYS_WRITE16 0x0101 +#define IPC_SYS_WRITE8 0x0102 +#define IPC_SYS_READ32 0x0103 +#define IPC_SYS_READ16 0x0104 +#define IPC_SYS_READ8 0x0105 +#define IPC_SYS_SET32 0x0106 +#define IPC_SYS_SET16 0x0107 +#define IPC_SYS_SET8 0x0108 +#define IPC_SYS_CLEAR32 0x0109 +#define IPC_SYS_CLEAR16 0x010a +#define IPC_SYS_CLEAR8 0x010b +#define IPC_SYS_MASK32 0x010c +#define IPC_SYS_MASK16 0x010d +#define IPC_SYS_MASK8 0x010e + + +#define IPC_CODE (f,d,r) (((f)<<24)|((d)<<16)|(r)) + +typedef struct { + union { + struct { + u8 flags; + u8 device; + u16 req; + }; + u32 code; + }; + u32 tag; + u32 args[6]; +} ipc_request; + +void ipc_irq(void); + +void ipc_initialize(void); +void ipc_shutdown(void); +void ipc_post(u32 code, u32 tag, u32 num_args, ...); +void ipc_process_slow(void); + +#endif diff --git a/ipcstruct.h b/ipcstruct.h index 2cb63bd..6097f24 100644 --- a/ipcstruct.h +++ b/ipcstruct.h @@ -6,6 +6,11 @@ #ifndef _LANGUAGE_ASSEMBLY +#include "ipc.h" + +extern volatile ipc_request ipc_in[IPC_IN_SIZE]; +extern volatile ipc_request ipc_out[IPC_OUT_SIZE]; + #endif #endif diff --git a/irq.c b/irq.c index 80088af..c1a73b6 100644 --- a/irq.c +++ b/irq.c @@ -2,6 +2,7 @@ #include "hollywood.h" #include "gecko.h" #include "utils.h" +#include "ipc.h" void irq_setup_stack(void); @@ -60,12 +61,13 @@ void irq_handler(void) write32(HW_IRQFLAG, IRQF_RESET); } if(flags & IRQF_IPC) { - gecko_printf("IRQ: IPC\n"); + //gecko_printf("IRQ: IPC\n"); + ipc_irq(); write32(HW_IRQFLAG, IRQF_IPC); } flags &= ~IRQF_ALL; if(flags) { - gecko_printf("IRQ: unknown 0x%08x\n"); + gecko_printf("IRQ: unknown 0x%08x\n", flags); write32(HW_IRQFLAG, flags); } } diff --git a/main.c b/main.c index 909244a..f437498 100644 --- a/main.c +++ b/main.c @@ -11,6 +11,9 @@ #include "panic.h" #include "powerpc_elf.h" #include "irq.h" +#include "ipc.h" + +void *vector; typedef struct { u32 hdrsize; @@ -30,7 +33,7 @@ static inline void mem1_poke(u8 *dst, u8 bv) { u32 *p = (u32*)(((u32)dst) & ~3); u32 val = *p; - + switch(((u32)dst) & 3) { case 0: val = (val & 0x00FFFFFF) | bv << 24; @@ -45,7 +48,7 @@ static inline void mem1_poke(u8 *dst, u8 bv) val = (val & 0xFFFFFF00) | bv; break; } - + *p = val; } @@ -133,7 +136,7 @@ void *patch_boot2(void *base, u64 titleID) boot2_patchelf(elf, titleID); parhdr->argument = 0x42; - + gecko_printf("Vector: %p\n", (void*)(((u32)parhdr) + parhdr->hdrsize)); return (void*)(((u32)parhdr) + parhdr->hdrsize); @@ -147,28 +150,28 @@ void *_main(void *base) gecko_init(); gecko_puts("MiniIOS v0.1 loading\n"); - fres = f_mount(0, &fatfs); - if(fres != FR_OK) { - gecko_printf("Error %d while trying to mount SD\n", fres); - panic2(0, PANIC_MOUNT); - } - + irq_initialize(); irq_enable(IRQ_TIMER); irq_enable(IRQ_NAND); irq_enable(IRQ_GPIO1B); irq_enable(IRQ_GPIO1); irq_enable(IRQ_RESET); - irq_enable(IRQ_IPC); gecko_puts("Interrupts initialized\n"); - gecko_puts("Trying to boot:" PPC_BOOT_FILE "\n"); + gecko_puts("Initializing IPC...\n"); + ipc_initialize(); - write32(HW_IPC_PPCMSG, 0); - write32(HW_IPC_ARMMSG, 0); - write32(HW_IPC_PPCCTRL, IPC_CTRL_SENT|IPC_CTRL_RECV); - write32(HW_IPC_ARMCTRL, IPC_CTRL_SENT|IPC_CTRL_RECV); + gecko_puts("Mounting SD...\n"); + fres = f_mount(0, &fatfs); + + if(fres != FR_OK) { + gecko_printf("Error %d while trying to mount SD\n", fres); + panic2(0, PANIC_MOUNT); + } + + gecko_puts("Trying to boot:" PPC_BOOT_FILE "\n"); res = powerpc_load_file(PPC_BOOT_FILE); if(res < 0) { @@ -176,25 +179,16 @@ void *_main(void *base) gecko_puts("Continuing anyway\n"); } - u32 tidh=0, tidl; - - while(1) { - if(read32(HW_IPC_ARMCTRL) & IPC_CTRL_RECV) { - tidh = read32(HW_IPC_PPCMSG); - write32(HW_IPC_ARMCTRL, read32(HW_IPC_ARMCTRL) | IPC_CTRL_RECV); - } - if(read32(HW_IPC_ARMCTRL) & IPC_CTRL_SENT) { - tidl = read32(HW_IPC_PPCMSG); - write32(HW_IPC_ARMCTRL, read32(HW_IPC_ARMCTRL) | IPC_CTRL_SENT); - break; - } - } - - void *bootmii = patch_boot2(base, (((u64)tidh)<<32) | tidl); - - gecko_puts("Shutting down interrupts\n"); + gecko_puts("Going into IPC mainloop...\n"); + ipc_process_slow(); + gecko_puts("IPC mainloop done!\n"); + gecko_puts("Shutting down IPC...\n"); + ipc_shutdown(); + gecko_puts("Shutting down interrupts...\n"); irq_shutdown(); - - gecko_puts("Returning to BootMii...\n"); - return bootmii; + + //vector = patch_boot2(base, (((u64)tidh)<<32) | tidl); + + gecko_printf("Vectoring to %p...\n",vector); + return vector; }