1 /*
2 gba.c - Game Boy Advance support for uCON64
3
4 Copyright (c) 2001 - 2005 NoisyB
5 Copyright (c) 2001 - 2005, 2015 - 2021 dbjh
6
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #ifdef _MSC_VER
26 #pragma warning(push)
27 #pragma warning(disable: 4668) // 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives'
28 #pragma warning(disable: 4820) // 'bytes' bytes padding added after construct 'member_name'
29 #include <io.h>
30 #pragma warning(pop)
31 #endif
32 #include <stdlib.h>
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #ifdef _MSC_VER
37 #pragma warning(push)
38 #pragma warning(disable: 4820) // 'bytes' bytes padding added after construct 'member_name'
39 #endif
40 #include <sys/stat.h>
41 #ifdef _MSC_VER
42 #pragma warning(pop)
43 #endif
44 #include "misc/archive.h"
45 #include "misc/bswap.h"
46 #include "misc/file.h"
47 #include "misc/misc.h"
48 #include "misc/property.h"
49 #include "misc/string.h"
50 #include "ucon64_misc.h"
51 #include "console/console.h"
52 #include "console/gba.h"
53 #include "backup/backup.h"
54 #include "backup/fal.h"
55
56
57 #define GBA_NAME_LEN 12
58 #define GBA_HEADER_START 0
59 #define GBA_HEADER_LEN (sizeof (st_gba_header_t))
60 #define GBA_MENU_SIZE 20916
61 #define GBA_BLANK_SIZE 52232
62 #define GBA_SAV_TEMPLATE_SIZE 65536
63 #define GBA_SCI_TEMPLATE_SIZE 458752
64
65 static int gba_chksum (void);
66
67
68 static st_ucon64_obj_t gba_obj[] =
69 {
70 {0, WF_DEFAULT},
71 {0, WF_INIT | WF_PROBE | WF_STOP},
72 {UCON64_GBA, WF_SWITCH},
73 {UCON64_GBA, WF_DEFAULT}
74 };
75
76 const st_getopt2_t gba_usage[] =
77 {
78 {
79 NULL, 0, 0, 0,
80 NULL, "Game Boy Advance (SP)"/*"2001 Nintendo http://www.nintendo.com"*/,
81 NULL
82 },
83 {
84 UCON64_GBA_S, 0, 0, UCON64_GBA,
85 NULL, "force recognition",
86 &gba_obj[2]
87 },
88 {
89 "n", 1, 0, UCON64_N,
90 "NEW_NAME", "change internal ROM name to NEW_NAME",
91 &gba_obj[0]
92 },
93 {
94 "logo", 0, 0, UCON64_LOGO,
95 NULL, "restore ROM logo character data (offset: 0x04-0x9F)",
96 &gba_obj[0]
97 },
98 {
99 "chk", 0, 0, UCON64_CHK,
100 NULL, "fix ROM header checksum",
101 &gba_obj[0]
102 },
103 {
104 "sram", 0, 0, UCON64_SRAM,
105 NULL, "patch ROM for SRAM saving",
106 &gba_obj[3]
107 },
108 {
109 "sc", 0, 0, UCON64_SC,
110 NULL, "convert to Super Card (CF to GBA Adapter)\n"
111 #if 0
112 "enables \"Saver patch\", \"restart to Menu\" and\n"
113 "\"Real Time Save\""
114 #endif
115 "(creates SAV and SCI templates)",
116 &gba_obj[3]
117 },
118 {
119 "crp", 1, 0, UCON64_CRP,
120 "WAIT_TIME", "slow down ROM access (\"crash patch\");\n"
121 "WAIT_TIME" OPTARG_S "0 default in most crash patches\n"
122 "WAIT_TIME" OPTARG_S "4 faster than 0, slower than 8\n"
123 "WAIT_TIME" OPTARG_S "8 faster than 4, slower than 28\n"
124 "WAIT_TIME" OPTARG_S "12 slowest cartridge access speed\n"
125 "WAIT_TIME" OPTARG_S "16 faster than 28, but slower than 20\n"
126 "WAIT_TIME" OPTARG_S "20 default in most original cartridges\n"
127 "WAIT_TIME" OPTARG_S "24 fastest cartridge access speed\n"
128 "WAIT_TIME" OPTARG_S "28 faster than 8 but slower than 16",
129 &gba_obj[3]
130 },
131 // "n 0 and 28, with a stepping of 4. I.e. 0, 4, 8, 12 ...\n"
132 {
133 "multi", 1, 0, UCON64_MULTI,
134 "SIZE", "make multi-game file for use with FAL/F2A flash card, truncated\n"
135 "to SIZE Mbit; file with loader must be specified first, then\n"
136 "all the ROMs, multi-game file to create last",
137 &gba_obj[1]
138 },
139 {NULL, 0, 0, 0, NULL, NULL, NULL}
140 };
141
142 /*
143 Offset 00h-03h - Start address - A 32 bit ARM B command with jump destination
144 to the start address of the program, cannot be manipulated
145 with this tool, there's no reason.
146
147 Offset 04h-9fh - Nintendo logo character data - The fix Nintendo logo graphics
148 needed to start a ROM on the real machine as it is verified
149 by it.
150
151 Offset a0h-abh - Game title - The game title is an ASCII string, officially
152 can use only ASCII characters between the ASCII code 20h and
153 60h. Although it is not a strict rule for hobby programmers,
154 it is fun to follow such a rules in my opinion. As I know
155 developers can choose their own game title here describing
156 the product in short.
157
158 Offset ach-afh - Game code - The 4 bytes long code of the game is an ASCII
159 string too, officially can use only ASCII characters between
160 the ASCII code 20h and 60h. The first letter is always A as I
161 know, probably stands for GBA, so it won't change unless a
162 higher hardware with backwards compatibility won't be
163 introduced and this letter could hold some more infos about
164 it. The second and third letters are the shortened version of
165 the name of the game. And the fourth letter is the territory
166 code. Don't afraid, there's no territory lockout, this is for
167 information purposes only. So far as I know J stands for
168 Japan and Asia, E stands for USA and the whole American
169 continent and P stands for Europe, Australia and Africa
170 (probably came from that these are the PAL video standard
171 territories, but I could be wrong). Although it is not a
172 strict rule for hobby programmers, it is fun to follow such a
173 rules in my opinion. Developers get this 4 letter code right
174 from Nintendo and they have to use that.
175
176 Offset b0h-b1h - Maker code - The 2 bytes long code of the developer company
177 is an ASCII string too, officially can use only ASCII
178 characters between the ASCII code 20h and 60h. Although it is
179 not a strict rule for hobby programmers, it is fun to follow
180 such a rules in my opinion. Developers get this 2 letter code
181 right from Nintendo and they have to use that.
182
183 Offset b2h-b2h - 96h - Fixed 96h byte without any useful information.
184
185 Offset b3h-b3h - Main unit code - This hexadecimal byte is the destination
186 hardware code. It is always 00h at the moment as it stands
187 for Game Boy Advance, so it won't change in the future either
188 unless a higher hardware with backwards compatibility won't
189 be introduced and this byte could hold some more infos about
190 it. There's no reason to change this or write something
191 different than 00h into it.
192
193 Offset b4h-b4h - Device type - This hexadecimal byte is the device type code.
194 It is always 00h as the only other possible value stands for
195 a debugger cart what I assume won't be available on the
196 streets and I assume even if a developer works with such a
197 hardware, he or she doesn't have to change this byte, however
198 he or she easily can of course. So there's no reason to
199 change this or write something different than 00h into it.
200
201 Offset b5h-bbh - Reserved area - Fixed, 00h filled area without any useful
202 information.
203
204 Offset bch-bch - Mask ROM version number - This hexadecimal byte holds the
205 version number of the ROM. As I know it works somehow that
206 way, the first published (and released on the streets) is
207 always the first version and for that 00h is stored here. In
208 the case it is getting updated, so in the same territory the
209 very same game with the very same title is getting replaced
210 with a new version, what is happening rarely, the number here
211 is getting increased by one. So usually this byte holds 00h
212 and there isn't too much reason to write something here and
213 something else than 00h.
214
215 Offset bdh-bdh - Complement check - This hexadecimal byte have to be
216 calculated automatically, when the whole header is in its
217 final state, so nothing will change inside of it. (Manually
218 it would be hard to calculate.) Add the bytes between offset
219 a0h and bch together, take the number's two's complement and
220 add 19h to the result. Store the lowest 8 bits here. Or
221 calculate automatically with GBARM. The hardware is
222 verifying this byte just like the Nintendo logo character
223 data and in the case it isn't correct, the game won't start
224 on the real machine.
225
226 Offset beh-bfh - Reserved area - Fixed, 00h filled area without any useful
227 information.
228 */
229 typedef struct st_gba_header
230 {
231 unsigned char start[4]; // 0x00
232 unsigned char logo[GBA_LOGODATA_LEN]; // 0x04
233 unsigned char name[GBA_NAME_LEN]; // 0xa0
234 unsigned char game_id_prefix; // 0xac
235 unsigned char game_id_low; // 0xad
236 unsigned char game_id_high; // 0xae
237 unsigned char game_id_country; // 0xaf
238 unsigned char maker_high; // 0xb0
239 unsigned char maker_low; // 0xb1
240 unsigned char pad1;
241 unsigned char gba_type; // 0xb3
242 unsigned char device_type; // 0xb4
243 unsigned char pad2[7];
244 unsigned char version; // 0xbc
245 unsigned char checksum; // 0xbd
246 unsigned char pad3[2];
247 } st_gba_header_t;
248
249 static st_gba_header_t gba_header;
250 const unsigned char gba_logodata[] = // NOTE: not a static variable
251 {
252 0x24, 0xff, 0xae, 0x51,
253 0x69, 0x9a, 0xa2, 0x21, 0x3d, 0x84, 0x82, 0x0a,
254 0x84, 0xe4, 0x09, 0xad, 0x11, 0x24, 0x8b, 0x98,
255 0xc0, 0x81, 0x7f, 0x21, 0xa3, 0x52, 0xbe, 0x19,
256 0x93, 0x09, 0xce, 0x20, 0x10, 0x46, 0x4a, 0x4a,
257 0xf8, 0x27, 0x31, 0xec, 0x58, 0xc7, 0xe8, 0x33,
258 0x82, 0xe3, 0xce, 0xbf, 0x85, 0xf4, 0xdf, 0x94,
259 0xce, 0x4b, 0x09, 0xc1, 0x94, 0x56, 0x8a, 0xc0,
260 0x13, 0x72, 0xa7, 0xfc, 0x9f, 0x84, 0x4d, 0x73,
261 0xa3, 0xca, 0x9a, 0x61, 0x58, 0x97, 0xa3, 0x27,
262 0xfc, 0x03, 0x98, 0x76, 0x23, 0x1d, 0xc7, 0x61,
263 0x03, 0x04, 0xae, 0x56, 0xbf, 0x38, 0x84, 0x00,
264 0x40, 0xa7, 0x0e, 0xfd, 0xff, 0x52, 0xfe, 0x03,
265 0x6f, 0x95, 0x30, 0xf1, 0x97, 0xfb, 0xc0, 0x85,
266 0x60, 0xd6, 0x80, 0x25, 0xa9, 0x63, 0xbe, 0x03,
267 0x01, 0x4e, 0x38, 0xe2, 0xf9, 0xa2, 0x34, 0xff,
268 0xbb, 0x3e, 0x03, 0x44, 0x78, 0x00, 0x90, 0xcb,
269 0x88, 0x11, 0x3a, 0x94, 0x65, 0xc0, 0x7c, 0x63,
270 0x87, 0xf0, 0x3c, 0xaf, 0xd6, 0x25, 0xe4, 0x8b,
271 0x38, 0x0a, 0xac, 0x72, 0x21, 0xd4, 0xf8, 0x07
272 };
273
274
275 int
gba_n(st_ucon64_nfo_t * rominfo,const char * name)276 gba_n (st_ucon64_nfo_t *rominfo, const char *name)
277 {
278 char buf[GBA_NAME_LEN], dest_name[FILENAME_MAX];
279
280 #if defined __GNUC__ && __GNUC__ >= 8
281 #pragma GCC diagnostic push
282 #pragma GCC diagnostic ignored "-Wstringop-truncation"
283 #endif
284 strncpy (buf, name, GBA_NAME_LEN);
285 #if defined __GNUC__ && __GNUC__ >= 8
286 #pragma GCC diagnostic pop
287 #endif
288 strcpy (dest_name, ucon64.fname);
289 ucon64_file_handler (dest_name, NULL, 0);
290 fcopy (ucon64.fname, 0, ucon64.fsize, dest_name, "wb");
291 ucon64_fwrite (buf, GBA_HEADER_START + rominfo->backup_header_len + 0xa0,
292 GBA_NAME_LEN, dest_name, "r+b");
293
294 printf (ucon64_msg[WROTE], dest_name);
295 return 0;
296 }
297
298
299 int
gba_logo(st_ucon64_nfo_t * rominfo)300 gba_logo (st_ucon64_nfo_t *rominfo)
301 {
302 char dest_name[FILENAME_MAX];
303
304 strcpy (dest_name, ucon64.fname);
305 ucon64_file_handler (dest_name, NULL, 0);
306 fcopy (ucon64.fname, 0, ucon64.fsize, dest_name, "wb");
307 ucon64_fwrite (gba_logodata, GBA_HEADER_START + rominfo->backup_header_len +
308 0x04, GBA_LOGODATA_LEN, dest_name, "r+b");
309
310 printf (ucon64_msg[WROTE], dest_name);
311 return 0;
312 }
313
314
315 int
gba_chk(st_ucon64_nfo_t * rominfo)316 gba_chk (st_ucon64_nfo_t *rominfo)
317 {
318 char buf, dest_name[FILENAME_MAX];
319
320 strcpy (dest_name, ucon64.fname);
321 ucon64_file_handler (dest_name, NULL, 0);
322 fcopy (ucon64.fname, 0, ucon64.fsize, dest_name, "wb");
323
324 buf = (char) rominfo->current_internal_crc;
325 ucon64_fputc (dest_name, GBA_HEADER_START + rominfo->backup_header_len + 0xbd,
326 buf, "r+b");
327
328 dumper (stdout, &buf, 1, GBA_HEADER_START + rominfo->backup_header_len + 0xbd,
329 DUMPER_HEX);
330
331 printf (ucon64_msg[WROTE], dest_name);
332 return 0;
333 }
334
335
336 int
gba_sram(void)337 gba_sram (void)
338 // This function is based on Omar Kilani's gbautil 1.1
339 {
340 unsigned char st_orig[2][10] =
341 {
342 { 0x0E, 0x48, 0x39, 0x68, 0x01, 0x60, 0x0E, 0x48, 0x79, 0x68 },
343 { 0x13, 0x4B, 0x18, 0x60, 0x13, 0x48, 0x01, 0x60, 0x13, 0x49 }
344 },
345 st_repl[2][10] =
346 {
347 { 0x00, 0x48, 0x00, 0x47, 0x01, 0xFF, 0xFF, 0x08, 0x79, 0x68 },
348 { 0x01, 0x4C, 0x20, 0x47, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x08 }
349 },
350 fl_orig[2][24] =
351 {
352 {
353 0xD0, 0x20, 0x00, 0x05, 0x01, 0x88, 0x01, 0x22, 0x08, 0x1C,
354 0x10, 0x40, 0x02, 0x1C, 0x11, 0x04, 0x08, 0x0C, 0x00, 0x28,
355 0x01, 0xD0, 0x1B, 0xE0
356 },
357 {
358 0xD0, 0x21, 0x09, 0x05, 0x01, 0x23, 0x0C, 0x4A, 0x08, 0x88,
359 0x18, 0x40, 0x00, 0x28, 0x08, 0xD1, 0x10, 0x78, 0x00, 0x28,
360 0xF8, 0xD0, 0x08, 0x88
361 }
362 },
363 fl_repl[2][24] =
364 {
365 {
366 0xE0, 0x20, 0x00, 0x05, 0x01, 0x88, 0x01, 0x22, 0x08, 0x1C,
367 0x10, 0x40, 0x02, 0x1C, 0x11, 0x04, 0x08, 0x0C, 0x00, 0x28,
368 0x01, 0xD0, 0x1B, 0xE0
369 },
370 {
371 0xE0, 0x21, 0x09, 0x05, 0x01, 0x23, 0x0C, 0x4A, 0x08, 0x88,
372 0x18, 0x40, 0x00, 0x28, 0x08, 0xD1, 0x10, 0x78, 0x00, 0x28,
373 0xF8, 0xD0, 0x08, 0x88
374 }
375 },
376 p_repl[2][188] =
377 {
378 {
379 0x39, 0x68, 0x27, 0x48, 0x81, 0x42, 0x23, 0xD0, 0x89, 0x1C,
380 0x08, 0x88, 0x01, 0x28, 0x02, 0xD1, 0x24, 0x48, 0x78, 0x60,
381 0x33, 0xE0, 0x00, 0x23, 0x00, 0x22, 0x89, 0x1C, 0x10, 0xB4,
382 0x01, 0x24, 0x08, 0x68, 0x20, 0x40, 0x5B, 0x00, 0x03, 0x43,
383 0x89, 0x1C, 0x52, 0x1C, 0x06, 0x2A, 0xF7, 0xD1, 0x10, 0xBC,
384 0x39, 0x60, 0xDB, 0x01, 0x02, 0x20, 0x00, 0x02, 0x1B, 0x18,
385 0x0E, 0x20, 0x00, 0x06, 0x1B, 0x18, 0x7B, 0x60, 0x39, 0x1C,
386 0x08, 0x31, 0x08, 0x88, 0x09, 0x38, 0x08, 0x80, 0x16, 0xE0,
387 0x15, 0x49, 0x00, 0x23, 0x00, 0x22, 0x10, 0xB4, 0x01, 0x24,
388 0x08, 0x68, 0x20, 0x40, 0x5B, 0x00, 0x03, 0x43, 0x89, 0x1C,
389 0x52, 0x1C, 0x06, 0x2A, 0xF7, 0xD1, 0x10, 0xBC, 0xDB, 0x01,
390 0x02, 0x20, 0x00, 0x02, 0x1B, 0x18, 0x0E, 0x20, 0x00, 0x06,
391 0x1B, 0x18, 0x08, 0x3B, 0x3B, 0x60, 0x0B, 0x48, 0x39, 0x68,
392 0x01, 0x60, 0x0A, 0x48, 0x79, 0x68, 0x01, 0x60, 0x0A, 0x48,
393 0x39, 0x1C, 0x08, 0x31, 0x0A, 0x88, 0x80, 0x21, 0x09, 0x06,
394 0x0A, 0x43, 0x02, 0x60, 0x07, 0x48, 0x00, 0x47, 0x00, 0x00,
395 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0E, 0x04, 0x00,
396 0x00, 0x0E, 0xD4, 0x00, 0x00, 0x04, 0xD8, 0x00, 0x00, 0x04,
397 0xDC, 0x00, 0x00, 0x04, 0xFF, 0xFF, 0xFF, 0x08
398 },
399 {
400 0x22, 0x4C, 0x84, 0x42, 0x20, 0xD0, 0x80, 0x1C, 0x04, 0x88,
401 0x01, 0x25, 0x2C, 0x40, 0x01, 0x2C, 0x02, 0xD1, 0x80, 0x1E,
402 0x1E, 0x49, 0x2E, 0xE0, 0x00, 0x23, 0x00, 0x24, 0x80, 0x1C,
403 0x40, 0xB4, 0x01, 0x26, 0x05, 0x68, 0x35, 0x40, 0x5B, 0x00,
404 0x2B, 0x43, 0x80, 0x1C, 0x64, 0x1C, 0x06, 0x2C, 0xF7, 0xD1,
405 0x40, 0xBC, 0xDB, 0x01, 0x02, 0x24, 0x24, 0x02, 0x1B, 0x19,
406 0x0E, 0x24, 0x24, 0x06, 0x1B, 0x19, 0x19, 0x1C, 0x09, 0x3A,
407 0x16, 0xE0, 0x12, 0x48, 0x00, 0x23, 0x00, 0x24, 0x40, 0xB4,
408 0x01, 0x26, 0x05, 0x68, 0x35, 0x40, 0x5B, 0x00, 0x2B, 0x43,
409 0x80, 0x1C, 0x64, 0x1C, 0x06, 0x2C, 0xF7, 0xD1, 0x40, 0xBC,
410 0xDB, 0x01, 0x02, 0x24, 0x24, 0x02, 0x1B, 0x19, 0x0E, 0x24,
411 0x24, 0x06, 0x1B, 0x19, 0x08, 0x3B, 0x18, 0x1C, 0x08, 0x4C,
412 0x20, 0x60, 0x08, 0x4C, 0x21, 0x60, 0x08, 0x49, 0x80, 0x20,
413 0x00, 0x06, 0x02, 0x43, 0x0A, 0x60, 0x06, 0x4C, 0x20, 0x47,
414 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0E, 0x04, 0x00,
415 0x00, 0x0E, 0xD4, 0x00, 0x00, 0x04, 0xD8, 0x00, 0x00, 0x04,
416 0xDC, 0x00, 0x00, 0x04, 0xFF, 0xFF, 0xFF, 0x08
417 }
418 },
419 major, minor, micro, *buffer, *bufferptr, *ptr, value;
420 char dest_name[FILENAME_MAX];
421 int p_size[2] = { 188, 168 }, p_off, st_off;
422 unsigned int fsize = (unsigned int) ucon64.fsize;
423 FILE *destfile;
424
425 strcpy (dest_name, ucon64.fname);
426 ucon64_file_handler (dest_name, NULL, 0);
427 fcopy (ucon64.fname, 0, ucon64.fsize, dest_name, "wb");
428
429 if ((destfile = fopen (dest_name, "r+b")) == NULL)
430 {
431 fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], dest_name);
432 return -1;
433 }
434 if ((buffer = (unsigned char *) malloc (fsize)) == NULL)
435 {
436 fprintf (stderr, ucon64_msg[ROM_BUFFER_ERROR], fsize);
437 fclose (destfile);
438 exit (1);
439 }
440 if (fread (buffer, 1, fsize, destfile) != fsize)
441 {
442 fprintf (stderr, ucon64_msg[READ_ERROR], dest_name);
443 free (buffer);
444 fclose (destfile);
445 return -1;
446 }
447
448 bufferptr = buffer + 160 + 12 + 4;
449
450 ptr = (unsigned char *) memmem2 (bufferptr, fsize, "EEPROM_", 7, 0);
451 if (ptr == NULL)
452 {
453 puts ("This ROM does not appear to use EEPROM saving");
454 free (buffer);
455 fclose (destfile);
456 return -1;
457 }
458 major = ptr[8] - '0';
459 minor = ptr[9] - '0';
460 micro = ptr[10] - '0';
461 if (ucon64.quiet < 0)
462 printf ("version: %u.%u.%u; offset: 0x%08x\n",
463 major, minor, micro, (int) (ptr - buffer));
464 if (minor - 1 >= 2)
465 {
466 fputs ("ERROR: ROMs with an EEPROM minor version other than 1 or 2 are not supported\n", stderr);
467 free (buffer);
468 fclose (destfile);
469 return -1;
470 }
471
472 ptr = (unsigned char *) memmem2 (bufferptr, fsize,
473 fl_orig[minor - 1], sizeof fl_orig[minor - 1], 0);
474 if (ptr == NULL)
475 {
476 fputs ("ERROR: Could not find fl pattern. Perhaps this file is already patched?\n", stderr);
477 free (buffer);
478 fclose (destfile);
479 return -1;
480 }
481 if (ucon64.quiet < 0)
482 printf ("fl offset: 0x%08x\n", (int) (ptr - buffer));
483 fseek (destfile, (long) (ptr - buffer), SEEK_SET);
484 fwrite (fl_repl[minor - 1], 1, sizeof fl_repl[minor - 1], destfile);
485
486 ptr = buffer + fsize - 1;
487 value = *ptr;
488 do
489 ptr--;
490 while (*ptr == value && ptr - buffer > 0);
491
492 p_off = (ptr - buffer + 0xff) & ~0xff; // align at 256 byte boundary
493 if (ucon64.quiet < 0)
494 printf ("p_off: 0x%08x\n", p_off);
495 // if the SRAM function won't fit at the end of the ROM, abort
496 if ((minor == 1 && (int) (fsize - 188) < p_off) ||
497 (minor == 2 && (int) (fsize - 168) < p_off))
498 {
499 fputs ("ERROR: Not enough room for SRAM function at end of ROM\n", stderr);
500 free (buffer);
501 fclose (destfile);
502 return -1;
503 }
504
505 ptr = (unsigned char *) memmem2 (bufferptr, fsize,
506 st_orig[minor - 1], sizeof st_orig[minor - 1], 0);
507 if (ptr == NULL)
508 {
509 fputs ("ERROR: Could not find st pattern\n", stderr);
510 free (buffer);
511 fclose (destfile);
512 return -1;
513 }
514 st_off = (int) (ptr - buffer);
515 if (ucon64.quiet < 0)
516 printf ("st offset: 0x%08x\n", st_off);
517
518 bufferptr = buffer + p_off;
519 switch (minor)
520 {
521 case 1:
522 // these are the offsets to the caller function, it handles all saving and
523 // is at st_off
524 p_repl[minor - 1][184] = (unsigned char) (st_off + 0x21);
525 p_repl[minor - 1][186] = (unsigned char) (st_off >> 16);
526
527 if (*(bufferptr - 1) == 0xff)
528 p_repl[minor - 1][185] = (unsigned char) (st_off >> 8);
529 else
530 {
531 st_off += 0x1f;
532 p_repl[minor - 1][185] = (unsigned char) (st_off >> 8);
533 }
534
535 // tell the calling function where the SRAM function is (p_off)
536 st_repl[minor - 1][5] = (unsigned char) (p_off >> 8);
537 st_repl[minor - 1][6] = (unsigned char) (p_off >> 16);
538 break;
539 case 2:
540 // offsets to the caller function
541 p_repl[minor - 1][164] = (unsigned char) (st_off + 0x13);
542 p_repl[minor - 1][165] = (unsigned char) (st_off >> 8);
543 p_repl[minor - 1][166] = (unsigned char) (st_off >> 16);
544
545 // tell the calling function where the SRAM function is
546 st_repl[minor - 1][7] = (unsigned char) (p_off >> 8);
547 st_repl[minor - 1][8] = (unsigned char) (p_off >> 16);
548 break;
549 }
550 fseek (destfile, st_off, SEEK_SET);
551 fwrite (st_repl[minor - 1], 1, sizeof st_repl[minor - 1], destfile);
552 fseek (destfile, p_off, SEEK_SET);
553 fwrite (p_repl[minor - 1], 1, p_size[minor - 1], destfile);
554
555 free (buffer);
556 fclose (destfile);
557
558 puts ("SRAM patch applied");
559 printf (ucon64_msg[WROTE], dest_name);
560 return 0;
561 }
562
563
564 int
gba_crp(st_ucon64_nfo_t * rominfo,const char * value)565 gba_crp (st_ucon64_nfo_t *rominfo, const char *value)
566 {
567 FILE *srcfile, *destfile;
568 size_t bytesread;
569 int n = 0;
570 char buffer[32 * 1024], src_name[FILENAME_MAX], dest_name[FILENAME_MAX],
571 replace[2], wait_time = (char) atoi (value);
572
573 if (wait_time % 4 != 0 || wait_time > 28 || wait_time < 0)
574 {
575 fputs ("ERROR: You specified an incorrect WAIT_TIME value\n", stderr);
576 return -1;
577 }
578
579 puts ("Applying crash patch...");
580
581 strcpy (src_name, ucon64.fname);
582 strcpy (dest_name, ucon64.fname);
583 ucon64_file_handler (dest_name, src_name, 0);
584 if ((srcfile = fopen (src_name, "rb")) == NULL)
585 {
586 fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], src_name);
587 return -1;
588 }
589 if ((destfile = fopen (dest_name, "wb")) == NULL)
590 {
591 fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], dest_name);
592 fclose (srcfile);
593 return -1;
594 }
595 if (rominfo->backup_header_len) // copy header (if present)
596 {
597 fread_checked (buffer, 1, rominfo->backup_header_len, srcfile);
598 fwrite (buffer, 1, rominfo->backup_header_len, destfile);
599 }
600
601 replace[0] = wait_time;
602 replace[1] = 0x40;
603 while ((bytesread = fread (buffer, 1, 32 * 1024, srcfile)) != 0)
604 { // '!' == ASCII 33 (\x21), '*' == 42 (\x2a)
605 n += change_mem (buffer, bytesread, "\x04\x02\x00\x04\x14\x40", 6, '*', '!', replace, 1, -1);
606 n += change_mem (buffer, bytesread, "\x02\x00\x04\x14\x40\x00", 6, '*', '!', replace, 1, -2);
607 n += change_mem (buffer, bytesread, "\x04\x02\x00\x04\xB4\x45", 6, '*', '!', replace, 2, -1);
608 n += change_mem (buffer, bytesread, "\x3E\xE0\x00\x00\xB4\x45", 6, '*', '!', replace, 2, -1);
609 n += change_mem (buffer, bytesread, "\x04\x02\x00\x04\x94\x44", 6, '*', '!', replace, 2, -1);
610
611 fwrite (buffer, 1, bytesread, destfile);
612 }
613 fclose (srcfile);
614 fclose (destfile);
615
616 printf ("Found %d pattern%s\n", n, n != 1 ? "s" : "");
617 printf (ucon64_msg[WROTE], dest_name);
618 remove_temp_file ();
619 return 0;
620 }
621
622
623 int
gba_init(st_ucon64_nfo_t * rominfo)624 gba_init (st_ucon64_nfo_t *rominfo)
625 {
626 int result = -1, value;
627 unsigned int pos = (unsigned int) strlen (rominfo->misc);
628
629 rominfo->backup_header_len = UCON64_ISSET2 (ucon64.backup_header_len, unsigned int) ?
630 ucon64.backup_header_len : 0;
631
632 ucon64_fread (&gba_header, GBA_HEADER_START +
633 rominfo->backup_header_len, GBA_HEADER_LEN, ucon64.fname);
634 if (/*gba_header.game_id_prefix == 'A' && */ // 'B' in Mario vs. Donkey Kong
635 gba_header.start[3] == 0xea && gba_header.pad1 == 0x96 && gba_header.gba_type == 0)
636 result = 0;
637 else
638 {
639 #if 0 // AFAIK (dbjh) GBA ROMs never have a header
640 rominfo->backup_header_len = UCON64_ISSET (ucon64.backup_header_len, unsigned int) ?
641 ucon64.backup_header_len : UNKNOWN_HEADER_LEN;
642
643 ucon64_fread (&gba_header, GBA_HEADER_START +
644 rominfo->backup_header_len, GBA_HEADER_LEN, ucon64.fname);
645 if (gba_header.game_id_prefix == 'A' && gba_header.gba_type == 0)
646 result = 0;
647 else
648 #endif
649 result = -1;
650 }
651 if (ucon64.console == UCON64_GBA)
652 result = 0;
653
654 rominfo->header_start = GBA_HEADER_START;
655 rominfo->header_len = GBA_HEADER_LEN;
656 rominfo->header = &gba_header;
657
658 // internal ROM name
659 strncpy (rominfo->name, (char *) gba_header.name, GBA_NAME_LEN);
660 rominfo->name[GBA_NAME_LEN] = '\0';
661
662 // ROM maker
663 {
664 int ih = gba_header.maker_high <= '9' ?
665 gba_header.maker_high - '0' : gba_header.maker_high - 'A' + 10,
666 il = gba_header.maker_low <= '9' ?
667 gba_header.maker_low - '0' : gba_header.maker_low - 'A' + 10;
668 value = ih * 36 + il;
669 }
670 if (value < 0 || value >= NINTENDO_MAKER_LEN)
671 value = 0;
672 rominfo->maker = NULL_TO_UNKNOWN_S (nintendo_maker[value]);
673
674 // ROM country
675 rominfo->country =
676 (gba_header.game_id_country == 'J') ? "Japan/Asia" :
677 (gba_header.game_id_country == 'E') ? "U.S.A." :
678 (gba_header.game_id_country == 'P') ? "Europe, Australia and Africa" :
679 "Unknown country";
680
681 // misc stuff
682 pos += sprintf (rominfo->misc + pos, "Version: 1.%u\n", gba_header.version);
683 pos += sprintf (rominfo->misc + pos, "Device type: 0x%02x\n", gba_header.device_type);
684
685 /*
686 start address = current address + (parameter of B instruction * 4) + 8
687 gba_header.start[3] is opcode of B instruction (0xea)
688 */
689 value = 0x8000008 +
690 (gba_header.start[2] << 18 | gba_header.start[1] << 10 | gba_header.start[0] << 2);
691 pos += sprintf (rominfo->misc + pos, "Start address: 0x%08x\n", value);
692
693 sprintf (rominfo->misc + pos, "Logo data: %s",
694 memcmp (gba_header.logo, gba_logodata, GBA_LOGODATA_LEN) == 0 ?
695 #ifdef USE_ANSI_COLOR
696 ucon64.ansi_color ? "\x1b[01;32mOK\x1b[0m" : "OK" :
697 ucon64.ansi_color ? "\x1b[01;31mBad\x1b[0m" : "Bad");
698 #else
699 "OK" : "Bad");
700 #endif
701
702 // internal ROM crc
703 if (!UCON64_ISSET (ucon64.do_not_calc_crc) && result == 0)
704 {
705 rominfo->has_internal_crc = 1;
706 rominfo->internal_crc_len = 1;
707 rominfo->current_internal_crc = gba_chksum ();
708
709 rominfo->internal_crc = gba_header.checksum;
710 rominfo->internal_crc2[0] = 0;
711 }
712
713 rominfo->console_usage = gba_usage[0].help;
714 // we use fal_usage, but we could just as well use f2a_usage
715 rominfo->backup_usage = (!rominfo->backup_header_len ? fal_usage[0].help : unknown_backup_usage[0].help);
716
717 return result;
718 }
719
720
721 int
gba_chksum(void)722 gba_chksum (void)
723 // Note that this function only calculates the checksum of the internal header
724 {
725 unsigned char sum = 0x19, *ptr = (unsigned char *) &gba_header + 0xa0;
726
727 while (ptr < (unsigned char *) &gba_header + 0xbd)
728 sum += *ptr++;
729 sum = -sum;
730
731 return sum;
732 }
733
734
735 int
gba_multi(unsigned int truncate_size,char * multi_fname)736 gba_multi (unsigned int truncate_size, char *multi_fname)
737 // TODO: Check if 1024 Mbit multi-game files are supported by the FAL code
738 {
739 size_t n, n_files, bytestowrite, byteswritten, totalsize = 0;
740 unsigned int file_no, done, truncated = 0, size_pow2_lesser = 1,
741 size_pow2 = 1, truncate_size_ispow2 = 0;
742 struct stat fstate;
743 FILE *srcfile, *destfile;
744 char buffer[32 * 1024], fname[FILENAME_MAX], *fname_ptr;
745 const char *p = NULL;
746
747 if (truncate_size == 0)
748 {
749 fputs ("ERROR: Cannot make multi-game file of 0 bytes\n", stderr);
750 return -1;
751 }
752
753 #if 0
754 if (truncate_size != 64 * MBIT && truncate_size != 128 * MBIT &&
755 truncate_size != 256 * MBIT && truncate_size != 512 * MBIT &&
756 truncate_size != 1024 * MBIT)
757 {
758 fputs ("ERROR: Truncate size must be 64, 128, 256, 512 or 1024\n", stderr);
759 return -1;
760 }
761 #endif
762
763 if (multi_fname != NULL) // -xfalmulti
764 {
765 n_files = ucon64.argc;
766 snprintf (fname, FILENAME_MAX, "%s", multi_fname);
767 }
768 else // -multi
769 {
770 n_files = ucon64.argc - 1;
771 snprintf (fname, FILENAME_MAX, "%s", ucon64.argv[n_files]);
772 }
773 fname[FILENAME_MAX - 1] = '\0';
774
775 ucon64_file_handler (fname, NULL, OF_FORCE_BASENAME);
776 if ((destfile = fopen (fname, "wb")) == NULL)
777 {
778 fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], fname);
779 return -1;
780 }
781 printf ("Creating multi-game file for FAL(/F2A): %s\n", fname);
782
783 file_no = 0;
784 for (n = 1; n < n_files; n++)
785 {
786 if (access (ucon64.argv[n], F_OK))
787 continue; // "file" does not exist (option)
788 stat (ucon64.argv[n], &fstate);
789 if (!S_ISREG (fstate.st_mode))
790 continue;
791
792 if (file_no == 0)
793 {
794 if (multi_fname != NULL) // -xfalmulti
795 {
796 size_t len;
797
798 p = get_property (ucon64.configfile, "gbaloader", PROPERTY_MODE_FILENAME);
799 if (!p)
800 p = "loader.bin";
801 len = strnlen (p, sizeof fname - 1);
802 strncpy (fname, p, len)[len] = '\0';
803 if (access (fname, F_OK))
804 {
805 fprintf (stderr, "ERROR: Cannot open loader binary (%s)\n", fname);
806 fclose (destfile);
807 return -1;
808 }
809 fname_ptr = fname;
810 // NOTE: loop counter is modified, because we have to insert
811 // loader in the file list
812 n--;
813 }
814 else // -multi
815 fname_ptr = ucon64.argv[n];
816
817 printf ("Loader: %s\n", fname_ptr);
818 if (fsizeof (fname_ptr) > 64 * 1024)
819 printf ("WARNING: Are you sure %s is a loader binary?\n", fname_ptr);
820 }
821 else
822 {
823 fname_ptr = ucon64.argv[n];
824 printf ("ROM%u: %s\n", file_no, fname_ptr);
825 }
826
827 if ((srcfile = fopen (fname_ptr, "rb")) == NULL)
828 {
829 fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], fname_ptr);
830 continue;
831 }
832 done = 0;
833 byteswritten = 0; // # of bytes written per file
834 while (!done)
835 {
836 bytestowrite = fread (buffer, 1, sizeof buffer, srcfile);
837 if (totalsize + bytestowrite > truncate_size)
838 {
839 bytestowrite = truncate_size - totalsize;
840 done = 1;
841 truncated = 1;
842 printf ("Output file is %u Mbit, truncating %s, skipping %u bytes\n",
843 truncate_size / MBIT, fname_ptr,
844 (unsigned) (fsizeof (fname_ptr) - (byteswritten + bytestowrite)));
845 // DON'T use fstate.st_size, because file could be compressed
846 }
847 totalsize += bytestowrite;
848 if (bytestowrite == 0)
849 done = 1;
850 fwrite (buffer, 1, bytestowrite, destfile);
851 byteswritten += bytestowrite;
852 }
853 fclose (srcfile);
854 if (truncated)
855 break;
856 file_no++;
857 }
858 fclose (destfile);
859
860 /*
861 Display a notification if a truncate size was specified that is not exactly
862 the size of one of the flash card sizes.
863 */
864 n = truncate_size;
865 while (n >>= 1)
866 size_pow2 <<= 1;
867 if (truncate_size == size_pow2)
868 truncate_size_ispow2 = 1;
869
870 n = totalsize - 1;
871 while (n >>= 1)
872 size_pow2_lesser <<= 1;
873
874 size_pow2 = size_pow2_lesser << 1;
875
876 if (totalsize > 64 * MBIT && !truncate_size_ispow2)
877 printf("\n"
878 "NOTE: This multi-game file can only be written to a card >= %u Mbit.\n"
879 " Use -multi=%u to create a file truncated to %u Mbit.\n"
880 " Current size is %.5f Mbit\n", // 5 digits to have 1 byte resolution
881 size_pow2 / MBIT, size_pow2_lesser / MBIT, size_pow2_lesser / MBIT,
882 totalsize / (float) MBIT);
883
884 return 0;
885 }
886
887
888 static int
gba_saver_patch(FILE * destfile,unsigned char * buffer,unsigned int fsize)889 gba_saver_patch (FILE *destfile, unsigned char *buffer, unsigned int fsize)
890 {
891 // reverse engineered from SuperCard.exe
892 const unsigned char saver_patch_orig[38] =
893 {
894 0xf0, 0xb5, 0xa0, 0xb0, 0x0d, 0x1c, 0x16, 0x1c,
895 0x1f, 0x1c, 0x03, 0x04, 0x1c, 0x0c, 0x0f, 0x4a,
896 0x10, 0x88, 0x0f, 0x49, 0x08, 0x40, 0x03, 0x21,
897 0x08, 0x43, 0x10, 0x80, 0x0d, 0x48, 0x00, 0x68,
898 0x01, 0x68, 0x80, 0x20, 0x80, 0x02
899 },
900 saver_patch_repl[38] =
901 {
902 0x70, 0xb5, 0xa0, 0xb0, 0x00, 0x03, 0x40, 0x18,
903 0xe0, 0x21, 0x09, 0x05, 0x09, 0x18, 0x08, 0x78,
904 0x10, 0x70, 0x01, 0x3b, 0x01, 0x32, 0x01, 0x31,
905 0x00, 0x2b, 0xf8, 0xd1, 0x00, 0x20, 0x20, 0xb0,
906 0x70, 0xbc, 0x02, 0xbc, 0x08, 0x47
907 },
908 saver_patch2_orig[38] =
909 {
910 0xf0, 0xb5, 0x90, 0xb0, 0x0f, 0x1c, 0x00, 0x04,
911 0x04, 0x0c, 0x0f, 0x2c, 0x04, 0xd9, 0x01, 0x48,
912 0x40, 0xe0, 0x00, 0x00, 0xff, 0x80, 0x00, 0x00,
913 0x20, 0x1c, 0xff, 0xf7, 0xd7, 0xfe, 0x00, 0x04,
914 0x05, 0x0c, 0x00, 0x2d, 0x35, 0xd1
915 },
916 saver_patch2_repl[38] =
917 {
918 0x70, 0xb5, 0x00, 0x03, 0x0a, 0x1c, 0xe0, 0x21,
919 0x09, 0x05, 0x41, 0x18, 0x01, 0x23, 0x1b, 0x03,
920 0x10, 0x78, 0x08, 0x70, 0x01, 0x3b, 0x01, 0x32,
921 0x01, 0x31, 0x00, 0x2b, 0xf8, 0xd1, 0x00, 0x20,
922 0x70, 0xbc, 0x02, 0xbc, 0x08, 0x47
923 },
924 saver_patch3_orig[38] =
925 {
926 0xa2, 0xb0, 0x0d, 0x1c, 0x00, 0x04, 0x03, 0x0c,
927 0x03, 0x48, 0x00, 0x68, 0x80, 0x88, 0x83, 0x42,
928 0x05, 0xd3, 0x01, 0x48,
929 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, // 6 byte wildcard
930 0xff, 0x80, 0x00, 0x00,
931 0x3f, // 1 byte wildcard
932 0x48, 0x06, 0x1c, 0x00, 0x68, 0x01, 0x7a
933 },
934 saver_patch3_repl[38] =
935 {
936 0x00, 0x04, 0x0a, 0x1c, 0x40, 0x0b, 0xe0, 0x21,
937 0x09, 0x05, 0x41, 0x18, 0x07, 0x31, 0x00, 0x23,
938 0x08, 0x78, 0x10, 0x70,
939 0x01, 0x33, 0x01, 0x32, 0x01, 0x39,
940 0x07, 0x2b, 0xf8, 0xd9,
941 0x00,
942 0x20, 0x70, 0xbc, 0x02, 0xbc, 0x08, 0x47
943 },
944 saver_patch4_orig[40] =
945 {
946 0x30, 0xb5,
947 0xa9, 0xb0, 0x0d, 0x1c, 0x00, 0x04, 0x04, 0x0c,
948 0x03, 0x48, 0x00, 0x68, 0x80, 0x88, 0x84, 0x42,
949 0x05, 0xd3, 0x01, 0x48,
950 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, // 6 byte wildcard
951 0xff, 0x80, 0x00, 0x00, 0x0f, 0x48,
952 0x00, 0x68, 0x00, 0x7a, 0x40, 0x00
953 },
954 saver_patch4_repl[40] =
955 {
956 0x70, 0xb5,
957 0x00, 0x04, 0x0a, 0x1c, 0x40, 0x0b, 0xe0, 0x21,
958 0x09, 0x05, 0x41, 0x18, 0x07, 0x31, 0x00, 0x23,
959 0x10, 0x78, 0x08, 0x70,
960 0x01, 0x33, 0x01, 0x32, 0x01, 0x39,
961 0x07, 0x2b, 0xf8, 0xd9, 0x00, 0x20,
962 0x70, 0xbc, 0x02, 0xbc, 0x08, 0x47
963 },
964 saver_patch5_orig[42] =
965 {
966 0xf0, 0xb5, 0x90, 0xb0, 0x0f, 0x1c, 0x00, 0x04,
967 0x04, 0x0c, 0x03, 0x48, 0x00, 0x68, 0x40, 0x89,
968 0x84, 0x42, 0x05, 0xd3, 0x01, 0x48, 0x41, 0xe0,
969 0xf0, 0x89, 0x03, 0x02, 0xff, 0x80, 0x00, 0x00,
970 0x20, 0x1c, 0xff, 0xf7, 0xd3, 0xfe, 0x00, 0x04,
971 0x05, 0x0c
972 },
973 saver_patch5_repl[42] =
974 {
975 0x7c, 0xb5, 0x90, 0xb0, 0x00, 0x03, 0x0a, 0x1c,
976 0xe0, 0x21, 0x09, 0x05, 0x09, 0x18, 0x01, 0x23,
977 0x1b, 0x03, 0x10, 0x78, 0x08, 0x70, 0x01, 0x3b,
978 0x01, 0x32, 0x01, 0x31, 0x00, 0x2b, 0xf8, 0xd1,
979 0x00, 0x20, 0x10, 0xb0, 0x7c, 0xbc, 0x02, 0xbc,
980 0x08, 0x47
981 };
982 int found = 0;
983 unsigned char *ptr = NULL;
984
985 for (ptr = buffer;
986 (ptr = (unsigned char *) memmem2 (ptr, fsize - (ptr - buffer),
987 saver_patch_orig, 38, 0)) != NULL;
988 ptr++)
989 {
990 if (ucon64.quiet < 0)
991 printf ("offset: 0x%08x\n", (int) (ptr - buffer));
992 fseek (destfile, (long) (ptr - buffer), SEEK_SET);
993 fwrite (saver_patch_repl, 1, 38, destfile);
994 found++;
995 }
996
997 for (ptr = buffer;
998 (ptr = (unsigned char *) memmem2 (ptr, fsize - (ptr - buffer),
999 saver_patch2_orig, 38, 0)) != NULL;
1000 ptr++)
1001 {
1002 if (ucon64.quiet < 0)
1003 printf ("offset: 0x%08x\n", (int) (ptr - buffer));
1004 fseek (destfile, (long) (ptr - buffer), SEEK_SET);
1005 fwrite (saver_patch2_repl, 1, 38, destfile);
1006 found++;
1007 }
1008
1009 for (ptr = buffer;
1010 (ptr = (unsigned char *) memmem2 (ptr, fsize - (ptr - buffer),
1011 saver_patch3_orig, 38, MEMMEM2_WCARD (0x3f))) != NULL;
1012 ptr++)
1013 {
1014 if (ucon64.quiet < 0)
1015 printf ("offset: 0x%08x\n", (int) (ptr - buffer));
1016 fseek (destfile, (long) (ptr - buffer), SEEK_SET);
1017 fwrite (saver_patch3_repl, 1, 38, destfile);
1018 found++;
1019 }
1020
1021 for (ptr = buffer;
1022 (ptr = (unsigned char *) memmem2 (ptr, fsize - (ptr - buffer),
1023 saver_patch4_orig, 40, MEMMEM2_WCARD (0x3f))) != NULL;
1024 ptr++)
1025 {
1026 if (ucon64.quiet < 0)
1027 printf ("offset: 0x%08x\n", (int) (ptr - buffer));
1028 fseek (destfile, (long) (ptr - buffer), SEEK_SET);
1029 fwrite (saver_patch4_repl, 1, 40, destfile);
1030 found++;
1031 }
1032
1033 for (ptr = buffer;
1034 (ptr = (unsigned char *) memmem2 (ptr, fsize - (ptr - buffer),
1035 saver_patch5_orig, 42, 0)) != NULL;
1036 ptr++)
1037 {
1038 if (ucon64.quiet < 0)
1039 printf ("offset: 0x%08x\n", (int) (ptr - buffer));
1040 fseek (destfile, (long) (ptr - buffer), SEEK_SET);
1041 fwrite (saver_patch5_repl, 1, 42, destfile);
1042 found++;
1043 }
1044
1045 fprintf (stdout, "%d saver patches applied\n", found);
1046
1047 return 0;
1048 }
1049
1050
1051 // We allocate one buffer for the templates and loader (not for each structure)
1052 #if GBA_SCI_TEMPLATE_SIZE < GBA_BLANK_SIZE || \
1053 GBA_SCI_TEMPLATE_SIZE < GBA_MENU_SIZE || \
1054 GBA_SCI_TEMPLATE_SIZE < GBA_SAV_TEMPLATE_SIZE
1055 #error GBA_SCI_TEMPLATE_SIZE is too small
1056 #endif
1057
1058 int
gba_sc(void)1059 gba_sc (void)
1060 /*
1061 reverse engineered from SuperCard.exe
1062
1063 BOND EON only?
1064 a0 7f 00 03 00 80 00 03
1065 a0 7f 00 03 f0 7f 00 03
1066
1067 0e 48 39 68 01 60 0e 48 -> 00 48 00 47 01 fb 7f 08
1068 0003756c 0a 1c 02 80 0e 48 39 68 01 60 0e 48 79 68 01 60 TONY HAWK 2!
1069 0003756c 0a 1c 02 80 00 48 00 47 01 fb 7f 08 79 68 01 60
1070
1071 d0 -> e0
1072 00037842 7f 08 27 e0 d0 20 00 05 01 88 01 22 TONY HAWK 2!
1073 00037842 7f 08 27 e0 e0 20 00 05 01 88 01 22
1074
1075 08 80 -> c0 46
1076 00039870 08 88 07 48 08 80 00 f0 e5 f8 01 f0 a9 f8 01 f0 PINOBEE only?
1077 00039870 08 88 07 48 c0 46 00 f0 e5 f8 01 f0 a9 f8 01 f0
1078
1079 08 80 -> c0 46
1080 00000238 3a 4c 20 1c 08 80 3a 49 3a 48 08 60 4a 60 3a 48 PINOBEE
1081 00000238 3a 4c 20 1c c0 46 3a 49 3a 48 08 60 4a 60 3a 48
1082
1083 01 60 -> c0 46
1084 000000fa 09 02 14 31 01 60 27 49 28 48 08 60 40 21 09 03 CT SPECIAL F only?
1085 000000fa 09 02 14 31 c0 46 27 49 28 48 08 60 40 21 09 03
1086 */
1087 {
1088 const unsigned char sc_orig[15][6] =
1089 {
1090 { 0x04, 0x02, 0x00, 0x04, 0x01, 0x20 },
1091 { 0x04, 0x02, 0x00, 0x04, 0x14, 0x40 },
1092 { 0x04, 0x02, 0x00, 0x04, 0x14, 0xb2 },
1093 { 0x04, 0x02, 0x00, 0x04, 0x38, 0x68 },
1094 { 0x04, 0x02, 0x00, 0x04, 0xa0, 0x0f },
1095 { 0x04, 0x02, 0x00, 0x04, 0xb4, 0x05 },
1096 { 0x04, 0x02, 0x00, 0x04, 0xb4, 0x45 },
1097 { 0x04, 0x02, 0x00, 0x04, 0xb6, 0x45 },
1098 { 0x04, 0x02, 0x00, 0x04, 0xb7, 0x45 },
1099 { 0x04, 0x02, 0x00, 0x04, 0xd4, 0x00 },
1100 { 0x04, 0x02, 0x00, 0x04, 0xe3, 0xff },
1101 { 0x04, 0x02, 0x00, 0x04, 0xf8, 0x20 },
1102 { 0x04, 0x02, 0x00, 0x04, 0xfc, 0xff },
1103 { 0x04, 0x02, 0x00, 0x04, 0xfe, 0x2f },
1104 // { 0x04, 0x02, 0x00, 0x04, 0xfe, 0xff }, // CASTLEVANIA1 + CROUCHING TI only?
1105 { 0x04, 0x02, 0x00, 0x04, 0xff, 0xf8 } // they have it but work also without it
1106 },
1107 sc_repl[4] =
1108 {
1109 0x00, 0x00, 0x00, 0x00 // overwrite only the 0x04 0x02 0x00 0x04 part
1110 },
1111 sc2_orig[4] =
1112 {
1113 0xfc, 0x7f, 0x00, 0x03 // replace this everywhere
1114 },
1115 sc2_repl = 0xa0,
1116 sc3_orig[92] =
1117 {
1118 // replace this at offset 0xee only
1119 0x80, 0xe3,
1120 0x81, 0x1f, 0xa0, 0xe3,
1121 0xb1, 0x00, 0x8c, // diff
1122 0xe1,
1123 0xd4, 0xc0, 0x8c, 0xe2, 0x74, 0x00, 0x9f, 0xe5,
1124 0x74, 0x10, 0x9f, 0xe5, 0x74, 0x30, 0x9f, 0xe5,
1125 0x01, 0x30, 0x43, 0xe0, 0x21, 0x23, 0xa0, 0xe3,
1126 0x43, 0x21, 0x82, 0xe1, 0x07, 0x00, 0x8c, 0xe8,
1127 0x03, 0x00, 0x80, 0xe0, 0x60, 0x10, 0x9f, 0xe5,
1128 0x60, 0x30, 0x9f, 0xe5, 0x01, 0x30, 0x43, 0xe0,
1129 0x21, 0x23, 0xa0, 0xe3, 0x43, 0x21, 0x82, 0xe1,
1130 0x07, 0x00, 0x8c, 0xe8, 0x64, 0x30, 0x9f, 0xe5,
1131 0x13, 0xff, 0x2f, 0xe1, 0x15, 0x49, 0x13, 0x48,
1132 0x16, 0x4b, 0x42, 0x1a, 0xd2, 0x1a, 0x02, 0x20,
1133 0xfe, 0x46
1134 },
1135 sc3_repl[92] =
1136 {
1137 0x80, 0xe3,
1138 0x81, 0x1f, 0xa0, 0xe3,
1139 0x00, 0x00, 0xa0, // diff
1140 0xe1,
1141 0xd4, 0xc0, 0x8c, 0xe2, 0x74, 0x00, 0x9f, 0xe5,
1142 0x74, 0x10, 0x9f, 0xe5, 0x74, 0x30, 0x9f, 0xe5,
1143 0x01, 0x30, 0x43, 0xe0, 0x21, 0x23, 0xa0, 0xe3,
1144 0x43, 0x21, 0x82, 0xe1, 0x07, 0x00, 0x8c, 0xe8,
1145 0x03, 0x00, 0x80, 0xe0, 0x60, 0x10, 0x9f, 0xe5,
1146 0x60, 0x30, 0x9f, 0xe5, 0x01, 0x30, 0x43, 0xe0,
1147 0x21, 0x23, 0xa0, 0xe3, 0x43, 0x21, 0x82, 0xe1,
1148 0x07, 0x00, 0x8c, 0xe8, 0x64, 0x30, 0x9f, 0xe5,
1149 0x13, 0xff, 0x2f, 0xe1, 0x15, 0x49, 0x13, 0x48,
1150 0x16, 0x4b, 0x42, 0x1a, 0xd2, 0x1a, 0x02, 0x20,
1151 0xfe, 0x46
1152 };
1153 int x = 0;
1154 unsigned int fsize = (unsigned int) ucon64.fsize, padded = 0;
1155 uint32_t address = 0, pos = 0;
1156 char dest_name[FILENAME_MAX], fname[FILENAME_MAX];
1157 unsigned char *buffer, *ptr = NULL;
1158 const char *p = NULL;
1159 FILE *destfile;
1160
1161 strcpy (dest_name, ucon64.fname);
1162 ucon64_file_handler (dest_name, NULL, 0);
1163 fcopy (ucon64.fname, 0, ucon64.fsize, dest_name, "wb");
1164
1165 if ((destfile = fopen (dest_name, "rb+")) == NULL)
1166 {
1167 fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], dest_name);
1168 return -1;
1169 }
1170 if ((buffer = (unsigned char *) malloc (fsize)) == NULL)
1171 {
1172 fprintf (stderr, ucon64_msg[ROM_BUFFER_ERROR], fsize);
1173 fclose (destfile);
1174 exit (1);
1175 }
1176 if (fread (buffer, 1, fsize, destfile) != fsize)
1177 {
1178 fprintf (stderr, ucon64_msg[READ_ERROR], dest_name);
1179 free (buffer);
1180 fclose (destfile);
1181 return -1;
1182 }
1183
1184 // saver patch
1185 gba_saver_patch (destfile, buffer, fsize);
1186
1187 // restart
1188 for (ptr = buffer;
1189 (ptr = (unsigned char *) memmem2 (ptr, fsize - (ptr - buffer),
1190 sc_orig[0], 4, 0)) != NULL &&
1191 (ptr - buffer) < 7445976; // seems like < 7445976 is far enough
1192 // SONICPINBALL 64Mb (< 7445976)
1193 // AGB KIRBY DX (< 10223404) 128Mb
1194 ptr++)
1195 for (x = 0; x < 15; x++)
1196 if (!memcmp (ptr, sc_orig[x], 6)) // Do the last 2 bytes match?
1197 {
1198 if (ucon64.quiet < 0)
1199 printf ("offset: 0x%08x\n", (int) (ptr - buffer));
1200 fseek (destfile, (long) (ptr - buffer), SEEK_SET);
1201 fwrite (sc_repl, 1, 4, destfile);
1202 }
1203
1204 for (ptr = buffer;
1205 (ptr = (unsigned char *) memmem2 (ptr, fsize - (ptr - buffer),
1206 sc2_orig, 4, 0)) != NULL &&
1207 (ptr - buffer) < 7445660; // seems like < 7445660 is far enough
1208 // SONICPINBALL 64 Mb (< 7445660)
1209 // AGB KIRBY DX (< 10223428) 128Mb
1210 ptr++)
1211 {
1212 if (ucon64.quiet < 0)
1213 printf ("offset: 0x%08x\n", (int) (ptr - buffer));
1214 fseek (destfile, (long) (ptr - buffer), SEEK_SET);
1215 fputc (sc2_repl, destfile);
1216 }
1217
1218 if (!memcmp (buffer + 0xee, &sc3_orig, 92))
1219 {
1220 if (ucon64.quiet < 0)
1221 printf ("offset: 0x%08x\n", 0xee);
1222 fseek (destfile, 0xee, SEEK_SET);
1223 fwrite (sc3_repl, 1, 92, destfile);
1224 }
1225
1226 // write menu (intro) at end of ROM
1227 // SuperCard.exe ignores padding with anything else than 0xff Bytes
1228 fseek (destfile, -1, SEEK_END);
1229 if ((unsigned char) fgetc (destfile) == 0xff)
1230 padded = (unsigned int) ucon64_testpad (ucon64.fname);
1231 fseek (destfile, fsize - padded, SEEK_SET);
1232
1233 printf ("Writing restart menu at offset: 0x%08x\n", fsize - padded);
1234
1235 {
1236 // there is a 52232 bytes blank before the actual menu
1237 unsigned char *old_buffer = buffer;
1238 if ((buffer = (unsigned char *) realloc (old_buffer, GBA_SCI_TEMPLATE_SIZE)) == NULL)
1239 {
1240 fprintf (stderr, ucon64_msg[ROM_BUFFER_ERROR], GBA_SCI_TEMPLATE_SIZE);
1241 free (old_buffer);
1242 fclose (destfile);
1243 exit (1);
1244 }
1245 }
1246 memset (buffer, 0, GBA_BLANK_SIZE);
1247 fwrite (buffer, 1, GBA_BLANK_SIZE, destfile);
1248
1249 /*
1250 menu[0x2f0]:
1251 0xe0, // some kind of chksum? changes into 0xee, 0xf0, ...
1252 0xff, 0x00, 0x0e, 0x01, 0x00, 0x00, 0x00,
1253 0xc0, 0x00, 0x00, 0x08, // the old start address 0xc0 changes into 0xc8 sometimes
1254 0x00, 0x00, 0x00, 0x00,
1255 0x00, 0x00, 0x00, 0x00, 0xf0, 0xfd, 0x00, 0x0e,
1256 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1257 0x00, 0x00, 0x00, 0x08, // address in menu
1258 0x00, 0x00, 0x00, 0x00,
1259 */
1260 // write the menu (the formulas will NOT be optimized)
1261 p = get_property (ucon64.configfile, "gbaloader_sc", PROPERTY_MODE_FILENAME);
1262 if (!p)
1263 p = "sc_menu.bin";
1264 {
1265 size_t len = strnlen (p, sizeof fname - 1);
1266
1267 strncpy (fname, p, len)[len] = '\0';
1268 }
1269 if (ucon64_fread (buffer, 0, GBA_MENU_SIZE, fname) == 0)
1270 {
1271 fprintf (stderr, "ERROR: Could not load Super Card loader (%s)\n", fname);
1272 exit (1); // fatal
1273 }
1274 fwrite (buffer, 1, GBA_MENU_SIZE, destfile);
1275 pos = ftell (destfile); // truncate() this later
1276
1277 // calculate and write new start address
1278 printf ("New start address: 0x%08x\n", (int) (pos - GBA_MENU_SIZE + 0x8000000));
1279 address = ((pos - GBA_MENU_SIZE - 8) >> 2) & 0xffffff;
1280 fseek (destfile, 0, SEEK_SET);
1281 #ifdef WORDS_BIGENDIAN
1282 address = bswap_32 (address);
1283 #endif
1284 fwrite (&address, 1, 3, destfile);
1285
1286 // calculate and write new address at offset 0x60
1287 printf ("New offset 0x60 address: 0x%08x\n", (int) (pos - GBA_MENU_SIZE + 846));
1288 address = (pos - GBA_MENU_SIZE + 846 - 2) & 0xffffff;
1289 if ((pos - GBA_MENU_SIZE) > 128 * MBIT)
1290 address |= 0x09000000; // 0x09 == "large" jmp?
1291 else
1292 address |= 0x08000000;
1293 fseek (destfile, 0x60, SEEK_SET);
1294 #ifdef WORDS_BIGENDIAN
1295 address = bswap_32 (address);
1296 #endif
1297 fwrite (&address, 1, 4, destfile);
1298
1299 // calculate and write new address in menu
1300 printf ("New address in menu: 0x%08x\n", (int) (pos - GBA_MENU_SIZE + 846 - 53076));
1301 address = (pos - GBA_MENU_SIZE + 846 - 53076 - 2) & 0xffffff;
1302 if ((pos - GBA_MENU_SIZE) > 128 * MBIT)
1303 address |= 0x09000000; // 0x09 == "large" jmp?
1304 else
1305 address |= 0x08000000;
1306 fseek (destfile, pos - GBA_MENU_SIZE + 784, SEEK_SET);
1307 #ifdef WORDS_BIGENDIAN
1308 address = bswap_32 (address);
1309 #endif
1310 fwrite (&address, 1, 4, destfile);
1311
1312 fclose (destfile);
1313
1314 puts ("Removing padded bytes");
1315 truncate2 (dest_name, pos);
1316 puts ("Super Card conversion done");
1317 printf (ucon64_msg[WROTE], dest_name);
1318
1319 // write SAV template
1320 set_suffix (dest_name, ".sav");
1321 if ((destfile = fopen (dest_name, "wb")) == NULL)
1322 {
1323 fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], dest_name);
1324 return -1;
1325 }
1326 memset (buffer, 0, GBA_SAV_TEMPLATE_SIZE);
1327 buffer[2] = 0xaa;
1328 buffer[3] = 0x55;
1329 fwrite (buffer, 1, GBA_SAV_TEMPLATE_SIZE, destfile);
1330 fclose (destfile);
1331 printf (ucon64_msg[WROTE], dest_name);
1332
1333 // write SCI template
1334 set_suffix (dest_name, ".sci");
1335 if ((destfile = fopen (dest_name, "wb")) == NULL)
1336 {
1337 fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], dest_name);
1338 return -1;
1339 }
1340 memset (buffer, 0, GBA_SCI_TEMPLATE_SIZE);
1341 buffer[2] = 0xaa;
1342 buffer[3] = 0x55;
1343 fwrite (buffer, 1, GBA_SCI_TEMPLATE_SIZE, destfile);
1344 fclose (destfile);
1345 printf (ucon64_msg[WROTE], dest_name);
1346
1347 free (buffer);
1348 return 0;
1349 }
1350