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