mirror of
https://github.com/Fledge68/WiiFlow_Lite.git
synced 2024-11-27 13:44:15 +01:00
-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:
parent
d7aed43333
commit
92b17333ef
@ -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
39
resources/extldr/cache.c
Normal 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
21
resources/extldr/cache.h
Normal 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
292
resources/extldr/ios.c
Normal 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
28
resources/extldr/ios.h
Normal 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
|
||||
|
@ -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"
|
||||
);
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
@ -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
23
resources/extldr/types.h
Normal 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
|
||||
|
@ -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
30
resources/extldr/utils.c
Normal 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
17
resources/extldr/utils.h
Normal 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
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user