From 92b17333efa465332b4b5684681aaa642539035d Mon Sep 17 00:00:00 2001 From: "fix94.1" Date: Mon, 31 Mar 2014 14:33:24 +0000 Subject: [PATCH] -added some more cleanup code to the external loader to fix up even more random crashes on wii game bootup --- resources/extldr/Makefile | 4 +- resources/extldr/cache.c | 39 +++++ resources/extldr/cache.h | 21 +++ resources/extldr/ios.c | 292 +++++++++++++++++++++++++++++++++++ resources/extldr/ios.h | 28 ++++ resources/extldr/main.c | 21 ++- resources/extldr/string.c | 14 +- resources/extldr/string.h | 4 +- resources/extldr/sync.c | 16 -- resources/extldr/sync.h | 6 - resources/extldr/types.h | 23 +++ resources/extldr/usbgecko.c | 23 ++- resources/extldr/utils.c | 30 ++++ resources/extldr/utils.h | 17 ++ source/homebrew/homebrew.cpp | 1 + 15 files changed, 485 insertions(+), 54 deletions(-) create mode 100644 resources/extldr/cache.c create mode 100644 resources/extldr/cache.h create mode 100644 resources/extldr/ios.c create mode 100644 resources/extldr/ios.h delete mode 100644 resources/extldr/sync.c delete mode 100644 resources/extldr/sync.h create mode 100644 resources/extldr/types.h create mode 100644 resources/extldr/utils.c create mode 100644 resources/extldr/utils.h diff --git a/resources/extldr/Makefile b/resources/extldr/Makefile index 3cf14293..060b382a 100644 --- a/resources/extldr/Makefile +++ b/resources/extldr/Makefile @@ -18,8 +18,8 @@ ASFLAGS = -D_LANGUAGE_ASSEMBLY -DHW_RVL TARGET_LINKED = boot.elf TARGET = extldr.bin -CFILES = string.c sync.c usbgecko.c main.c -OBJS = crt0.o string.o sync.o usbgecko.o main.o +CFILES = string.c ios.c utils.c cache.c usbgecko.c main.c +OBJS = crt0.o string.o ios.o utils.o cache.o usbgecko.o main.o DEPDIR = .deps diff --git a/resources/extldr/cache.c b/resources/extldr/cache.c new file mode 100644 index 00000000..85689d89 --- /dev/null +++ b/resources/extldr/cache.c @@ -0,0 +1,39 @@ +/* + TinyLoad - a simple region free (original) game launcher in 4k + +# This code is licensed to you under the terms of the GNU GPL, version 2; +# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt +*/ + +/* This code comes from the Twilight Hack */ +// Copyright 2008-2009 Segher Boessenkool +// Copyright 2008-2009 Hector Martin + +#include "types.h" + +void sync_before_read(void *p, u32 len) +{ + u32 a, b; + + a = (u32)p & ~0x1f; + b = ((u32)p + len + 0x1f) & ~0x1f; + + for ( ; a < b; a += 32) + asm("dcbi 0,%0" : : "b"(a) : "memory"); + + asm("sync ; isync"); +} + +void sync_after_write(const void *p, u32 len) +{ + u32 a, b; + + a = (u32)p & ~0x1f; + b = ((u32)p + len + 0x1f) & ~0x1f; + + for ( ; a < b; a += 32) + asm("dcbf 0,%0" : : "b"(a)); + + asm("sync ; isync"); +} + diff --git a/resources/extldr/cache.h b/resources/extldr/cache.h new file mode 100644 index 00000000..9c4c8e62 --- /dev/null +++ b/resources/extldr/cache.h @@ -0,0 +1,21 @@ +/* + TinyLoad - a simple region free (original) game launcher in 4k + +# This code is licensed to you under the terms of the GNU GPL, version 2; +# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt +*/ + +/* This code comes from the Twilight Hack */ +// Copyright 2008-2009 Segher Boessenkool +// Copyright 2008-2009 Hector Martin + +#ifndef __CACHE_H__ +#define __CACHE_H__ + +#include "types.h" + +void sync_before_read(void *p, u32 len); +void sync_after_write(const void *p, u32 len); + +#endif + diff --git a/resources/extldr/ios.c b/resources/extldr/ios.c new file mode 100644 index 00000000..d2df75b2 --- /dev/null +++ b/resources/extldr/ios.c @@ -0,0 +1,292 @@ +/* + TinyLoad - a simple region free (original) game launcher in 4k + +# This code is licensed to you under the terms of the GNU GPL, version 2; +# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt +*/ + +/* This code comes from HBC's stub which was based on the Twilight Hack code */ +// Copyright 2008-2009 Segher Boessenkool +// Copyright 2008-2009 Andre Heider +// Copyright 2008-2009 Hector Martin + +#include "ios.h" +#include "cache.h" +#include "utils.h" + +#define virt_to_phys(x) ((u32*)(((u32)(x))&0x3FFFFFFF)) +#define phys_to_virt(x) ((u32*)(((u32)(x))|0x80000000)) + +// Low-level IPC access. + +static inline u32 iread32(u32 addr) +{ + u32 x; + + asm volatile("lwz %0,0(%1) ; sync ; isync" : "=r"(x) : "b"(0xc0000000 | addr)); + + return x; +} + +static inline void iwrite32(u32 addr, u32 x) +{ + asm volatile("stw %0,0(%1) ; eieio" : : "r"(x), "b"(0xc0000000 | addr)); +} + +static u32 _ipc_read(u32 reg) __attribute__((noinline)); +static void _ipc_write(u32 reg, u32 value) __attribute__((noinline)); +static void ipc_bell(u32 w) __attribute__((noinline)); + +// inline the 4*, don't inline the 0x0d0 stuff. yes, this saves a few bytes. +static u32 _ipc_read(u32 reg) +{ + return iread32(0x0d000000 + reg); +} + +static void _ipc_write(u32 reg, u32 value) +{ + iwrite32(0x0d000000 + reg, value); +} + +static inline u32 ipc_read(u32 reg) +{ + return _ipc_read(4*reg); +} + +static inline void ipc_write(u32 reg, u32 value) +{ + _ipc_write(4*reg, value); +} + +static void ipc_bell(u32 w) +{ + ipc_write(1, w); +} + +static void ios_delay(void) __attribute__((noinline)); + +static void ios_delay(void) +{ + usleep(500); +} + +static void ipc_wait_ack(void) +{ + while(!(ipc_read(1) & 0x2)) + ; + ios_delay(); +} + +static void ipc_wait_reply(void) +{ + while(!(ipc_read(1) & 0x4)) + ; + ios_delay(); +} + +static u32 ipc_wait(void) +{ + u32 ret; + while(!((ret = ipc_read(1)) & 0x6)) + ; + ios_delay(); + return ret; +} + +// Mid-level IPC access. + +struct ipc { + u32 cmd; + int result; + int fd; + u32 arg[5]; + + u32 user[8]; +}; + +static struct ipc ipc ALIGNED(64); + +static void ipc_send_request(void) +{ + sync_after_write(&ipc, 0x40); + + ipc_write(0, (u32)virt_to_phys(&ipc)); + ipc_bell(1); + + ipc_wait_ack(); + + ipc_bell(2); +} + +static int ipc_send_twoack(void) +{ + sync_after_write(&ipc, 0x40); + ios_delay(); + + ipc_write(0, (u32)virt_to_phys(&ipc)); + ipc_bell(1); + + if(ipc_wait() & 4) + return 0; + + ipc_bell(2); + + if(ipc_wait() & 4) + return 0; + + ipc_bell(2); + ipc_bell(8); + return 1; +} + +static void ipc_recv_reply(void) +{ + for (;;) + { + u32 reply; + + ipc_wait_reply(); + + reply = ipc_read(2); + ipc_bell(4); + + ipc_bell(8); + + if (((u32*)reply) == virt_to_phys(&ipc)) + break; + } + + sync_before_read(&ipc, 0x40); +} + + +// High-level IPC access. + +void ios_cleanup() +{ + int loops = 0xA; + do + { + if ((ipc_read(1) & 0x22) == 0x22) + { + ipc_write(1, (ipc_read(1)&~0x30) | 2); + } + if ((ipc_read(1) & 0x14) == 0x14) + { + ipc_read(2); + ipc_write(1, (ipc_read(1)&~0x30) | 4); + ipc_write(12, 0x4000); + ipc_write(1, (ipc_read(1)&~0x30) | 8); + } + ipc_write(12, 0x4000); + usleep(1000); + loops--; + } while(loops != 0); + + int fd; + for (fd = 0; fd != 31; fd++) + { + ios_close(fd); + } +} + +int ios_open(const char *filename, u32 mode) +{ + sync_after_write((void*)filename, 0x20); + + ipc.cmd = 1; + ipc.fd = 0; + ipc.arg[0] = (u32)virt_to_phys(filename); + ipc.arg[1] = mode; + + ipc_send_request(); + ipc_recv_reply(); + + return ipc.result; +} + +int ios_close(int fd) +{ + ipc.cmd = 2; + ipc.fd = fd; + + ipc_send_request(); + ipc_recv_reply(); + + return ipc.result; +} + +static void ios_std(int fd, int cmd) +{ + ipc.cmd = cmd; + ipc.fd = fd; + + ipc_send_request(); + ipc_recv_reply(); +} + +int ios_read(int fd, void *buf, u32 size) +{ + ipc.arg[0] = (u32)virt_to_phys(buf); + ipc.arg[1] = size; + + ios_std(fd, 3); + + sync_before_read(buf, size); + + return ipc.result; +} + +int _ios_ioctlv(int fd, u32 n, u32 in_count, u32 out_count, struct ioctlv *vec, int reboot) +{ + u32 i; + + for (i = 0; i < in_count + out_count; i++) + { + if (vec[i].data) + { + sync_after_write(vec[i].data, vec[i].len); + vec[i].data = (void *)virt_to_phys(vec[i].data); + } + } + + sync_after_write(vec, (in_count + out_count) * sizeof *vec); + + ipc.cmd = 7; + ipc.fd = fd; + ipc.arg[0] = n; + ipc.arg[1] = in_count; + ipc.arg[2] = out_count; + ipc.arg[3] = (u32)virt_to_phys(vec); + + if(reboot) + { + if(ipc_send_twoack()) + return 0; + } + else + ipc_send_request(); + ipc_recv_reply(); + + for(i = in_count; i < in_count + out_count; i++) + { + if (vec[i].data) + { + vec[i].data = phys_to_virt((u32)vec[i].data); + sync_before_read(vec[i].data, vec[i].len); + } + } + if(reboot && (ipc.result >= 0)) + return -100; + return ipc.result; +} + +int ios_ioctlv(int fd, u32 n, u32 in_count, u32 out_count, struct ioctlv *vec) +{ + return _ios_ioctlv(fd, n, in_count, out_count, vec, 0); +} + +int ios_ioctlvreboot(int fd, u32 n, u32 in_count, u32 out_count, struct ioctlv *vec) +{ + return _ios_ioctlv(fd, n, in_count, out_count, vec, 1); +} diff --git a/resources/extldr/ios.h b/resources/extldr/ios.h new file mode 100644 index 00000000..1b11c957 --- /dev/null +++ b/resources/extldr/ios.h @@ -0,0 +1,28 @@ +/* + TinyLoad - a simple region free (original) game launcher in 4k + +# This code is licensed to you under the terms of the GNU GPL, version 2; +# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt +*/ + +#ifndef __IOS_H__ +#define __IOS_H__ + +// Copyright 2008-2009 Hector Martin + +#include "types.h" + +struct ioctlv { + void *data; + u32 len; +}; + +void ios_cleanup(void); +int ios_open(const char *filename, u32 mode); +int ios_close(int fd); +int ios_ioctlv(int fd, u32 n, u32 in_count, u32 out_count, struct ioctlv *vec); +int ios_ioctlvreboot(int fd, u32 n, u32 in_count, u32 out_count, struct ioctlv *vec); +int ios_read(int fd, void *buf, u32 size); + +#endif + diff --git a/resources/extldr/main.c b/resources/extldr/main.c index 0c80f026..321db8bb 100644 --- a/resources/extldr/main.c +++ b/resources/extldr/main.c @@ -1,16 +1,23 @@ +#include "types.h" #include "string.h" -#include "sync.h" +#include "cache.h" +#include "ios.h" #include "usbgecko.h" -typedef void (*entrypoint) (void); -static entrypoint exeEntryPoint = (entrypoint)0x80A80000; -static unsigned char *start = (unsigned char*)0x80A80000; -static unsigned char *buffer = (unsigned char*)0x90110000; +u8 *start = (u8*)0x80A80000; +u8 *buffer = (u8*)0x90110000; void _main(void) { usbgecko_init(); + ios_cleanup(); //hopefully that wont disable any features gprintf("Copying External Booter...\n"); _memcpy(start, buffer, 0xF0000); //960kb safe copying of booter - sync_before_exec(start, 0xF0000); + sync_after_write(start, 0xF0000); gprintf("Done! Jumping to Entrypoint...\n"); - exeEntryPoint(); + asm volatile ( + "lis %r3, start@h\n" + "ori %r3, %r3, start@l\n" + "lwz %r3, 0(%r3)\n" + "mtlr %r3\n" + "blr\n" + ); } \ No newline at end of file diff --git a/resources/extldr/string.c b/resources/extldr/string.c index bc4d00d5..707a6372 100644 --- a/resources/extldr/string.c +++ b/resources/extldr/string.c @@ -1,23 +1,23 @@ // Copyright 2008-2009 Segher Boessenkool // This code is licensed to you under the terms of the GNU GPL, version 2; // see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt - -void * _memset(void *b, int c, unsigned int len) +#include "types.h" +void * _memset(void *b, u8 c, u32 len) { - unsigned int i; + u32 i; for (i = 0; i < len; i++) - ((unsigned char *)b)[i] = c; + ((u8*)b)[i] = c; return b; } -void * _memcpy(void *dst, const void *src, unsigned int len) +void * _memcpy(void *dst, const void *src, u32 len) { - unsigned int i; + u32 i; for (i = 0; i < len; i++) - ((unsigned char *)dst)[i] = ((unsigned char *)src)[i]; + ((u8*)dst)[i] = ((u8*)src)[i]; return dst; } diff --git a/resources/extldr/string.h b/resources/extldr/string.h index bbbf4b92..a515223f 100644 --- a/resources/extldr/string.h +++ b/resources/extldr/string.h @@ -1,7 +1,7 @@ #ifndef STRING_H_ #define STRING_H_ -void * _memcpy(void *dst, const void *src, unsigned int len); -void * _memset(void *b, int c, unsigned int len); +void * _memcpy(void *dst, const void *src, u32 len); +void * _memset(void *b, u8 c, u32 len); #endif diff --git a/resources/extldr/sync.c b/resources/extldr/sync.c deleted file mode 100644 index 0c3ae04a..00000000 --- a/resources/extldr/sync.c +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2008-2009 Segher Boessenkool -// This code is licensed to you under the terms of the GNU GPL, version 2; -// see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt - -void sync_before_exec(const void *p, unsigned int len) -{ - unsigned int a, b; - - a = (unsigned int)p & ~0x1f; - b = ((unsigned int)p + len + 0x1f) & ~0x1f; - - for ( ; a < b; a += 32) - asm("dcbst 0,%0 ; sync ; icbi 0,%0" : : "b"(a)); - - asm("sync ; isync"); -} diff --git a/resources/extldr/sync.h b/resources/extldr/sync.h deleted file mode 100644 index 9fce35f1..00000000 --- a/resources/extldr/sync.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __SYNC_H_ -#define __SYNC_H_ - -void sync_before_exec(const void *p, unsigned int len); - -#endif diff --git a/resources/extldr/types.h b/resources/extldr/types.h new file mode 100644 index 00000000..992664a8 --- /dev/null +++ b/resources/extldr/types.h @@ -0,0 +1,23 @@ +/* + TinyLoad - a simple region free (original) game launcher in 4k + +# This code is licensed to you under the terms of the GNU GPL, version 2; +# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt +*/ + +// Copyright 2008-2009 Hector Martin + +#ifndef __TYPES_H__ +#define __TYPES_H__ + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; +typedef volatile unsigned int vu32; +#define NULL ((void *)0) + +#define ALIGNED(n) __attribute__((aligned(n))) + +#endif + diff --git a/resources/extldr/usbgecko.c b/resources/extldr/usbgecko.c index dfff2e8c..614632fc 100644 --- a/resources/extldr/usbgecko.c +++ b/resources/extldr/usbgecko.c @@ -1,6 +1,6 @@ #include "exi.h" #include "usbgecko.h" - +#include "types.h" #define USBGECKO_CMD_IDENTIFY 0x90000000 #define USBGECKO_IDENTIFY_RESPONSE 0x04700000 #define USBGECKO_CMD_TX_STATUS 0xc0000000 @@ -10,38 +10,33 @@ #define USBGECKO_CMD_RECEIVE 0xa0000000 #define USBGECKO_CMD_TRANSMIT(ch) (0xb0000000 | ((ch) << 20)) -/* We're poking registers; so ensure any access is volatile! */ -typedef volatile unsigned int vuint32_t; -typedef unsigned int uint32_t; - static int usb_gecko_channel = -1; -static uint32_t -usbgecko_transaction(int ch, uint32_t data) +static u32 usbgecko_transaction(int ch, u32 data) { volatile void* exi_base = (volatile void*)EXI_ADDR(ch); /* 5.9.1.2: Selecting a specific EXI device: select the USB Gecko device */ - *(vuint32_t*)(exi_base + EXI_CSR) = EXI_CSR_CLK_32MHZ | EXI_CSR_CS(1); + *(vu32*)(exi_base + EXI_CSR) = EXI_CSR_CLK_32MHZ | EXI_CSR_CS(1); /* 5.9.1.4: Perform IMM operation: setup data */ - *(vuint32_t*)(exi_base + EXI_DATA) = data; + *(vu32*)(exi_base + EXI_DATA) = data; /* 5.9.1.4: Perform IMM operation: schedule read/write; 2 bytes; start now */ - *(vuint32_t*)(exi_base + EXI_CR) = EXI_CR_TLEN_2 | EXI_CR_RW_RW | EXI_CR_TSTART; + *(vu32*)(exi_base + EXI_CR) = EXI_CR_TLEN_2 | EXI_CR_RW_RW | EXI_CR_TSTART; /* 5.9.1.4: Perform IMM operation: Wait until transfer is completed */ while (1) { - if ((*(vuint32_t*)(exi_base + EXI_CR) & EXI_CR_TSTART) == 0) + if ((*(vu32*)(exi_base + EXI_CR) & EXI_CR_TSTART) == 0) break; /* XXX barrier */ } /* 5.9.1.4: Fetch the data */ - data = *(vuint32_t*)(exi_base + EXI_DATA); + data = *(vu32*)(exi_base + EXI_DATA); /* 5.9.1.3: Deselecting EXI devices */ - *(vuint32_t*)(exi_base + EXI_CSR) = 0; + *(vu32*)(exi_base + EXI_CSR) = 0; return data; } @@ -80,7 +75,7 @@ void usbgecko_init() { int i; for (i = 0; i < 2; i++) { - uint32_t d = usbgecko_transaction(i, USBGECKO_CMD_IDENTIFY); + u32 d = usbgecko_transaction(i, USBGECKO_CMD_IDENTIFY); if (d != USBGECKO_IDENTIFY_RESPONSE) continue; usb_gecko_channel = i; diff --git a/resources/extldr/utils.c b/resources/extldr/utils.c new file mode 100644 index 00000000..03d3a711 --- /dev/null +++ b/resources/extldr/utils.c @@ -0,0 +1,30 @@ +/* + TinyLoad - a simple region free (original) game launcher in 4k + +# This code is licensed to you under the terms of the GNU GPL, version 2; +# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt +*/ + +/* This code comes from HBC's stub which was based on geckoloader and the Twilight Hack code */ +/* Some of these routines are from public domain sources */ +// Copyright 2008-2009 Segher Boessenkool +// Copyright 2008-2009 Andre Heider +// Copyright 2008-2009 Hector Martin + +#include "types.h" +#include "utils.h" + +static u32 get_time(void) +{ + u32 x; + + asm volatile("mftb %0" : "=r"(x)); + + return x; +} + +void usleep(u32 us) +{ + u32 _start = get_time(); + while ((get_time() - _start) < (91*us)) ; +} diff --git a/resources/extldr/utils.h b/resources/extldr/utils.h new file mode 100644 index 00000000..9424a262 --- /dev/null +++ b/resources/extldr/utils.h @@ -0,0 +1,17 @@ +/* + TinyLoad - a simple region free (original) game launcher in 4k + +# This code is licensed to you under the terms of the GNU GPL, version 2; +# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt +*/ + +// Copyright 2008-2009 Hector Martin + +#ifndef __UTILS_H__ +#define __UTILS_H__ + +#include "types.h" + +void usleep(u32 us); + +#endif diff --git a/source/homebrew/homebrew.cpp b/source/homebrew/homebrew.cpp index 62bf898e..f87556d3 100644 --- a/source/homebrew/homebrew.cpp +++ b/source/homebrew/homebrew.cpp @@ -152,6 +152,7 @@ void JumpToEntry(entry EntryPoint) u32 level = IRQ_Disable(); __IOS_ShutdownSubsystems(); __exception_closeall(); + __lwp_thread_closeall(); //dont like it but whatever asm volatile ( "lis %r3, AppEntrypoint@h\n" "ori %r3, %r3, AppEntrypoint@l\n"