-added some more cleanup code to the external loader to fix up even more random crashes on wii game bootup

This commit is contained in:
fix94.1 2014-03-31 14:33:24 +00:00
parent d7aed43333
commit 92b17333ef
15 changed files with 485 additions and 54 deletions

View File

@ -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

39
resources/extldr/cache.c Normal file
View File

@ -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 <segher@kernel.crashing.org>
// Copyright 2008-2009 Hector Martin <marcan@marcansoft.com>
#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");
}

21
resources/extldr/cache.h Normal file
View File

@ -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 <segher@kernel.crashing.org>
// Copyright 2008-2009 Hector Martin <marcan@marcansoft.com>
#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

292
resources/extldr/ios.c Normal file
View File

@ -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 <segher@kernel.crashing.org>
// Copyright 2008-2009 Andre Heider <dhewg@wiibrew.org>
// Copyright 2008-2009 Hector Martin <marcan@marcansoft.com>
#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);
}

28
resources/extldr/ios.h Normal file
View File

@ -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 <marcan@marcansoft.com>
#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

View File

@ -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"
);
}

View File

@ -1,23 +1,23 @@
// Copyright 2008-2009 Segher Boessenkool <segher@kernel.crashing.org>
// 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;
}

View File

@ -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

View File

@ -1,16 +0,0 @@
// Copyright 2008-2009 Segher Boessenkool <segher@kernel.crashing.org>
// 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");
}

View File

@ -1,6 +0,0 @@
#ifndef __SYNC_H_
#define __SYNC_H_
void sync_before_exec(const void *p, unsigned int len);
#endif

23
resources/extldr/types.h Normal file
View File

@ -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 <marcan@marcansoft.com>
#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

View File

@ -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;

30
resources/extldr/utils.c Normal file
View File

@ -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 <segher@kernel.crashing.org>
// Copyright 2008-2009 Andre Heider <dhewg@wiibrew.org>
// Copyright 2008-2009 Hector Martin <marcan@marcansoft.com>
#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)) ;
}

17
resources/extldr/utils.h Normal file
View File

@ -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 <marcan@marcansoft.com>
#ifndef __UTILS_H__
#define __UTILS_H__
#include "types.h"
void usleep(u32 us);
#endif

View File

@ -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"