diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/link.c | 16 | ||||
| -rw-r--r-- | source/link.h | 8 | ||||
| -rw-r--r-- | source/main.c | 1287 |
3 files changed, 852 insertions, 459 deletions
| diff --git a/source/link.c b/source/link.c new file mode 100644 index 0000000..7229191 --- /dev/null +++ b/source/link.c | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | #include "link.h" | ||
| 2 | |||
| 3 | u32 waitForButtons(u32 mask) | ||
| 4 | { | ||
| 5 | for (;;) | ||
| 6 | { | ||
| 7 | PAD_ScanPads(); | ||
| 8 | VIDEO_WaitVSync(); | ||
| 9 | |||
| 10 | u32 btns = PAD_ButtonsDown(0); | ||
| 11 | if (btns & mask) | ||
| 12 | { | ||
| 13 | return btns; | ||
| 14 | } | ||
| 15 | } | ||
| 16 | } | ||
| diff --git a/source/link.h b/source/link.h new file mode 100644 index 0000000..4e536b4 --- /dev/null +++ b/source/link.h | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef _LINK_H_ | ||
| 2 | #define _LINK_H_ | ||
| 3 | |||
| 4 | #include <gccore.h> | ||
| 5 | |||
| 6 | u32 waitForButtons(u32 mask); | ||
| 7 | |||
| 8 | #endif | ||
| 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 | } |
