mirror of
https://github.com/lewurm/savezelda.git
synced 2024-11-17 16:19:21 +01:00
223 lines
4.3 KiB
C
223 lines
4.3 KiB
C
|
// 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
|
||
|
|
||
|
#undef DEBUG_GECKO
|
||
|
#undef DEBUG_BLINK
|
||
|
|
||
|
typedef unsigned int u32;
|
||
|
typedef unsigned char u8;
|
||
|
|
||
|
int nand_open_E0(const char *path, void *buf, u32 mode);
|
||
|
int nand_open_E2(const char *path, void *buf, u32 mode);
|
||
|
int nand_open_J0(const char *path, void *buf, u32 mode);
|
||
|
int nand_open_P0(const char *path, void *buf, u32 mode);
|
||
|
|
||
|
int nand_read_E0(void *buf, void *dest, u32 len);
|
||
|
int nand_read_E2(void *buf, void *dest, u32 len);
|
||
|
int nand_read_J0(void *buf, void *dest, u32 len);
|
||
|
int nand_read_P0(void *buf, void *dest, u32 len);
|
||
|
|
||
|
void audio_stop_E0(void);
|
||
|
void audio_stop_E2(void);
|
||
|
void audio_stop_J0(void);
|
||
|
void audio_stop_P0(void);
|
||
|
|
||
|
void graphics_stop_E0(void);
|
||
|
void graphics_stop_E2(void);
|
||
|
void graphics_stop_J0(void);
|
||
|
void graphics_stop_P0(void);
|
||
|
|
||
|
static u8 nand_buf[0x100] __attribute__ ((aligned(0x40)));
|
||
|
|
||
|
#ifdef DEBUG_GECKO
|
||
|
void gecko_print(void *, const char *);
|
||
|
|
||
|
#define PRINT(x) gecko_print(0, x)
|
||
|
#define HEX(x) hex(x)
|
||
|
|
||
|
static void hex(u32 x)
|
||
|
{
|
||
|
u32 i;
|
||
|
u32 digit;
|
||
|
char s[10];
|
||
|
|
||
|
for (i = 0; i < 8; i++) {
|
||
|
digit = x >> 28;
|
||
|
x <<= 4;
|
||
|
s[i] = digit + '0' + (digit < 10 ? 0 : 'a' - 10 - '0');
|
||
|
}
|
||
|
s[8] = '\n';
|
||
|
s[9] = 0;
|
||
|
PRINT(s);
|
||
|
}
|
||
|
#else
|
||
|
#define PRINT(x) do { } while (0)
|
||
|
#define HEX(x) do { } while (0)
|
||
|
#endif
|
||
|
|
||
|
static void sync_cache(void *p, u32 n)
|
||
|
{
|
||
|
u32 start, end;
|
||
|
|
||
|
start = (u32)p & ~31;
|
||
|
end = ((u32)p + n + 31) & ~31;
|
||
|
n = (end - start) >> 5;
|
||
|
|
||
|
while (n--) {
|
||
|
asm("dcbst 0,%0 ; icbi 0,%0" : : "b"(p));
|
||
|
p += 32;
|
||
|
}
|
||
|
asm("sync ; isync");
|
||
|
}
|
||
|
|
||
|
static void sync_before_read(void *p, u32 n)
|
||
|
{
|
||
|
u32 start, end;
|
||
|
|
||
|
start = (u32)p & ~31;
|
||
|
end = ((u32)p + n + 31) & ~31;
|
||
|
n = (end - start) >> 5;
|
||
|
|
||
|
while (n--) {
|
||
|
asm("dcbf 0,%0" : : "b"(p));
|
||
|
p += 32;
|
||
|
}
|
||
|
asm("sync");
|
||
|
}
|
||
|
|
||
|
static void jump(void *p, u32 arg)
|
||
|
{
|
||
|
PRINT("taking the plunge...\n");
|
||
|
|
||
|
asm("mr 3,%1 ; mtctr %0 ; bctrl" : : "r"(p), "r"(arg) : "r3");
|
||
|
|
||
|
PRINT("whoops, payload returned to us\n");
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUG_BLINK
|
||
|
static u32 read32(u32 addr)
|
||
|
{
|
||
|
u32 x;
|
||
|
|
||
|
asm volatile("lwz %0,0(%1) ; sync" : "=r"(x) : "b"(0xc0000000 | addr));
|
||
|
|
||
|
return x;
|
||
|
}
|
||
|
|
||
|
static void write32(u32 addr, u32 x)
|
||
|
{
|
||
|
asm("stw %0,0(%1) ; eieio" : : "r"(x), "b"(0xc0000000 | addr));
|
||
|
}
|
||
|
|
||
|
static void blink(u32 colour)
|
||
|
{
|
||
|
u32 *fb = (u32 *)0xC0F00000;
|
||
|
u32 i;
|
||
|
|
||
|
// blink tray led
|
||
|
write32(0x0d8000c0, read32(0x0d8000c0) ^ 0x20);
|
||
|
|
||
|
for (i = 0; i < 640*576/2; i++)
|
||
|
fb[i] = colour;
|
||
|
}
|
||
|
#else
|
||
|
#define blink(x) do { } while(0)
|
||
|
#endif
|
||
|
|
||
|
void __attribute__ ((noreturn)) main(u32 baddr)
|
||
|
{
|
||
|
int ret, i, len;
|
||
|
char *area;
|
||
|
char *gameid = (char *)0x80000000;
|
||
|
int (*nand_open)(const char *path, void *buf, u32 mode);
|
||
|
int (*nand_read)(void *buf, void *dest, u32 len);
|
||
|
void (*audio_stop)(void);
|
||
|
void (*graphics_stop)(void);
|
||
|
|
||
|
PRINT("Hello, Brave New World!\n");
|
||
|
|
||
|
baddr -= 0x2c0;
|
||
|
|
||
|
switch (gameid[3]) {
|
||
|
case 'E':
|
||
|
if ((baddr>>16) == 0x8045) {
|
||
|
nand_open = nand_open_E2;
|
||
|
nand_read = nand_read_E2;
|
||
|
audio_stop = audio_stop_E2;
|
||
|
graphics_stop = graphics_stop_E2;
|
||
|
} else {
|
||
|
nand_open = nand_open_E0;
|
||
|
nand_read = nand_read_E0;
|
||
|
audio_stop = audio_stop_E0;
|
||
|
graphics_stop = graphics_stop_E0;
|
||
|
}
|
||
|
break;
|
||
|
case 'P':
|
||
|
nand_open = nand_open_P0;
|
||
|
nand_read = nand_read_P0;
|
||
|
audio_stop = audio_stop_P0;
|
||
|
graphics_stop = graphics_stop_P0;
|
||
|
break;
|
||
|
case 'J':
|
||
|
nand_open = nand_open_J0;
|
||
|
nand_read = nand_read_J0;
|
||
|
audio_stop = audio_stop_J0;
|
||
|
graphics_stop = graphics_stop_J0;
|
||
|
break;
|
||
|
default:
|
||
|
PRINT("unsupported game region\n");
|
||
|
for (;;)
|
||
|
;
|
||
|
}
|
||
|
|
||
|
audio_stop();
|
||
|
graphics_stop();
|
||
|
|
||
|
blink(0x266a26c0); // maroon
|
||
|
|
||
|
ret = nand_open("zeldaTp.dat", nand_buf, 1);
|
||
|
|
||
|
blink(0x7140718a); // olive
|
||
|
|
||
|
PRINT("nand open --> ");
|
||
|
HEX(ret);
|
||
|
|
||
|
area = (void *)0x90000020;
|
||
|
|
||
|
// Skip past save game, to loader.bin
|
||
|
ret = nand_read(nand_buf, area, 0x4000);
|
||
|
|
||
|
len = 0;
|
||
|
for (i = 0; i < 0x40; i++) {
|
||
|
PRINT("reading bootloader page: ");
|
||
|
HEX(i);
|
||
|
|
||
|
blink(0x40804080 + i*0x02000200); // grey
|
||
|
|
||
|
sync_before_read(area + 0x1000*i, 0x1000);
|
||
|
ret = nand_read(nand_buf, area + 0x1000*i, 0x1000);
|
||
|
len += ret;
|
||
|
|
||
|
blink(0x552b5515 + i*0x02000200); // lime
|
||
|
|
||
|
PRINT("--> ");
|
||
|
HEX(ret);
|
||
|
PRINT("\n");
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < 0x100; i++)
|
||
|
HEX(((u32 *)area)[i]);
|
||
|
|
||
|
blink(0xc399c36a); // sky blue
|
||
|
|
||
|
sync_cache(area, len);
|
||
|
jump(area, 0x123);
|
||
|
|
||
|
blink(0x4c544cff); // red
|
||
|
|
||
|
PRINT("(shouldn't happen)\n");
|
||
|
for (;;)
|
||
|
;
|
||
|
}
|