about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--gba/source/gamedata.c20
-rw-r--r--gba/source/link.c6
-rw-r--r--gba/source/main.c12
-rw-r--r--source/encoding.c12
-rw-r--r--source/main.c486
6 files changed, 268 insertions, 269 deletions
diff --git a/.gitignore b/.gitignore index ac7cf98..9f62bc6 100644 --- a/.gitignore +++ b/.gitignore
@@ -5,3 +5,4 @@ data
5tags 5tags
6*.o 6*.o
7*.d 7*.d
8*.swp
diff --git a/gba/source/gamedata.c b/gba/source/gamedata.c index 6868b2b..bbcf4dd 100644 --- a/gba/source/gamedata.c +++ b/gba/source/gamedata.c
@@ -244,11 +244,11 @@ bool initSaveData(
244 break; 244 break;
245 } 245 }
246 246
247 /// --- FR/LG --- 247 /// --- FR/LG ---
248 // In FR/LG, the function that initialises the save-block pointers to 248 // In FR/LG, the function that initialises the save-block pointers to
249 // default does not set up saveblock3. Which will need to be set up before 249 // default does not set up saveblock3. Which will need to be set up before
250 // loading the save if we want boxed Pokémon to not disappear. Oh, and 250 // loading the save if we want boxed Pokémon to not disappear. Oh, and
251 // loadsave() offset is different between FR and LG... 251 // loadsave() offset is different between FR and LG...
252 252
253 case 'DRPB': // FireRed German 253 case 'DRPB': // FireRed German
254 case 'DGPB': // LeafGreen German 254 case 'DGPB': // LeafGreen German
@@ -401,11 +401,11 @@ bool initSaveData(
401 break; 401 break;
402 } 402 }
403 403
404 /// --- Emerald --- 404 /// --- Emerald ---
405 // In Emerald, the saveblock pointer that isn't set up is saveblock1 (in 405 // In Emerald, the saveblock pointer that isn't set up is saveblock1 (in
406 // FR/LG it was saveblock3). The initial save loading code after the 406 // FR/LG it was saveblock3). The initial save loading code after the
407 // copyright screen is also updated, now it sets up ASLR/crypto here before 407 // copyright screen is also updated, now it sets up ASLR/crypto here before
408 // loading the save. 408 // loading the save.
409 409
410 case 'DEPB': // Emerald German 410 case 'DEPB': // Emerald German
411 { 411 {
diff --git a/gba/source/link.c b/gba/source/link.c index c84e44d..acadf3b 100644 --- a/gba/source/link.c +++ b/gba/source/link.c
@@ -12,8 +12,8 @@
12 12
13void initializeLink() 13void initializeLink()
14{ 14{
15 REG_HS_CTRL |= JOY_RW; 15 REG_HS_CTRL |= JOY_RW;
16 REG_JOYTR = 0; 16 REG_JOYTR = 0;
17 while ((REG_HS_CTRL & JOY_WRITE) == 0); 17 while ((REG_HS_CTRL & JOY_WRITE) == 0);
18 REG_HS_CTRL |= JOY_RW; 18 REG_HS_CTRL |= JOY_RW;
19} 19}
@@ -22,7 +22,7 @@ void waitForAck()
22{ 22{
23 while ((REG_HS_CTRL & JOY_WRITE) == 0); 23 while ((REG_HS_CTRL & JOY_WRITE) == 0);
24 REG_HS_CTRL |= JOY_RW; 24 REG_HS_CTRL |= JOY_RW;
25 REG_JOYTR = 0; 25 REG_JOYTR = 0;
26 while ((REG_HS_CTRL & JOY_WRITE) == 0); 26 while ((REG_HS_CTRL & JOY_WRITE) == 0);
27 REG_HS_CTRL |= JOY_RW; 27 REG_HS_CTRL |= JOY_RW;
28} 28}
diff --git a/gba/source/main.c b/gba/source/main.c index 9f97324..6207685 100644 --- a/gba/source/main.c +++ b/gba/source/main.c
@@ -10,7 +10,7 @@
10 10
11int main(void) 11int main(void)
12{ 12{
13 initializeLink(); 13 initializeLink();
14 14
15 // Identify the host game. 15 // Identify the host game.
16 if (GAME_RUBY) 16 if (GAME_RUBY)
@@ -30,9 +30,9 @@ int main(void)
30 sendS32(5); 30 sendS32(5);
31 } else { 31 } else {
32 sendS32(-1); 32 sendS32(-1);
33 waitForAck(); 33 waitForAck();
34 34
35 return 0; 35 return 0;
36 } 36 }
37 37
38 waitForAck(); 38 waitForAck();
@@ -46,9 +46,9 @@ int main(void)
46 { 46 {
47 // Unsupported game version. 47 // Unsupported game version.
48 sendS32(-1); 48 sendS32(-1);
49 waitForAck(); 49 waitForAck();
50 50
51 return 0; 51 return 0;
52 } 52 }
53 53
54 sendS32(1); 54 sendS32(1);
@@ -105,6 +105,4 @@ int main(void)
105 105
106 sendU32(tti); 106 sendU32(tti);
107 waitForAck(); 107 waitForAck();
108
109 // Halt();
110} 108}
diff --git a/source/encoding.c b/source/encoding.c index 7b70df2..0be1e0b 100644 --- a/source/encoding.c +++ b/source/encoding.c
@@ -10,14 +10,14 @@
10#include "encoding.h" 10#include "encoding.h"
11 11
12const char charmap[] = { 12const char charmap[] = {
13 ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!', '?', '.', '-', ' ', 13 ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!', '?', '.', '-', ' ',
14 ' ', '\"', '\"', '\'', '\'', '*', '*', ' ', ',', ' ', '/', 'A', 'B', 'C', 'D', 'E', 14 ' ', '\"', '\"', '\'', '\'', '*', '*', ' ', ',', ' ', '/', 'A', 'B', 'C', 'D', 'E',
15 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 15 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
16 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 16 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
17 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ' ' 17 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ' '
18}; 18};
19 19
20char debugGen3Decode(u8 val) 20char debugGen3Decode(u8 val)
21{ 21{
22 return charmap[val - 0xA0]; 22 return charmap[val - 0xA0];
23} 23}
diff --git a/source/main.c b/source/main.c index 8a9e672..128feb9 100644 --- a/source/main.c +++ b/source/main.c
@@ -27,7 +27,7 @@ void printmain()
27 printf("\x1b[2J"); 27 printf("\x1b[2J");
28 printf("\x1b[37m"); 28 printf("\x1b[37m");
29 printf("Pokemon Gen III Data Extractor by hatkirby\n"); 29 printf("Pokemon Gen III Data Extractor by hatkirby\n");
30 printf("Based on gba-gen3multiboot by slipstream/RoL\n"); 30 printf("Based on gba-gen3multiboot by slipstream/RoL\n");
31 printf("Based on GBA Link Cable Dumper v1.6 by FIX94\n"); 31 printf("Based on GBA Link Cable Dumper v1.6 by FIX94\n");
32} 32}
33 33
@@ -47,21 +47,21 @@ void acb(s32 res, u32 val)
47 47
48unsigned int docrc(u32 crc,u32 val) 48unsigned int docrc(u32 crc,u32 val)
49{ 49{
50 u32 result; 50 u32 result;
51 51
52 result = val ^ crc; 52 result = val ^ crc;
53 for (int i = 0; i < 0x20; i++) 53 for (int i = 0; i < 0x20; i++)
54 { 54 {
55 if (result & 1) 55 if (result & 1)
56 { 56 {
57 result >>= 1; 57 result >>= 1;
58 result ^= 0xA1C1; 58 result ^= 0xA1C1;
59 } else { 59 } else {
60 result >>= 1; 60 result >>= 1;
61 } 61 }
62 } 62 }
63 63
64 return result; 64 return result;
65} 65}
66 66
67void doreset() 67void doreset()
@@ -84,7 +84,7 @@ void getstatus()
84 84
85void endproc() 85void endproc()
86{ 86{
87 doreset(); 87 doreset();
88 printf("Start pressed, exit\n"); 88 printf("Start pressed, exit\n");
89 VIDEO_WaitVSync(); 89 VIDEO_WaitVSync();
90 VIDEO_WaitVSync(); 90 VIDEO_WaitVSync();
@@ -98,8 +98,8 @@ u32 recv()
98 transval = 0; 98 transval = 0;
99 SI_Transfer(1, cmdbuf, 1, resbuf, 5, transcb, SI_TRANS_DELAY); 99 SI_Transfer(1, cmdbuf, 1, resbuf, 5, transcb, SI_TRANS_DELAY);
100 100
101 while (transval == 0); 101 while (transval == 0);
102 printf("%08lx\n", *(vu32*)resbuf); 102 printf("%08lx\n", *(vu32*)resbuf);
103 return *(vu32*)resbuf; 103 return *(vu32*)resbuf;
104} 104}
105 105
@@ -137,113 +137,113 @@ void fatalError(char *msg)
137 137
138u32 genKeyA() 138u32 genKeyA()
139{ 139{
140 u32 retries = 0; 140 u32 retries = 0;
141 141
142 for (;;) 142 for (;;)
143 { 143 {
144 u32 key = 0; 144 u32 key = 0;
145 145
146 if (retries > 32) 146 if (retries > 32)
147 { 147 {
148 key = 0xDD654321; 148 key = 0xDD654321;
149 } else { 149 } else {
150 key = (rand() & 0x00ffffff) | 0xDD000000; 150 key = (rand() & 0x00ffffff) | 0xDD000000;
151 } 151 }
152 152
153 u32 unk = (key % 2 != 0); 153 u32 unk = (key % 2 != 0);
154 u32 v12 = key; 154 u32 v12 = key;
155 for (u32 v13 = 1; v13 < 32; v13++) 155 for (u32 v13 = 1; v13 < 32; v13++)
156 { 156 {
157 v12 >>= 1; 157 v12 >>= 1;
158 unk += (v12 % 2 != 0); 158 unk += (v12 % 2 != 0);
159 } 159 }
160 160
161 if ((unk >= 10 && unk <= 24)) 161 if ((unk >= 10 && unk <= 24))
162 { 162 {
163 if (retries > 4) 163 if (retries > 4)
164 { 164 {
165 printf("KeyA retries = %ld", retries); 165 printf("KeyA retries = %ld", retries);
166 } 166 }
167 167
168 printf("KeyA = 0x%08lx\n", key); 168 printf("KeyA = 0x%08lx\n", key);
169 169
170 return key; 170 return key;
171 } 171 }
172 172
173 retries++; 173 retries++;
174 } 174 }
175} 175}
176 176
177u32 checkKeyB(u32 KeyBRaw) 177u32 checkKeyB(u32 KeyBRaw)
178{ 178{
179 if ((KeyBRaw & 0xFF) != 0xEE) 179 if ((KeyBRaw & 0xFF) != 0xEE)
180 { 180 {
181 printf("Invalid KeyB - lowest 8 bits should be 0xEE, actually 0x%02x\n", 181 printf("Invalid KeyB - lowest 8 bits should be 0xEE, actually 0x%02x\n",
182 ((u8)(KeyBRaw))); 182 ((u8)(KeyBRaw)));
183 183
184 return 0; 184 return 0;
185 } 185 }
186 186
187 u32 KeyB = KeyBRaw & 0xffffff00; 187 u32 KeyB = KeyBRaw & 0xffffff00;
188 u32 val = KeyB; 188 u32 val = KeyB;
189 u32 unk = (val < 0); 189 u32 unk = (val < 0);
190 for (u32 i = 1; i < 24; i++) 190 for (u32 i = 1; i < 24; i++)
191 { 191 {
192 val <<= 1; 192 val <<= 1;
193 unk += (val < 0); 193 unk += (val < 0);
194 } 194 }
195 195
196 if (unk > 14) 196 if (unk > 14)
197 { 197 {
198 printf("Invalid KeyB - high 24 bits bad: 0x%08lx\n", KeyB); 198 printf("Invalid KeyB - high 24 bits bad: 0x%08lx\n", KeyB);
199 199
200 return 0; 200 return 0;
201 } 201 }
202 202
203 printf("Valid KeyB: 0x%08lx\n", KeyB); 203 printf("Valid KeyB: 0x%08lx\n", KeyB);
204 204
205 return KeyB; 205 return KeyB;
206} 206}
207 207
208u32 deriveKeyC(u32 keyCderive, u32 kcrc) 208u32 deriveKeyC(u32 keyCderive, u32 kcrc)
209{ 209{
210 u32 keyc = 0; 210 u32 keyc = 0;
211 u32 keyCi = 0; 211 u32 keyCi = 0;
212 212
213 do 213 do
214 { 214 {
215 u32 v5 = 0x1000000 * keyCi - 1; 215 u32 v5 = 0x1000000 * keyCi - 1;
216 u32 keyCattempt = docrc(kcrc,v5); 216 u32 keyCattempt = docrc(kcrc,v5);
217 217
218 if (keyCderive == keyCattempt) 218 if (keyCderive == keyCattempt)
219 { 219 {
220 keyc = v5; 220 keyc = v5;
221 221
222 printf("Found keyC: %08lx\n",keyc); 222 printf("Found keyC: %08lx\n",keyc);
223 223
224 return keyc; 224 return keyc;
225 } 225 }
226 226
227 keyCi++; 227 keyCi++;
228 } while (keyCi < 256); 228 } while (keyCi < 256);
229 229
230 return keyc; 230 return keyc;
231} 231}
232 232
233u32 getMsg() 233u32 getMsg()
234{ 234{
235 u32 val = 0; 235 u32 val = 0;
236 while (val == 0) 236 while (val == 0)
237 { 237 {
238 val = __builtin_bswap32(recv()); 238 val = __builtin_bswap32(recv());
239 sleep(1); 239 sleep(1);
240 } 240 }
241 241
242 send(0); 242 send(0);
243 while (recv()!=0) {sleep(1);}; 243 while (recv()!=0) {sleep(1);};
244 send(0); 244 send(0);
245 245
246 return val; 246 return val;
247} 247}
248 248
249int main(int argc, char *argv[]) 249int main(int argc, char *argv[])
@@ -272,11 +272,11 @@ int main(int argc, char *argv[])
272 { 272 {
273 printmain(); 273 printmain();
274 274
275 printf("Press A to begin, press Start to quit.\n"); 275 printf("Press A to begin, press Start to quit.\n");
276 if (waitForButtons(PAD_BUTTON_A | PAD_BUTTON_START) & PAD_BUTTON_START) 276 if (waitForButtons(PAD_BUTTON_A | PAD_BUTTON_START) & PAD_BUTTON_START)
277 { 277 {
278 endproc(); 278 endproc();
279 } 279 }
280 280
281 printf("Waiting for a GBA in port 2...\n"); 281 printf("Waiting for a GBA in port 2...\n");
282 resval = 0; 282 resval = 0;
@@ -300,7 +300,7 @@ int main(int argc, char *argv[])
300 VIDEO_WaitVSync(); 300 VIDEO_WaitVSync();
301 if (PAD_ButtonsHeld(0) & PAD_BUTTON_START) 301 if (PAD_ButtonsHeld(0) & PAD_BUTTON_START)
302 { 302 {
303 getstatus(); 303 getstatus();
304 endproc(); 304 endproc();
305 } 305 }
306 } 306 }
@@ -309,139 +309,139 @@ int main(int argc, char *argv[])
309 { 309 {
310 printf("GBA Found! Waiting on BIOS\n"); 310 printf("GBA Found! Waiting on BIOS\n");
311 311
312 resbuf[2]=0; 312 resbuf[2]=0;
313 313
314 // wait for the BIOS to hand over to the game 314 // wait for the BIOS to hand over to the game
315 do 315 do
316 { 316 {
317 doreset(); 317 doreset();
318 } while (!(resbuf[1] > 4)); 318 } while (!(resbuf[1] > 4));
319 319
320 printf("BIOS handed over to game, waiting on game\n"); 320 printf("BIOS handed over to game, waiting on game\n");
321 321
322 do 322 do
323 { 323 {
324 doreset(); 324 doreset();
325 } while ((resbuf[0] != 0) || !(resbuf[2] & 0x10)); 325 } while ((resbuf[0] != 0) || !(resbuf[2] & 0x10));
326 326
327 // receive the game-code from GBA side. 327 // receive the game-code from GBA side.
328 u32 gamecode = recv(); 328 u32 gamecode = recv();
329 329
330 printf("Ready, sending multiboot ROM\n"); 330 printf("Ready, sending multiboot ROM\n");
331 331
332 unsigned int sendsize = ((gba_mb_gba_size+7)&~7); 332 unsigned int sendsize = ((gba_mb_gba_size+7)&~7);
333 333
334 // generate KeyA 334 // generate KeyA
335 unsigned int ourkey = genKeyA(); 335 unsigned int ourkey = genKeyA();
336 336
337 //printf("Our Key: %08x\n", ourkey); 337 //printf("Our Key: %08x\n", ourkey);
338 printf("Sending game code that we got: 0x%08lx\n", 338 printf("Sending game code that we got: 0x%08lx\n",
339 __builtin_bswap32(gamecode)); 339 __builtin_bswap32(gamecode));
340 340
341 // send the game code back, then KeyA. 341 // send the game code back, then KeyA.
342 send(__builtin_bswap32(gamecode)); 342 send(__builtin_bswap32(gamecode));
343 send(ourkey); 343 send(ourkey);
344 344
345 // get KeyB from GBA, check it to make sure its valid, then xor with KeyA 345 // get KeyB from GBA, check it to make sure its valid, then xor with KeyA
346 // to derive the initial CRC value and the sessionkey. 346 // to derive the initial CRC value and the sessionkey.
347 u32 sessionkeyraw = 0; 347 u32 sessionkeyraw = 0;
348 do 348 do
349 { 349 {
350 sessionkeyraw = recv(); 350 sessionkeyraw = recv();
351 } while (sessionkeyraw == gamecode); 351 } while (sessionkeyraw == gamecode);
352 352
353 sessionkeyraw = checkKeyB(__builtin_bswap32(sessionkeyraw)); 353 sessionkeyraw = checkKeyB(__builtin_bswap32(sessionkeyraw));
354 if (sessionkeyraw == 0) 354 if (sessionkeyraw == 0)
355 { 355 {
356 warnError("Cannot continue.\n");
357
358 continue;
359 }
360
361 u32 sessionkey = sessionkeyraw ^ ourkey;
362 u32 kcrc = sessionkey;
363 printf("start kCRC=%08lx\n",kcrc);
364
365 sessionkey = (sessionkey*0x6177614b)+1;
366
367 // send hacked up send-size in uint32s
368 u32 hackedupsize = (sendsize >> 3) - 1;
369
370 printf("Sending hacked up size 0x%08lx\n",hackedupsize);
371 send(hackedupsize);
372
373 //unsigned int fcrc = 0x00bb;
374 // send over multiboot binary header, in the clear until the end of the
375 // nintendo logo. GBA checks this, if nintendo logo does not match the
376 // one in currently inserted cart's ROM, it will not accept any more data.
377 for (int i = 0; i < 0xA0; i+=4)
378 {
379 vu32 rom_dword = *(vu32*)(gba_mb_gba+i);
380 send(__builtin_bswap32(rom_dword));
381 }
382
383 printf("\n");
384 printf("Header done! Sending ROM...\n");
385
386 // Add each uint32 of the multiboot image to the checksum, encrypt the
387 // uint32 with the session key, increment the session key, send the
388 // encrypted uint32.
389 for (int i = 0xA0; i < sendsize; i+=4)
390 {
391 u32 dec = (
392 (((gba_mb_gba[i+3]) << 24) & 0xff000000) |
393 (((gba_mb_gba[i+2]) << 16) & 0x00ff0000) |
394 (((gba_mb_gba[i+1]) << 8) & 0x0000ff00) |
395 (((gba_mb_gba[i]) << 0) & 0x000000ff)
396 );
397
398 u32 enc = (dec - kcrc) ^ sessionkey;
399 kcrc = docrc(kcrc,dec);
400 sessionkey = (sessionkey * 0x6177614B) + 1;
401 //enc^=((~(i+(0x20<<20)))+1);
402 //enc^=0x6f646573;//0x20796220;
403
404 send(enc);
405 }
406
407 //fcrc |= (sendsize<<16);
408 printf("ROM done! CRC: %08lx\n", kcrc);
409 //get crc back (unused)
410
411 // Get KeyC derivation material from GBA (eventually)
412 u32 keyCderive = 0;
413 do
414 {
415 keyCderive = recv();
416 } while (keyCderive <= 0xfeffffff);
417
418 keyCderive = __builtin_bswap32(keyCderive);
419 keyCderive >>= 8;
420
421 printf("KeyC derivation material: %08lx\n",keyCderive);
422
423 // (try to) find the KeyC, using the checksum of the multiboot image, and
424 // the derivation material that GBA sent to us
425 u32 keyc = deriveKeyC(keyCderive,kcrc);
426 if (keyc == 0)
427 {
428 printf("Could not find keyC - kcrc=0x%08lx\n",kcrc);
429 warnError("Cannot continue.\n"); 356 warnError("Cannot continue.\n");
430 357
431 continue; 358 continue;
432 } 359 }
360
361 u32 sessionkey = sessionkeyraw ^ ourkey;
362 u32 kcrc = sessionkey;
363 printf("start kCRC=%08lx\n",kcrc);
364
365 sessionkey = (sessionkey*0x6177614b)+1;
366
367 // send hacked up send-size in uint32s
368 u32 hackedupsize = (sendsize >> 3) - 1;
369
370 printf("Sending hacked up size 0x%08lx\n",hackedupsize);
371 send(hackedupsize);
372
373 //unsigned int fcrc = 0x00bb;
374 // send over multiboot binary header, in the clear until the end of the
375 // nintendo logo. GBA checks this, if nintendo logo does not match the
376 // one in currently inserted cart's ROM, it will not accept any more data.
377 for (int i = 0; i < 0xA0; i+=4)
378 {
379 vu32 rom_dword = *(vu32*)(gba_mb_gba+i);
380 send(__builtin_bswap32(rom_dword));
381 }
382
383 printf("\n");
384 printf("Header done! Sending ROM...\n");
433 385
434 // derive the boot key from the found KeyC, and send to GBA. if this is 386 // Add each uint32 of the multiboot image to the checksum, encrypt the
387 // uint32 with the session key, increment the session key, send the
388 // encrypted uint32.
389 for (int i = 0xA0; i < sendsize; i+=4)
390 {
391 u32 dec = (
392 (((gba_mb_gba[i+3]) << 24) & 0xff000000) |
393 (((gba_mb_gba[i+2]) << 16) & 0x00ff0000) |
394 (((gba_mb_gba[i+1]) << 8) & 0x0000ff00) |
395 (((gba_mb_gba[i]) << 0) & 0x000000ff)
396 );
397
398 u32 enc = (dec - kcrc) ^ sessionkey;
399 kcrc = docrc(kcrc,dec);
400 sessionkey = (sessionkey * 0x6177614B) + 1;
401 //enc^=((~(i+(0x20<<20)))+1);
402 //enc^=0x6f646573;//0x20796220;
403
404 send(enc);
405 }
406
407 //fcrc |= (sendsize<<16);
408 printf("ROM done! CRC: %08lx\n", kcrc);
409 //get crc back (unused)
410
411 // Get KeyC derivation material from GBA (eventually)
412 u32 keyCderive = 0;
413 do
414 {
415 keyCderive = recv();
416 } while (keyCderive <= 0xfeffffff);
417
418 keyCderive = __builtin_bswap32(keyCderive);
419 keyCderive >>= 8;
420
421 printf("KeyC derivation material: %08lx\n",keyCderive);
422
423 // (try to) find the KeyC, using the checksum of the multiboot image, and
424 // the derivation material that GBA sent to us
425 u32 keyc = deriveKeyC(keyCderive,kcrc);
426 if (keyc == 0)
427 {
428 printf("Could not find keyC - kcrc=0x%08lx\n",kcrc);
429 warnError("Cannot continue.\n");
430
431 continue;
432 }
433
434 // derive the boot key from the found KeyC, and send to GBA. if this is
435 // not correct, GBA will not jump to the multiboot image it was sent. 435 // not correct, GBA will not jump to the multiboot image it was sent.
436 u32 bootkey = docrc(0xBB,keyc) | 0xbb000000; 436 u32 bootkey = docrc(0xBB,keyc) | 0xbb000000;
437 printf("BootKey = 0x%08lx\n",bootkey); 437 printf("BootKey = 0x%08lx\n",bootkey);
438 438
439 send(bootkey); 439 send(bootkey);
440 sleep(2); 440 sleep(2);
441 441
442 printf("Waiting for GBA...\n"); 442 printf("Waiting for GBA...\n");
443 while (recv() != 0) {sleep(1);}; 443 while (recv() != 0) {sleep(1);};
444 send(0); 444 send(0);
445 445
446 VIDEO_WaitVSync(); 446 VIDEO_WaitVSync();
447 447
@@ -471,9 +471,9 @@ int main(int argc, char *argv[])
471 } 471 }
472 472
473 printf("\n"); 473 printf("\n");
474 VIDEO_WaitVSync(); 474 VIDEO_WaitVSync();
475 475
476 u32 isValid = getMsg(); 476 u32 isValid = getMsg();
477 if (isValid == -1) 477 if (isValid == -1)
478 { 478 {
479 warnError("ERROR: Unsupported game version inserted!\n"); 479 warnError("ERROR: Unsupported game version inserted!\n");
@@ -501,22 +501,22 @@ int main(int argc, char *argv[])
501 501
502 printf("Trainer: "); 502 printf("Trainer: ");
503 503
504 for (int i = 0; i < 8; i++) 504 for (int i = 0; i < 8; i++)
505 { 505 {
506 if (trainerName[i] == 0xFF) 506 if (trainerName[i] == 0xFF)
507 { 507 {
508 break; 508 break;
509 } else { 509 } else {
510 printf("%c", debugGen3Decode(trainerName[i])); 510 printf("%c", debugGen3Decode(trainerName[i]));
511 } 511 }
512 } 512 }
513 513
514 printf(" (%ld)\n", trainerId); 514 printf(" (%ld)\n", trainerId);
515 515
516 // Wait for confirmation. 516 // Wait for confirmation.
517 printf("Press A to import the data from this game.\n"); 517 printf("Press A to import the data from this game.\n");
518 printf("Press B to cancel.\n"); 518 printf("Press B to cancel.\n");
519 VIDEO_WaitVSync(); 519 VIDEO_WaitVSync();
520 520
521 if (waitForButtons(PAD_BUTTON_A | PAD_BUTTON_B) & PAD_BUTTON_B) 521 if (waitForButtons(PAD_BUTTON_A | PAD_BUTTON_B) & PAD_BUTTON_B)
522 { 522 {