LEGO Indiana Jones
[savezelda.git] / twilight / twilight.c
1 // Copyright 2008-2009  Segher Boessenkool  <segher@kernel.crashing.org>
2 // This code is licensed to you under the terms of the GNU GPL, version 2;
3 // see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
4
5 #undef DEBUG_GECKO
6 #undef DEBUG_BLINK
7
8 typedef unsigned int u32;
9 typedef unsigned char u8;
10
11 int nand_open_E0(const char *path, void *buf, u32 mode);
12 int nand_open_E2(const char *path, void *buf, u32 mode);
13 int nand_open_J0(const char *path, void *buf, u32 mode);
14 int nand_open_P0(const char *path, void *buf, u32 mode);
15
16 int nand_read_E0(void *buf, void *dest, u32 len);
17 int nand_read_E2(void *buf, void *dest, u32 len);
18 int nand_read_J0(void *buf, void *dest, u32 len);
19 int nand_read_P0(void *buf, void *dest, u32 len);
20
21 void audio_stop_E0(void);
22 void audio_stop_E2(void);
23 void audio_stop_J0(void);
24 void audio_stop_P0(void);
25
26 void graphics_stop_E0(void);
27 void graphics_stop_E2(void);
28 void graphics_stop_J0(void);
29 void graphics_stop_P0(void);
30
31 static u8 nand_buf[0x100] __attribute__ ((aligned(0x40)));
32
33 #ifdef DEBUG_GECKO
34 void gecko_print(void *, const char *);
35
36 #define PRINT(x) gecko_print(0, x)
37 #define HEX(x) hex(x)
38
39 static void hex(u32 x)
40 {
41         u32 i;
42         u32 digit;
43         char s[10];
44
45         for (i = 0; i < 8; i++) {
46                 digit = x >> 28;
47                 x <<= 4;
48                 s[i] = digit + '0' + (digit < 10 ? 0 : 'a' - 10 - '0');
49         }
50         s[8] = '\n';
51         s[9] = 0;
52         PRINT(s);
53 }
54 #else
55 #define PRINT(x) do { } while (0)
56 #define HEX(x) do { } while (0)
57 #endif
58
59 static void sync_cache(void *p, u32 n)
60 {
61         u32 start, end;
62
63         start = (u32)p & ~31;
64         end = ((u32)p + n + 31) & ~31;
65         n = (end - start) >> 5;
66
67         while (n--) {
68                 asm("dcbst 0,%0 ; icbi 0,%0" : : "b"(p));
69                 p += 32;
70         }
71         asm("sync ; isync");
72 }
73
74 static void sync_before_read(void *p, u32 n)
75 {
76         u32 start, end;
77
78         start = (u32)p & ~31;
79         end = ((u32)p + n + 31) & ~31;
80         n = (end - start) >> 5;
81
82         while (n--) {
83                 asm("dcbf 0,%0" : : "b"(p));
84                 p += 32;
85         }
86         asm("sync");
87 }
88
89 static void jump(void *p, u32 arg)
90 {
91         PRINT("taking the plunge...\n");
92
93         asm("mr 3,%1 ; mtctr %0 ; bctrl" : : "r"(p), "r"(arg) : "r3");
94
95         PRINT("whoops, payload returned to us\n");
96 }
97
98 #ifdef DEBUG_BLINK
99 static u32 read32(u32 addr)
100 {
101         u32 x;
102
103         asm volatile("lwz %0,0(%1) ; sync" : "=r"(x) : "b"(0xc0000000 | addr));
104
105         return x;
106 }
107
108 static void write32(u32 addr, u32 x)
109 {
110         asm("stw %0,0(%1) ; eieio" : : "r"(x), "b"(0xc0000000 | addr));
111 }
112
113 static void blink(u32 colour)
114 {
115         u32 *fb = (u32 *)0xC0F00000;
116         u32 i;
117
118         // blink tray led
119         write32(0x0d8000c0, read32(0x0d8000c0) ^ 0x20);
120
121         for (i = 0; i < 640*576/2; i++)
122                 fb[i] = colour;
123 }
124 #else
125 #define blink(x) do { } while(0)
126 #endif
127
128 void __attribute__ ((noreturn)) main(u32 baddr)
129 {
130         int ret, i, len;
131         char *area;
132         char *gameid = (char *)0x80000000;
133         int (*nand_open)(const char *path, void *buf, u32 mode);
134         int (*nand_read)(void *buf, void *dest, u32 len);
135         void (*audio_stop)(void);
136         void (*graphics_stop)(void);
137
138         PRINT("Hello, Brave New World!\n");
139
140         baddr -= 0x2c0;
141
142         switch (gameid[3]) {
143         case 'E':
144                 if ((baddr>>16) == 0x8045) {
145                         nand_open = nand_open_E2;
146                         nand_read = nand_read_E2;
147                         audio_stop = audio_stop_E2;
148                         graphics_stop = graphics_stop_E2;
149                 } else {
150                         nand_open = nand_open_E0;
151                         nand_read = nand_read_E0;
152                         audio_stop = audio_stop_E0;
153                         graphics_stop = graphics_stop_E0;
154                 }
155                 break;
156         case 'P':
157                 nand_open = nand_open_P0;
158                 nand_read = nand_read_P0;
159                 audio_stop = audio_stop_P0;
160                 graphics_stop = graphics_stop_P0;
161                 break;
162         case 'J':
163                 nand_open = nand_open_J0;
164                 nand_read = nand_read_J0;
165                 audio_stop = audio_stop_J0;
166                 graphics_stop = graphics_stop_J0;
167                 break;
168         default:
169                 PRINT("unsupported game region\n");
170                 for (;;)
171                         ;
172         }
173
174         audio_stop();
175         graphics_stop();
176
177         blink(0x266a26c0); // maroon
178
179         ret = nand_open("zeldaTp.dat", nand_buf, 1);
180
181         blink(0x7140718a); // olive
182
183         PRINT("nand open --> ");
184         HEX(ret);
185
186         area = (void *)0x90000020;
187
188         // Skip past save game, to loader.bin
189         ret = nand_read(nand_buf, area, 0x4000);
190
191         len = 0;
192         for (i = 0; i < 0x40; i++) {
193                 PRINT("reading bootloader page: ");
194                 HEX(i);
195
196                 blink(0x40804080 + i*0x02000200); // grey
197
198                 sync_before_read(area + 0x1000*i, 0x1000);
199                 ret = nand_read(nand_buf, area + 0x1000*i, 0x1000);
200                 len += ret;
201
202                 blink(0x552b5515 + i*0x02000200); // lime
203
204                 PRINT("--> ");
205                 HEX(ret);
206                 PRINT("\n");
207         }
208
209         for (i = 0; i < 0x100; i++)
210                 HEX(((u32 *)area)[i]);
211
212         blink(0xc399c36a); // sky blue
213
214         sync_cache(area, len);
215         jump(area, 0x123);
216
217         blink(0x4c544cff); // red
218
219         PRINT("(shouldn't happen)\n");
220         for (;;)
221                 ;
222 }