diff options
Diffstat (limited to 'source/main.c')
-rw-r--r-- | source/main.c | 1287 |
1 files changed, 828 insertions, 459 deletions
diff --git a/source/main.c b/source/main.c index 7fd5683..79fd2fc 100644 --- a/source/main.c +++ b/source/main.c | |||
@@ -1,4 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2017 hatkirby | ||
2 | * Copyright (C) 2016 FIX94 | 3 | * Copyright (C) 2016 FIX94 |
3 | * | 4 | * |
4 | * This software may be modified and distributed under the terms | 5 | * This software may be modified and distributed under the terms |
@@ -15,6 +16,7 @@ | |||
15 | #include <fcntl.h> | 16 | #include <fcntl.h> |
16 | #include <dirent.h> | 17 | #include <dirent.h> |
17 | #include <fat.h> | 18 | #include <fat.h> |
19 | #include "link.h" | ||
18 | 20 | ||
19 | //from my tests 50us seems to be the lowest | 21 | //from my tests 50us seems to be the lowest |
20 | //safe si transfer delay in between calls | 22 | //safe si transfer delay in between calls |
@@ -25,11 +27,12 @@ extern u32 gba_mb_gba_size; | |||
25 | 27 | ||
26 | void printmain() | 28 | void printmain() |
27 | { | 29 | { |
28 | printf("\x1b[2J"); | 30 | printf("\x1b[2J"); |
29 | printf("\x1b[37m"); | 31 | printf("\x1b[37m"); |
30 | printf("GBA Link Cable Dumper v1.6 by FIX94\n"); | 32 | printf("Pokemon Gen III Data Extractor by hatkirby\n"); |
31 | printf("Save Support based on SendSave by Chishm\n"); | 33 | printf("Based on GBA Link Cable Dumper v1.6 by FIX94\n"); |
32 | printf("GBA BIOS Dumper by Dark Fader\n \n"); | 34 | printf("Save Support based on SendSave by Chishm\n"); |
35 | printf("Save Structure based on gba-gen3multiboot by slipstream/RoL\n"); | ||
33 | } | 36 | } |
34 | 37 | ||
35 | u8 *resbuf,*cmdbuf; | 38 | u8 *resbuf,*cmdbuf; |
@@ -37,520 +40,886 @@ u8 *resbuf,*cmdbuf; | |||
37 | volatile u32 transval = 0; | 40 | volatile u32 transval = 0; |
38 | void transcb(s32 chan, u32 ret) | 41 | void transcb(s32 chan, u32 ret) |
39 | { | 42 | { |
40 | transval = 1; | 43 | transval = 1; |
41 | } | 44 | } |
42 | 45 | ||
43 | volatile u32 resval = 0; | 46 | volatile u32 resval = 0; |
44 | void acb(s32 res, u32 val) | 47 | void acb(s32 res, u32 val) |
45 | { | 48 | { |
46 | resval = val; | 49 | resval = val; |
47 | } | 50 | } |
48 | 51 | /* | |
49 | unsigned int docrc(u32 crc, u32 val) | 52 | unsigned int docrc(u32 crc, u32 val) |
50 | { | 53 | { |
51 | int i; | 54 | int i; |
52 | for(i = 0; i < 0x20; i++) | 55 | for (i = 0; i < 0x20; i++) |
53 | { | 56 | { |
54 | if((crc^val)&1) | 57 | if ((crc ^ val) & 1) |
55 | { | 58 | { |
56 | crc>>=1; | 59 | crc>>=1; |
57 | crc^=0xa1c1; | 60 | crc^=0xa1c1; |
58 | } | 61 | } else { |
59 | else | 62 | crc>>=1; |
60 | crc>>=1; | 63 | } |
61 | val>>=1; | 64 | |
65 | val>>=1; | ||
66 | } | ||
67 | |||
68 | return crc; | ||
69 | }*/ | ||
70 | unsigned int docrc(u32 crc,u32 val) { | ||
71 | u32 result; | ||
72 | |||
73 | result = val ^ crc; | ||
74 | for (int i = 0; i < 0x20; i++) { | ||
75 | if (result & 1) { | ||
76 | result >>= 1; | ||
77 | result ^= 0xA1C1; | ||
78 | } else result >>= 1; | ||
62 | } | 79 | } |
63 | return crc; | 80 | return result; |
64 | } | 81 | } |
65 | 82 | ||
66 | void endproc() | ||
67 | { | ||
68 | printf("Start pressed, exit\n"); | ||
69 | VIDEO_WaitVSync(); | ||
70 | VIDEO_WaitVSync(); | ||
71 | exit(0); | ||
72 | } | ||
73 | void fixFName(char *str) | 83 | void fixFName(char *str) |
74 | { | 84 | { |
75 | u8 i = 0; | 85 | u8 i = 0; |
76 | for(i = 0; i < strlen(str); ++i) | 86 | for (i = 0; i < strlen(str); ++i) |
77 | { | 87 | { |
78 | if(str[i] < 0x20 || str[i] > 0x7F) | 88 | if (str[i] < 0x20 || str[i] > 0x7F) |
79 | str[i] = '_'; | 89 | { |
80 | else switch(str[i]) | 90 | str[i] = '_'; |
81 | { | 91 | } else { |
82 | case '\\': | 92 | switch (str[i]) |
83 | case '/': | 93 | { |
84 | case ':': | 94 | case '\\': |
85 | case '*': | 95 | case '/': |
86 | case '?': | 96 | case ':': |
87 | case '\"': | 97 | case '*': |
88 | case '<': | 98 | case '?': |
89 | case '>': | 99 | case '\"': |
90 | case '|': | 100 | case '<': |
91 | str[i] = '_'; | 101 | case '>': |
92 | break; | 102 | case '|': |
93 | default: | 103 | str[i] = '_'; |
94 | break; | 104 | break; |
95 | } | 105 | default: |
96 | } | 106 | break; |
107 | } | ||
108 | } | ||
109 | } | ||
97 | } | 110 | } |
111 | |||
98 | unsigned int calckey(unsigned int size) | 112 | unsigned int calckey(unsigned int size) |
99 | { | 113 | { |
100 | unsigned int ret = 0; | 114 | unsigned int ret = 0; |
101 | size=(size-0x200) >> 3; | 115 | size= (size - 0x200) >> 3; |
102 | int res1 = (size&0x3F80) << 1; | 116 | int res1 = (size & 0x3F80) << 1; |
103 | res1 |= (size&0x4000) << 2; | 117 | res1 |= (size & 0x4000) << 2; |
104 | res1 |= (size&0x7F); | 118 | res1 |= (size & 0x7F); |
105 | res1 |= 0x380000; | 119 | res1 |= 0x380000; |
106 | int res2 = res1; | 120 | int res2 = res1; |
107 | res1 = res2 >> 0x10; | 121 | res1 = res2 >> 0x10; |
108 | int res3 = res2 >> 8; | 122 | int res3 = res2 >> 8; |
109 | res3 += res1; | 123 | res3 += res1; |
110 | res3 += res2; | 124 | res3 += res2; |
111 | res3 <<= 24; | 125 | res3 <<= 24; |
112 | res3 |= res2; | 126 | res3 |= res2; |
113 | res3 |= 0x80808080; | 127 | res3 |= 0x80808080; |
114 | 128 | ||
115 | if((res3&0x200) == 0) | 129 | if ((res3 & 0x200) == 0) |
116 | { | 130 | { |
117 | ret |= (((res3)&0xFF)^0x4B)<<24; | 131 | ret |= (((res3) & 0xFF) ^ 0x4B) << 24; |
118 | ret |= (((res3>>8)&0xFF)^0x61)<<16; | 132 | ret |= (((res3>>8) & 0xFF) ^ 0x61) << 16; |
119 | ret |= (((res3>>16)&0xFF)^0x77)<<8; | 133 | ret |= (((res3>>16) & 0xFF) ^ 0x77) << 8; |
120 | ret |= (((res3>>24)&0xFF)^0x61); | 134 | ret |= (((res3>>24) & 0xFF) ^ 0x61); |
121 | } | 135 | } else { |
122 | else | 136 | ret |= (((res3) & 0xFF) ^ 0x73) << 24; |
123 | { | 137 | ret |= (((res3>>8) & 0xFF) ^ 0x65) << 16; |
124 | ret |= (((res3)&0xFF)^0x73)<<24; | 138 | ret |= (((res3>>16) & 0xFF) ^ 0x64) << 8; |
125 | ret |= (((res3>>8)&0xFF)^0x65)<<16; | 139 | ret |= (((res3>>24) & 0xFF) ^ 0x6F); |
126 | ret |= (((res3>>16)&0xFF)^0x64)<<8; | 140 | } |
127 | ret |= (((res3>>24)&0xFF)^0x6F); | 141 | |
128 | } | 142 | return ret; |
129 | return ret; | ||
130 | } | 143 | } |
144 | |||
131 | void doreset() | 145 | void doreset() |
132 | { | 146 | { |
133 | cmdbuf[0] = 0xFF; //reset | 147 | cmdbuf[0] = 0xFF; //reset |
134 | transval = 0; | 148 | transval = 0; |
135 | SI_Transfer(1,cmdbuf,1,resbuf,3,transcb,SI_TRANS_DELAY); | 149 | SI_Transfer(1, cmdbuf, 1, resbuf, 3, transcb, SI_TRANS_DELAY); |
136 | while(transval == 0) ; | 150 | |
151 | while (transval == 0); | ||
137 | } | 152 | } |
153 | |||
138 | void getstatus() | 154 | void getstatus() |
139 | { | 155 | { |
140 | cmdbuf[0] = 0; //status | 156 | cmdbuf[0] = 0; //status |
141 | transval = 0; | 157 | transval = 0; |
142 | SI_Transfer(1,cmdbuf,1,resbuf,3,transcb,SI_TRANS_DELAY); | 158 | SI_Transfer(1, cmdbuf, 1, resbuf, 3, transcb, SI_TRANS_DELAY); |
143 | while(transval == 0) ; | 159 | |
160 | while (transval == 0); | ||
161 | } | ||
162 | |||
163 | void endproc() | ||
164 | { | ||
165 | doreset(); | ||
166 | printf("Start pressed, exit\n"); | ||
167 | VIDEO_WaitVSync(); | ||
168 | VIDEO_WaitVSync(); | ||
169 | exit(0); | ||
170 | } | ||
171 | |||
172 | void fsleep(int i) | ||
173 | { | ||
174 | sleep(i); | ||
175 | /*PAD_ScanPads(); | ||
176 | if (PAD_ButtonsDown(0) & PAD_BUTTON_START) | ||
177 | { | ||
178 | getstatus(); | ||
179 | endproc(); | ||
180 | }*/ | ||
144 | } | 181 | } |
182 | |||
145 | u32 recv() | 183 | u32 recv() |
146 | { | 184 | { |
147 | memset(resbuf,0,32); | 185 | memset(resbuf,0,32); |
148 | cmdbuf[0]=0x14; //read | 186 | cmdbuf[0]=0x14; //read |
149 | transval = 0; | 187 | transval = 0; |
150 | SI_Transfer(1,cmdbuf,1,resbuf,5,transcb,SI_TRANS_DELAY); | 188 | SI_Transfer(1, cmdbuf, 1, resbuf, 5, transcb, SI_TRANS_DELAY); |
151 | while(transval == 0) ; | 189 | |
152 | return *(vu32*)resbuf; | 190 | while (transval == 0); |
191 | printf("%08lx\n", *(vu32*)resbuf); | ||
192 | return *(vu32*)resbuf; | ||
153 | } | 193 | } |
194 | |||
154 | void send(u32 msg) | 195 | void send(u32 msg) |
155 | { | 196 | { |
156 | cmdbuf[0]=0x15;cmdbuf[1]=(msg>>0)&0xFF;cmdbuf[2]=(msg>>8)&0xFF; | 197 | cmdbuf[0] = 0x15; |
157 | cmdbuf[3]=(msg>>16)&0xFF;cmdbuf[4]=(msg>>24)&0xFF; | 198 | cmdbuf[1] = (msg >> 0) & 0xFF; |
158 | transval = 0; | 199 | cmdbuf[2] = (msg >> 8) & 0xFF; |
159 | resbuf[0] = 0; | 200 | cmdbuf[3] = (msg >> 16) & 0xFF; |
160 | SI_Transfer(1,cmdbuf,5,resbuf,1,transcb,SI_TRANS_DELAY); | 201 | cmdbuf[4] = (msg >> 24) & 0xFF; |
161 | while(transval == 0) ; | 202 | |
203 | transval = 0; | ||
204 | resbuf[0] = 0; | ||
205 | SI_Transfer(1, cmdbuf, 5, resbuf, 1, transcb, SI_TRANS_DELAY); | ||
206 | |||
207 | while (transval == 0); | ||
162 | } | 208 | } |
209 | |||
163 | bool dirExists(const char *path) | 210 | bool dirExists(const char *path) |
164 | { | 211 | { |
165 | DIR *dir; | 212 | DIR *dir = opendir(path); |
166 | dir = opendir(path); | 213 | if (dir) |
167 | if(dir) | 214 | { |
168 | { | 215 | closedir(dir); |
169 | closedir(dir); | 216 | |
170 | return true; | 217 | return true; |
171 | } | 218 | } |
172 | return false; | 219 | |
220 | return false; | ||
173 | } | 221 | } |
222 | |||
174 | void createFile(const char *path, size_t size) | 223 | void createFile(const char *path, size_t size) |
175 | { | 224 | { |
176 | int fd = open(path, O_WRONLY|O_CREAT); | 225 | int fd = open(path, O_WRONLY | O_CREAT); |
177 | if(fd >= 0) | 226 | if (fd >= 0) |
178 | { | 227 | { |
179 | ftruncate(fd, size); | 228 | ftruncate(fd, size); |
180 | close(fd); | 229 | close(fd); |
181 | } | 230 | } |
182 | } | 231 | } |
232 | |||
183 | void warnError(char *msg) | 233 | void warnError(char *msg) |
184 | { | 234 | { |
185 | puts(msg); | 235 | puts(msg); |
186 | VIDEO_WaitVSync(); | 236 | VIDEO_WaitVSync(); |
187 | VIDEO_WaitVSync(); | 237 | VIDEO_WaitVSync(); |
188 | sleep(2); | 238 | sleep(2); |
189 | } | 239 | } |
240 | |||
190 | void fatalError(char *msg) | 241 | void fatalError(char *msg) |
191 | { | 242 | { |
192 | puts(msg); | 243 | puts(msg); |
193 | VIDEO_WaitVSync(); | 244 | VIDEO_WaitVSync(); |
194 | VIDEO_WaitVSync(); | 245 | VIDEO_WaitVSync(); |
195 | sleep(5); | 246 | sleep(5); |
196 | exit(0); | 247 | exit(0); |
197 | } | 248 | } |
198 | int main(int argc, char *argv[]) | 249 | |
199 | { | 250 | u32 genKeyA() { |
200 | void *xfb = NULL; | 251 | u32 retries = 0; |
201 | GXRModeObj *rmode = NULL; | 252 | while (true) { |
202 | VIDEO_Init(); | 253 | u32 key = 0; |
203 | rmode = VIDEO_GetPreferredMode(NULL); | 254 | if (retries > 32) { |
204 | xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); | 255 | key = 0xDD654321; |
205 | VIDEO_Configure(rmode); | 256 | } else { |
206 | VIDEO_SetNextFramebuffer(xfb); | 257 | key = (rand() & 0x00ffffff) | 0xDD000000; |
207 | VIDEO_SetBlack(FALSE); | 258 | } |
208 | VIDEO_Flush(); | 259 | u32 unk = (key % 2 != 0); |
209 | VIDEO_WaitVSync(); | 260 | u32 v12 = key; |
210 | if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync(); | 261 | for (u32 v13 = 1; v13 < 32; v13++) { |
211 | int x = 24, y = 32, w, h; | 262 | v12 >>= 1; |
212 | w = rmode->fbWidth - (32); | 263 | unk += (v12 % 2 != 0); |
213 | h = rmode->xfbHeight - (48); | 264 | } |
214 | CON_InitEx(rmode, x, y, w, h); | 265 | if ((unk >= 10 && unk <= 24)) { |
215 | VIDEO_ClearFrameBuffer(rmode, xfb, COLOR_BLACK); | 266 | if (retries > 4) printf("KeyA retries = %ld",retries); |
216 | PAD_Init(); | 267 | printf("KeyA = 0x%08lx\n",key); |
217 | cmdbuf = memalign(32,32); | 268 | return key; |
218 | resbuf = memalign(32,32); | 269 | } |
219 | u8 *testdump = memalign(32,0x400000); | 270 | retries++; |
220 | if(!testdump) return 0; | ||
221 | if(!fatInitDefault()) | ||
222 | { | ||
223 | printmain(); | ||
224 | fatalError("ERROR: No usable device found to write dumped files to!"); | ||
225 | } | 271 | } |
226 | mkdir("/dumps", S_IREAD | S_IWRITE); | 272 | } |
227 | if(!dirExists("/dumps")) | 273 | |
228 | { | 274 | u32 checkKeyB(u32 KeyBRaw) { |
229 | printmain(); | 275 | if ((KeyBRaw & 0xFF) != 0xEE) { |
230 | fatalError("ERROR: Could not create dumps folder, make sure you have a supported device connected!"); | 276 | printf("Invalid KeyB - lowest 8 bits should be 0xEE, actually 0x%02x\n",((u8)(KeyBRaw))); |
277 | return 0; | ||
231 | } | 278 | } |
232 | int i; | 279 | u32 KeyB = KeyBRaw & 0xffffff00; |
233 | while(1) | 280 | u32 val = KeyB; |
234 | { | 281 | u32 unk = (val < 0); |
235 | printmain(); | 282 | for (u32 i = 1; i < 24; i++) { |
236 | printf("Waiting for a GBA in port 2...\n"); | 283 | val <<= 1; |
237 | resval = 0; | 284 | unk += (val < 0); |
238 | 285 | } | |
239 | SI_GetTypeAsync(1,acb); | 286 | if (unk > 14) { |
240 | while(1) | 287 | printf("Invalid KeyB - high 24 bits bad: 0x%08lx\n",KeyB); |
241 | { | 288 | return 0; |
242 | if(resval) | 289 | } |
243 | { | 290 | printf("Valid KeyB: 0x%08lx\n",KeyB); |
244 | if(resval == 0x80 || resval & 8) | 291 | return KeyB; |
245 | { | 292 | } |
246 | resval = 0; | 293 | |
247 | SI_GetTypeAsync(1,acb); | 294 | u32 deriveKeyC(u32 keyCderive, u32 kcrc) { |
248 | } | 295 | u32 keyc = 0; |
249 | else if(resval) | 296 | u32 keyCi = 0; |
250 | break; | 297 | do { |
251 | } | 298 | u32 v5 = 0x1000000 * keyCi - 1; |
252 | PAD_ScanPads(); | 299 | u32 keyCattempt = docrc(kcrc,v5); |
253 | VIDEO_WaitVSync(); | 300 | //printf("i = %d; keyCderive = %08x; keyCattempt = %08x\n",keyCi,keyCderive,keyCattempt); |
254 | if(PAD_ButtonsHeld(0)) | 301 | if (keyCderive == keyCattempt) { |
255 | endproc(); | 302 | keyc = v5; |
303 | printf("Found keyC: %08lx\n",keyc); | ||
304 | return keyc; | ||
256 | } | 305 | } |
257 | if(resval & SI_GBA) | 306 | keyCi++; |
307 | } while (keyCi < 256); | ||
308 | return keyc; | ||
309 | } | ||
310 | |||
311 | int main(int argc, char *argv[]) | ||
312 | { | ||
313 | void *xfb = NULL; | ||
314 | GXRModeObj *rmode = NULL; | ||
315 | VIDEO_Init(); | ||
316 | rmode = VIDEO_GetPreferredMode(NULL); | ||
317 | xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); | ||
318 | VIDEO_Configure(rmode); | ||
319 | VIDEO_SetNextFramebuffer(xfb); | ||
320 | VIDEO_SetBlack(FALSE); | ||
321 | VIDEO_Flush(); | ||
322 | VIDEO_WaitVSync(); | ||
323 | if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync(); | ||
324 | int x = 24, y = 32, w, h; | ||
325 | w = rmode->fbWidth - (32); | ||
326 | h = rmode->xfbHeight - (48); | ||
327 | CON_InitEx(rmode, x, y, w, h); | ||
328 | VIDEO_ClearFrameBuffer(rmode, xfb, COLOR_BLACK); | ||
329 | PAD_Init(); | ||
330 | cmdbuf = memalign(32,32); | ||
331 | resbuf = memalign(32,32); | ||
332 | u8 *testdump = memalign(32,0x400000); | ||
333 | if(!testdump) return 0; | ||
334 | |||
335 | /*if (!fatInitDefault()) | ||
336 | { | ||
337 | printmain(); | ||
338 | fatalError("ERROR: No usable device found to write dumped files to!"); | ||
339 | } | ||
340 | |||
341 | mkdir("/dumps", S_IREAD | S_IWRITE); | ||
342 | if (!dirExists("/dumps")) | ||
343 | { | ||
344 | printmain(); | ||
345 | fatalError("ERROR: Could not create dumps folder, make sure you have a supported device connected!"); | ||
346 | }*/ | ||
347 | |||
348 | int i; | ||
349 | while(1) | ||
350 | { | ||
351 | printmain(); | ||
352 | |||
353 | printf("Press A to begin, press Start to quit.\n"); | ||
354 | if (waitForButtons(PAD_BUTTON_A | PAD_BUTTON_START) & PAD_BUTTON_START) | ||
258 | { | 355 | { |
259 | printf("GBA Found! Waiting on BIOS\n"); | 356 | endproc(); |
357 | } | ||
358 | |||
359 | printf("Waiting for a GBA in port 2...\n"); | ||
360 | resval = 0; | ||
361 | |||
362 | SI_GetTypeAsync(1,acb); | ||
363 | while(1) | ||
364 | { | ||
365 | if (resval) | ||
366 | { | ||
367 | if (resval == 0x80 || resval & 8) | ||
368 | { | ||
369 | resval = 0; | ||
370 | SI_GetTypeAsync(1,acb); | ||
371 | } else if (resval) | ||
372 | { | ||
373 | break; | ||
374 | } | ||
375 | } | ||
376 | |||
377 | PAD_ScanPads(); | ||
378 | VIDEO_WaitVSync(); | ||
379 | if (PAD_ButtonsHeld(0) & PAD_BUTTON_START) | ||
380 | { | ||
381 | getstatus(); | ||
382 | endproc(); | ||
383 | } | ||
384 | } | ||
385 | |||
386 | if (resval & SI_GBA) | ||
387 | { | ||
388 | printf("GBA Found! Waiting on BIOS\n"); | ||
260 | resbuf[2]=0; | 389 | resbuf[2]=0; |
261 | while(!(resbuf[2]&0x10)) | 390 | //u32 oldresult = 0; |
391 | //u32 newresult = 0; | ||
392 | // wait for the BIOS to hand over to the game | ||
393 | do { | ||
394 | doreset(); | ||
395 | |||
396 | } while (!(resbuf[1] > 4)); | ||
397 | printf("BIOS handed over to game, waiting on game\n"); | ||
398 | do | ||
262 | { | 399 | { |
263 | doreset(); | 400 | doreset(); |
264 | getstatus(); | 401 | } while((resbuf[0] != 0) || !(resbuf[2]&0x10)); |
265 | } | 402 | // receive the game-code from GBA side. |
266 | printf("Ready, sending dumper\n"); | 403 | u32 gamecode = recv(); |
404 | printf("Ready, sending multiboot ROM\n"); | ||
267 | unsigned int sendsize = ((gba_mb_gba_size+7)&~7); | 405 | unsigned int sendsize = ((gba_mb_gba_size+7)&~7); |
268 | unsigned int ourkey = calckey(sendsize); | 406 | // generate KeyA |
407 | unsigned int ourkey = genKeyA(); | ||
269 | //printf("Our Key: %08x\n", ourkey); | 408 | //printf("Our Key: %08x\n", ourkey); |
270 | //get current sessionkey | 409 | printf("Sending game code that we got: 0x%08lx\n",__builtin_bswap32(gamecode)); |
271 | u32 sessionkeyraw = recv(); | 410 | // send the game code back, then KeyA. |
272 | u32 sessionkey = __builtin_bswap32(sessionkeyraw^0x7365646F); | 411 | send(__builtin_bswap32(gamecode)); |
273 | //send over our own key | 412 | send(ourkey); |
274 | send(__builtin_bswap32(ourkey)); | 413 | // get KeyB from GBA, check it to make sure its valid, then xor with KeyA to derive the initial CRC value and the sessionkey. |
275 | unsigned int fcrc = 0x15a0; | 414 | u32 sessionkeyraw = 0; |
276 | //send over gba header | 415 | do { |
277 | for(i = 0; i < 0xC0; i+=4) | 416 | sessionkeyraw = recv(); |
278 | send(__builtin_bswap32(*(vu32*)(gba_mb_gba+i))); | 417 | } while (sessionkeyraw == gamecode); |
279 | //printf("Header done! Sending ROM...\n"); | 418 | sessionkeyraw = checkKeyB(__builtin_bswap32(sessionkeyraw)); |
280 | for(i = 0xC0; i < sendsize; i+=4) | 419 | if (sessionkeyraw == 0) |
281 | { | 420 | { |
282 | u32 enc = ((gba_mb_gba[i+3]<<24)|(gba_mb_gba[i+2]<<16)|(gba_mb_gba[i+1]<<8)|(gba_mb_gba[i])); | 421 | warnError("Cannot continue.\n"); |
283 | fcrc=docrc(fcrc,enc); | 422 | |
423 | continue; | ||
424 | } | ||
425 | |||
426 | u32 sessionkey = sessionkeyraw ^ ourkey; | ||
427 | u32 kcrc = sessionkey; | ||
428 | printf("start kCRC=%08lx\n",kcrc); | ||
429 | sessionkey = (sessionkey*0x6177614b)+1; | ||
430 | // send hacked up send-size in uint32s | ||
431 | u32 hackedupsize = (sendsize >> 3) - 1; | ||
432 | printf("Sending hacked up size 0x%08lx\n",hackedupsize); | ||
433 | send(hackedupsize); | ||
434 | //unsigned int fcrc = 0x00bb; | ||
435 | // send over multiboot binary header, in the clear until the end of the nintendo logo. | ||
436 | // GBA checks this, if nintendo logo does not match the one in currently inserted cart's ROM, it will not accept any more data. | ||
437 | for(i = 0; i < 0xA0; i+=4) { | ||
438 | vu32 rom_dword = *(vu32*)(gba_mb_gba+i); | ||
439 | send(__builtin_bswap32(rom_dword)); | ||
440 | } | ||
441 | printf("\n"); | ||
442 | printf("Header done! Sending ROM...\n"); | ||
443 | // Add each uint32 of the multiboot image to the checksum, encrypt the uint32 with the session key, increment the session key, send the encrypted uint32. | ||
444 | for(i = 0xA0; i < sendsize; i+=4) | ||
445 | { | ||
446 | u32 dec = ( | ||
447 | (((gba_mb_gba[i+3]) << 24) & 0xff000000) | | ||
448 | (((gba_mb_gba[i+2]) << 16) & 0x00ff0000) | | ||
449 | (((gba_mb_gba[i+1]) << 8) & 0x0000ff00) | | ||
450 | (((gba_mb_gba[i]) << 0) & 0x000000ff) | ||
451 | ); | ||
452 | u32 enc = (dec - kcrc) ^ sessionkey; | ||
453 | kcrc=docrc(kcrc,dec); | ||
284 | sessionkey = (sessionkey*0x6177614B)+1; | 454 | sessionkey = (sessionkey*0x6177614B)+1; |
285 | enc^=sessionkey; | 455 | //enc^=((~(i+(0x20<<20)))+1); |
286 | enc^=((~(i+(0x20<<20)))+1); | 456 | //enc^=0x6f646573;//0x20796220; |
287 | enc^=0x20796220; | ||
288 | send(enc); | 457 | send(enc); |
289 | } | 458 | } |
290 | fcrc |= (sendsize<<16); | 459 | //fcrc |= (sendsize<<16); |
291 | //printf("ROM done! CRC: %08x\n", fcrc); | 460 | printf("ROM done! CRC: %08lx\n", kcrc); |
292 | //send over CRC | ||
293 | sessionkey = (sessionkey*0x6177614B)+1; | ||
294 | fcrc^=sessionkey; | ||
295 | fcrc^=((~(i+(0x20<<20)))+1); | ||
296 | fcrc^=0x20796220; | ||
297 | send(fcrc); | ||
298 | //get crc back (unused) | 461 | //get crc back (unused) |
299 | recv(); | 462 | // Get KeyC derivation material from GBA (eventually) |
300 | printf("Done!\n"); | 463 | u32 keyCderive = 0; |
301 | sleep(2); | 464 | do { |
302 | //hm | 465 | keyCderive = recv(); |
303 | while(1) | 466 | } while (keyCderive <= 0xfeffffff); |
304 | { | 467 | keyCderive = __builtin_bswap32(keyCderive); |
305 | printmain(); | 468 | keyCderive >>= 8; |
306 | printf("Press A once you have a GBA Game inserted.\n"); | 469 | printf("KeyC derivation material: %08lx\n",keyCderive); |
307 | printf("Press Y to backup the GBA BIOS.\n \n"); | 470 | |
308 | PAD_ScanPads(); | 471 | // (try to) find the KeyC, using the checksum of the multiboot image, and the derivation material that GBA sent to us |
309 | VIDEO_WaitVSync(); | 472 | |
310 | u32 btns = PAD_ButtonsDown(0); | 473 | u32 keyc = deriveKeyC(keyCderive,kcrc); |
311 | if(btns&PAD_BUTTON_START) | 474 | if (keyc == 0) |
312 | endproc(); | ||
313 | else if(btns&PAD_BUTTON_A) | ||
314 | { | 475 | { |
315 | if(recv() == 0) //ready | 476 | printf("Could not find keyC - kcrc=0x%08lx\n",kcrc); |
316 | { | 477 | warnError("Cannot continue.\n"); |
317 | printf("Waiting for GBA\n"); | 478 | continue; |
318 | VIDEO_WaitVSync(); | 479 | } |
319 | int gbasize = 0; | 480 | |
320 | while(gbasize == 0) | 481 | // derive the boot key from the found KeyC, and send to GBA. if this is not correct, GBA will not jump to the multiboot image it was sent. |
321 | gbasize = __builtin_bswap32(recv()); | 482 | u32 bootkey = docrc(0xBB,keyc) | 0xbb000000; |
322 | send(0); //got gbasize | 483 | printf("BootKey = 0x%08lx\n",bootkey); |
323 | u32 savesize = __builtin_bswap32(recv()); | 484 | send(bootkey); |
324 | send(0); //got savesize | 485 | /* |
325 | if(gbasize == -1) | 486 | printf("GBA Found! Waiting on BIOS...\n"); |
326 | { | 487 | |
327 | warnError("ERROR: No (Valid) GBA Card inserted!\n"); | 488 | resbuf[2]=0; |
328 | continue; | 489 | while (!(resbuf[2] & 0x10)) |
329 | } | 490 | { |
330 | //get rom header | 491 | doreset(); |
331 | for(i = 0; i < 0xC0; i+=4) | 492 | getstatus(); |
332 | *(vu32*)(testdump+i) = recv(); | 493 | } |
333 | //print out all the info from the game | 494 | |
334 | printf("Game Name: %.12s\n",(char*)(testdump+0xA0)); | 495 | printf("Ready, sending extractor.\n"); |
335 | printf("Game ID: %.4s\n",(char*)(testdump+0xAC)); | 496 | |
336 | printf("Company ID: %.2s\n",(char*)(testdump+0xB0)); | 497 | unsigned int sendsize = ((gba_mb_gba_size + 7) & ~7); |
337 | printf("ROM Size: %02.02f MB\n",((float)(gbasize/1024))/1024.f); | 498 | unsigned int ourkey = calckey(sendsize); |
338 | if(savesize > 0) | 499 | |
339 | printf("Save Size: %02.02f KB\n \n",((float)(savesize))/1024.f); | 500 | //get current sessionkey |
340 | else | 501 | u32 sessionkeyraw = recv(); |
341 | printf("No Save File\n \n"); | 502 | u32 sessionkey = __builtin_bswap32(sessionkeyraw ^ 0x7365646F); |
342 | //generate file paths | 503 | |
343 | char gamename[64]; | 504 | //send over our own key |
344 | sprintf(gamename,"/dumps/%.12s [%.4s%.2s].gba", | 505 | send(__builtin_bswap32(ourkey)); |
345 | (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0)); | 506 | unsigned int fcrc = 0x15a0; |
346 | fixFName(gamename+7); //fix name behind "/dumps/" | 507 | |
347 | char savename[64]; | 508 | //send over gba header |
348 | sprintf(savename,"/dumps/%.12s [%.4s%.2s].sav", | 509 | for(i = 0; i < 0xC0; i+=4) |
349 | (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0)); | 510 | { |
350 | fixFName(savename+7); //fix name behind "/dumps/" | 511 | send(__builtin_bswap32(*(vu32*)(gba_mb_gba+i))); |
351 | //let the user choose the option | 512 | } |
352 | printf("Press A to dump this game, it will take about %i minutes.\n",gbasize/1024/1024*3/2); | 513 | |
353 | printf("Press B if you want to cancel dumping this game.\n"); | 514 | for (i = 0xC0; i < sendsize; i+=4) |
354 | if(savesize > 0) | 515 | { |
355 | { | 516 | u32 enc = ( |
356 | printf("Press Y to backup this save file.\n"); | 517 | (gba_mb_gba[i+3] << 24) |
357 | printf("Press X to restore this save file.\n"); | 518 | | (gba_mb_gba[i+2] << 16) |
358 | printf("Press Z to clear the save file on the GBA Cartridge.\n\n"); | 519 | | (gba_mb_gba[i+1] << 8) |
359 | } | 520 | | (gba_mb_gba[i])); |
360 | else | 521 | |
361 | printf("\n"); | 522 | fcrc = docrc(fcrc,enc); |
362 | int command = 0; | 523 | sessionkey = (sessionkey * 0x6177614B) + 1; |
363 | while(1) | 524 | enc ^= sessionkey; |
364 | { | 525 | enc ^= ((~(i + (0x20 << 20))) + 1); |
365 | PAD_ScanPads(); | 526 | enc ^= 0x20796220; |
366 | VIDEO_WaitVSync(); | 527 | |
367 | u32 btns = PAD_ButtonsDown(0); | 528 | send(enc); |
368 | if(btns&PAD_BUTTON_START) | 529 | } |
369 | endproc(); | 530 | |
370 | else if(btns&PAD_BUTTON_A) | 531 | fcrc |= (sendsize<<16); |
371 | { | 532 | |
372 | command = 1; | 533 | //send over CRC |
373 | break; | 534 | sessionkey = (sessionkey * 0x6177614B) + 1; |
374 | } | 535 | fcrc ^= sessionkey; |
375 | else if(btns&PAD_BUTTON_B) | 536 | fcrc ^= ((~(i + (0x20 << 20))) + 1); |
376 | break; | 537 | fcrc ^= 0x20796220; |
377 | else if(savesize > 0) | 538 | |
378 | { | 539 | send(fcrc); |
379 | if(btns&PAD_BUTTON_Y) | 540 | |
380 | { | 541 | //get crc back (unused) |
381 | command = 2; | 542 | recv(); |
382 | break; | 543 | printf("Done!\n"); |
383 | } | 544 | sleep(2); |
384 | else if(btns&PAD_BUTTON_X) | 545 | |
385 | { | 546 | //hm |
386 | command = 3; | 547 | while (1) |
387 | break; | 548 | { |
388 | } | 549 | printmain(); |
389 | else if(btns&PAD_TRIGGER_Z) | 550 | printf("Press A once you have a GBA Game inserted.\n \n"); |
390 | { | 551 | |
391 | command = 4; | 552 | PAD_ScanPads(); |
392 | break; | 553 | VIDEO_WaitVSync(); |
393 | } | 554 | u32 btns = PAD_ButtonsDown(0); |
394 | } | 555 | if (btns & PAD_BUTTON_START) |
395 | } | 556 | { |
396 | if(command == 1) | 557 | endproc(); |
397 | { | 558 | } else if (btns & PAD_BUTTON_A) |
398 | FILE *f = fopen(gamename,"rb"); | 559 | {*/ |
399 | if(f) | 560 | sleep(1); |
400 | { | 561 | //recv(); |
401 | fclose(f); | 562 | |
402 | command = 0; | 563 | //if (recv() == 0) //ready |
403 | warnError("ERROR: Game already dumped!\n"); | 564 | { |
404 | } | 565 | |
405 | } | 566 | printf("Waiting for GBA...\n"); |
406 | else if(command == 2) | 567 | while (recv() != 0) {fsleep(1);}; |
407 | { | 568 | send(0); |
408 | FILE *f = fopen(savename,"rb"); | 569 | |
409 | if(f) | 570 | VIDEO_WaitVSync(); |
410 | { | 571 | |
411 | fclose(f); | 572 | /*int gbasize = 0; |
412 | command = 0; | 573 | while(gbasize == 0) |
413 | warnError("ERROR: Save already backed up!\n"); | 574 | { |
414 | } | 575 | gbasize = __builtin_bswap32(recv()); |
415 | } | 576 | } |
416 | else if(command == 3) | 577 | |
417 | { | 578 | send(0); //got gbasize |
418 | size_t readsize = 0; | 579 | while (recv()!=0) {sleep(1);}; |
419 | FILE *f = fopen(savename,"rb"); | 580 | |
420 | if(f) | 581 | //u32 savesize = __builtin_bswap32(recv()); |
421 | { | 582 | //send(0); //got savesize |
422 | fseek(f,0,SEEK_END); | 583 | |
423 | readsize = ftell(f); | 584 | if (gbasize == -1) |
424 | if(readsize != savesize) | 585 | { |
425 | { | 586 | warnError("ERROR: No (Valid) GBA Card inserted!\n"); |
426 | command = 0; | 587 | |
427 | warnError("ERROR: Save has the wrong size, aborting restore!\n"); | 588 | continue; |
428 | } | 589 | }*/ |
429 | else | 590 | |
430 | { | 591 | // Get game |
431 | rewind(f); | 592 | // -1 - unsupported game |
432 | fread(testdump,readsize,1,f); | 593 | // 1 - Ruby |
433 | } | 594 | // 2 - Sapphire |
434 | fclose(f); | 595 | // 3 - FireRed |
435 | } | 596 | // 4 - LeafGreen |
436 | else | 597 | // 5 - Emerald |
437 | { | 598 | u32 gameId = 0; |
438 | command = 0; | 599 | while (gameId == 0) |
439 | warnError("ERROR: No Save to restore!\n"); | ||
440 | } | ||
441 | } | ||
442 | send(command); | ||
443 | //let gba prepare | ||
444 | sleep(1); | ||
445 | if(command == 0) | ||
446 | continue; | ||
447 | else if(command == 1) | ||
448 | { | 600 | { |
449 | //create base file with size | 601 | gameId = __builtin_bswap32(recv()); |
450 | printf("Preparing file...\n"); | 602 | fsleep(1); |
451 | createFile(gamename,gbasize); | ||
452 | FILE *f = fopen(gamename,"wb"); | ||
453 | if(!f) | ||
454 | fatalError("ERROR: Could not create file! Exit..."); | ||
455 | printf("Dumping...\n"); | ||
456 | u32 bytes_read = 0; | ||
457 | while(gbasize > 0) | ||
458 | { | ||
459 | int toread = (gbasize > 0x400000 ? 0x400000 : gbasize); | ||
460 | int j; | ||
461 | for(j = 0; j < toread; j+=4) | ||
462 | { | ||
463 | *(vu32*)(testdump+j) = recv(); | ||
464 | bytes_read+=4; | ||
465 | if((bytes_read&0xFFFF) == 0) | ||
466 | printf("\r%02.02f MB done",(float)(bytes_read/1024)/1024.f); | ||
467 | } | ||
468 | fwrite(testdump,toread,1,f); | ||
469 | gbasize -= toread; | ||
470 | } | ||
471 | printf("\nClosing file\n"); | ||
472 | fclose(f); | ||
473 | printf("Game dumped!\n"); | ||
474 | sleep(5); | ||
475 | } | 603 | } |
476 | else if(command == 2) | 604 | |
605 | send(0); | ||
606 | while (recv()!=0) {fsleep(1);}; | ||
607 | //sleep(1); | ||
608 | |||
609 | if (gameId == -1) | ||
610 | { | ||
611 | warnError("ERROR: Unsupported GBA game inserted!\n"); | ||
612 | |||
613 | continue; | ||
614 | } | ||
615 | |||
616 | printf("\nPokemon "); | ||
617 | switch (gameId) | ||
618 | { | ||
619 | case 1: printf("Ruby"); break; | ||
620 | case 2: printf("Sapphire"); break; | ||
621 | case 3: printf("FireRed"); break; | ||
622 | case 4: printf("LeafGreen"); break; | ||
623 | case 5: printf("Emerald"); break; | ||
624 | } | ||
625 | |||
626 | printf("\n"); | ||
627 | VIDEO_WaitVSync(); | ||
628 | |||
629 | u32 isValid = 0; | ||
630 | while (isValid == 0) | ||
477 | { | 631 | { |
478 | //create base file with size | 632 | isValid = __builtin_bswap32(recv()); |
479 | printf("Preparing file...\n"); | 633 | fsleep(1); |
480 | createFile(savename,savesize); | ||
481 | FILE *f = fopen(savename,"wb"); | ||
482 | if(!f) | ||
483 | fatalError("ERROR: Could not create file! Exit..."); | ||
484 | printf("Waiting for GBA\n"); | ||
485 | VIDEO_WaitVSync(); | ||
486 | u32 readval = 0; | ||
487 | while(readval != savesize) | ||
488 | readval = __builtin_bswap32(recv()); | ||
489 | send(0); //got savesize | ||
490 | printf("Receiving...\n"); | ||
491 | for(i = 0; i < savesize; i+=4) | ||
492 | *(vu32*)(testdump+i) = recv(); | ||
493 | printf("Writing save...\n"); | ||
494 | fwrite(testdump,savesize,1,f); | ||
495 | fclose(f); | ||
496 | printf("Save backed up!\n"); | ||
497 | sleep(5); | ||
498 | } | 634 | } |
499 | else if(command == 3 || command == 4) | 635 | |
636 | if (isValid == -1) | ||
637 | { | ||
638 | //send(0); | ||
639 | |||
640 | warnError("ERROR: Unsupported game version inserted!\n"); | ||
641 | |||
642 | continue; | ||
643 | } | ||
644 | |||
645 | send(0); | ||
646 | while (recv()!=0) {fsleep(1);}; | ||
647 | //sleep(1); | ||
648 | /* | ||
649 | // Get trainer name | ||
650 | u8 trainerName[8]; | ||
651 | |||
652 | u32 tnd = recv(); | ||
653 | send(0); | ||
654 | trainerName[0] = (tnd & 0xFF000000); | ||
655 | trainerName[1] = (tnd & 0x00FF0000) >> 8; | ||
656 | trainerName[2] = (tnd & 0x0000FF00) >> 16; | ||
657 | trainerName[3] = (tnd & 0x000000FF) >> 24; | ||
658 | |||
659 | tnd = recv(); | ||
660 | send(0); | ||
661 | trainerName[4] = (tnd & 0xFF000000); | ||
662 | trainerName[5] = (tnd & 0x00FF0000) >> 8; | ||
663 | trainerName[6] = (tnd & 0x0000FF00) >> 16; | ||
664 | trainerName[7] = (tnd & 0x000000FF) >> 24; | ||
665 | |||
666 | printf("Trainer: %s", (char*) trainerName); | ||
667 | */ | ||
668 | // Get trainer ID | ||
669 | u32 trainerId = 0; | ||
670 | while (trainerId == 0) | ||
500 | { | 671 | { |
501 | u32 readval = 0; | 672 | trainerId = __builtin_bswap32(recv()); |
502 | while(readval != savesize) | 673 | fsleep(1); |
503 | readval = __builtin_bswap32(recv()); | ||
504 | if(command == 3) | ||
505 | { | ||
506 | printf("Sending save\n"); | ||
507 | VIDEO_WaitVSync(); | ||
508 | for(i = 0; i < savesize; i+=4) | ||
509 | send(__builtin_bswap32(*(vu32*)(testdump+i))); | ||
510 | } | ||
511 | printf("Waiting for GBA\n"); | ||
512 | while(recv() != 0) | ||
513 | VIDEO_WaitVSync(); | ||
514 | printf(command == 3 ? "Save restored!\n" : "Save cleared!\n"); | ||
515 | send(0); | ||
516 | sleep(5); | ||
517 | } | 674 | } |
518 | } | 675 | send(0); |
519 | } | 676 | while (recv()!=0) {fsleep(1);}; |
520 | else if(btns&PAD_BUTTON_Y) | 677 | //sleep(1); |
521 | { | 678 | |
522 | const char *biosname = "/dumps/gba_bios.bin"; | 679 | printf(" (%ld)\n", trainerId); |
523 | FILE *f = fopen(biosname,"rb"); | 680 | |
524 | if(f) | 681 | //continue; |
525 | { | 682 | |
526 | fclose(f); | 683 | // Wait for confirmation. |
527 | warnError("ERROR: BIOS already backed up!\n"); | 684 | printf("Press A to import the data from this game.\n"); |
528 | } | 685 | printf("Press B to cancel.\n"); |
529 | else | 686 | VIDEO_WaitVSync(); |
530 | { | 687 | |
531 | //create base file with size | 688 | if (waitForButtons(PAD_BUTTON_A | PAD_BUTTON_B) & PAD_BUTTON_B) |
532 | printf("Preparing file...\n"); | 689 | { |
533 | createFile(biosname,0x4000); | 690 | continue; |
534 | f = fopen(biosname,"wb"); | 691 | } |
535 | if(!f) | 692 | |
536 | fatalError("ERROR: Could not create file! Exit..."); | 693 | |
537 | //send over bios dump command | 694 | |
538 | send(5); | 695 | |
539 | //the gba might still be in a loop itself | 696 | /* |
540 | sleep(1); | 697 | //get rom header |
541 | //lets go! | 698 | for(i = 0; i < 0xC0; i+=4) |
542 | printf("Dumping...\n"); | 699 | *(vu32*)(testdump+i) = recv(); |
543 | for(i = 0; i < 0x4000; i+=4) | 700 | //print out all the info from the game |
544 | *(vu32*)(testdump+i) = recv(); | 701 | printf("Game Name: %.12s\n",(char*)(testdump+0xA0)); |
545 | fwrite(testdump,0x4000,1,f); | 702 | printf("Game ID: %.4s\n",(char*)(testdump+0xAC)); |
546 | printf("Closing file\n"); | 703 | printf("Company ID: %.2s\n",(char*)(testdump+0xB0)); |
547 | fclose(f); | 704 | printf("ROM Size: %02.02f MB\n",((float)(gbasize/1024))/1024.f); |
548 | printf("BIOS dumped!\n"); | 705 | if(savesize > 0) |
549 | sleep(5); | 706 | printf("Save Size: %02.02f KB\n \n",((float)(savesize))/1024.f); |
550 | } | 707 | else |
551 | } | 708 | printf("No Save File\n \n"); |
552 | } | 709 | //generate file paths |
553 | } | 710 | char gamename[64]; |
554 | } | 711 | sprintf(gamename,"/dumps/%.12s [%.4s%.2s].gba", |
555 | return 0; | 712 | (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0)); |
713 | fixFName(gamename+7); //fix name behind "/dumps/" | ||
714 | char savename[64]; | ||
715 | sprintf(savename,"/dumps/%.12s [%.4s%.2s].sav", | ||
716 | (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0)); | ||
717 | fixFName(savename+7); //fix name behind "/dumps/" | ||
718 | //let the user choose the option | ||
719 | printf("Press A to dump this game, it will take about %i minutes.\n",gbasize/1024/1024*3/2); | ||
720 | printf("Press B if you want to cancel dumping this game.\n"); | ||
721 | if(savesize > 0) | ||
722 | { | ||
723 | printf("Press Y to backup this save file.\n"); | ||
724 | printf("Press X to restore this save file.\n"); | ||
725 | printf("Press Z to clear the save file on the GBA Cartridge.\n\n"); | ||
726 | } | ||
727 | else | ||
728 | printf("\n"); | ||
729 | |||
730 | int command = 0; | ||
731 | while(1) | ||
732 | { | ||
733 | PAD_ScanPads(); | ||
734 | VIDEO_WaitVSync(); | ||
735 | u32 btns = PAD_ButtonsDown(0); | ||
736 | if(btns&PAD_BUTTON_START) | ||
737 | endproc(); | ||
738 | else if(btns&PAD_BUTTON_A) | ||
739 | { | ||
740 | command = 1; | ||
741 | break; | ||
742 | } | ||
743 | else if(btns&PAD_BUTTON_B) | ||
744 | break; | ||
745 | else if(savesize > 0) | ||
746 | { | ||
747 | if(btns&PAD_BUTTON_Y) | ||
748 | { | ||
749 | command = 2; | ||
750 | break; | ||
751 | } | ||
752 | else if(btns&PAD_BUTTON_X) | ||
753 | { | ||
754 | command = 3; | ||
755 | break; | ||
756 | } | ||
757 | else if(btns&PAD_TRIGGER_Z) | ||
758 | { | ||
759 | command = 4; | ||
760 | break; | ||
761 | } | ||
762 | } | ||
763 | } | ||
764 | if(command == 1) | ||
765 | { | ||
766 | FILE *f = fopen(gamename,"rb"); | ||
767 | if(f) | ||
768 | { | ||
769 | fclose(f); | ||
770 | command = 0; | ||
771 | warnError("ERROR: Game already dumped!\n"); | ||
772 | } | ||
773 | } | ||
774 | else if(command == 2) | ||
775 | { | ||
776 | FILE *f = fopen(savename,"rb"); | ||
777 | if(f) | ||
778 | { | ||
779 | fclose(f); | ||
780 | command = 0; | ||
781 | warnError("ERROR: Save already backed up!\n"); | ||
782 | } | ||
783 | } | ||
784 | else if(command == 3) | ||
785 | { | ||
786 | size_t readsize = 0; | ||
787 | FILE *f = fopen(savename,"rb"); | ||
788 | if(f) | ||
789 | { | ||
790 | fseek(f,0,SEEK_END); | ||
791 | readsize = ftell(f); | ||
792 | if(readsize != savesize) | ||
793 | { | ||
794 | command = 0; | ||
795 | warnError("ERROR: Save has the wrong size, aborting restore!\n"); | ||
796 | } | ||
797 | else | ||
798 | { | ||
799 | rewind(f); | ||
800 | fread(testdump,readsize,1,f); | ||
801 | } | ||
802 | fclose(f); | ||
803 | } | ||
804 | else | ||
805 | { | ||
806 | command = 0; | ||
807 | warnError("ERROR: No Save to restore!\n"); | ||
808 | } | ||
809 | } | ||
810 | send(command); | ||
811 | //let gba prepare | ||
812 | sleep(1); | ||
813 | if(command == 0) | ||
814 | continue; | ||
815 | else if(command == 1) | ||
816 | { | ||
817 | //create base file with size | ||
818 | printf("Preparing file...\n"); | ||
819 | createFile(gamename,gbasize); | ||
820 | FILE *f = fopen(gamename,"wb"); | ||
821 | if(!f) | ||
822 | fatalError("ERROR: Could not create file! Exit..."); | ||
823 | printf("Dumping...\n"); | ||
824 | u32 bytes_read = 0; | ||
825 | while(gbasize > 0) | ||
826 | { | ||
827 | int toread = (gbasize > 0x400000 ? 0x400000 : gbasize); | ||
828 | int j; | ||
829 | for(j = 0; j < toread; j+=4) | ||
830 | { | ||
831 | *(vu32*)(testdump+j) = recv(); | ||
832 | bytes_read+=4; | ||
833 | if((bytes_read&0xFFFF) == 0) | ||
834 | printf("\r%02.02f MB done",(float)(bytes_read/1024)/1024.f); | ||
835 | } | ||
836 | fwrite(testdump,toread,1,f); | ||
837 | gbasize -= toread; | ||
838 | } | ||
839 | printf("\nClosing file\n"); | ||
840 | fclose(f); | ||
841 | printf("Game dumped!\n"); | ||
842 | sleep(5); | ||
843 | } | ||
844 | else if(command == 2) | ||
845 | { | ||
846 | //create base file with size | ||
847 | printf("Preparing file...\n"); | ||
848 | createFile(savename,savesize); | ||
849 | FILE *f = fopen(savename,"wb"); | ||
850 | if(!f) | ||
851 | fatalError("ERROR: Could not create file! Exit..."); | ||
852 | printf("Waiting for GBA\n"); | ||
853 | VIDEO_WaitVSync(); | ||
854 | u32 readval = 0; | ||
855 | while(readval != savesize) | ||
856 | readval = __builtin_bswap32(recv()); | ||
857 | send(0); //got savesize | ||
858 | printf("Receiving...\n"); | ||
859 | for(i = 0; i < savesize; i+=4) | ||
860 | *(vu32*)(testdump+i) = recv(); | ||
861 | printf("Writing save...\n"); | ||
862 | fwrite(testdump,savesize,1,f); | ||
863 | fclose(f); | ||
864 | printf("Save backed up!\n"); | ||
865 | sleep(5); | ||
866 | } | ||
867 | else if(command == 3 || command == 4) | ||
868 | { | ||
869 | u32 readval = 0; | ||
870 | while(readval != savesize) | ||
871 | readval = __builtin_bswap32(recv()); | ||
872 | if(command == 3) | ||
873 | { | ||
874 | printf("Sending save\n"); | ||
875 | VIDEO_WaitVSync(); | ||
876 | for(i = 0; i < savesize; i+=4) | ||
877 | send(__builtin_bswap32(*(vu32*)(testdump+i))); | ||
878 | } | ||
879 | printf("Waiting for GBA\n"); | ||
880 | while(recv() != 0) | ||
881 | VIDEO_WaitVSync(); | ||
882 | printf(command == 3 ? "Save restored!\n" : "Save cleared!\n"); | ||
883 | send(0); | ||
884 | sleep(5); | ||
885 | }*/ | ||
886 | } | ||
887 | } | ||
888 | /*else if(btns&PAD_BUTTON_Y) | ||
889 | { | ||
890 | const char *biosname = "/dumps/gba_bios.bin"; | ||
891 | FILE *f = fopen(biosname,"rb"); | ||
892 | if(f) | ||
893 | { | ||
894 | fclose(f); | ||
895 | warnError("ERROR: BIOS already backed up!\n"); | ||
896 | } | ||
897 | else | ||
898 | { | ||
899 | //create base file with size | ||
900 | printf("Preparing file...\n"); | ||
901 | createFile(biosname,0x4000); | ||
902 | f = fopen(biosname,"wb"); | ||
903 | if(!f) | ||
904 | fatalError("ERROR: Could not create file! Exit..."); | ||
905 | //send over bios dump command | ||
906 | send(5); | ||
907 | //the gba might still be in a loop itself | ||
908 | sleep(1); | ||
909 | //lets go! | ||
910 | printf("Dumping...\n"); | ||
911 | for(i = 0; i < 0x4000; i+=4) | ||
912 | *(vu32*)(testdump+i) = recv(); | ||
913 | fwrite(testdump,0x4000,1,f); | ||
914 | printf("Closing file\n"); | ||
915 | fclose(f); | ||
916 | printf("BIOS dumped!\n"); | ||
917 | sleep(5); | ||
918 | } | ||
919 | }*/ | ||
920 | // } | ||
921 | // } | ||
922 | // } | ||
923 | } | ||
924 | return 0; | ||
556 | } | 925 | } |