about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--LICENSE1
-rw-r--r--Makefile.gc2
-rw-r--r--Makefile.wii2
-rw-r--r--README.md16
-rw-r--r--build.bat3
-rw-r--r--gba/Makefile13
-rw-r--r--gba/gba_pkjb.ld296
-rw-r--r--gba/gba_pkjb.specs8
-rw-r--r--gba/source/main.c262
-rw-r--r--gba/start/pkjb_crt0.s98
-rw-r--r--source/main.c551
11 files changed, 616 insertions, 636 deletions
diff --git a/LICENSE b/LICENSE index bd6e929..3bef6d6 100644 --- a/LICENSE +++ b/LICENSE
@@ -1,5 +1,6 @@
1The MIT License (MIT) 1The MIT License (MIT)
2 2
3Copyright (c) 2017 slipstream/RoL
3Copyright (c) 2016 FIX94 4Copyright (c) 2016 FIX94
4 5
5Permission is hereby granted, free of charge, to any person obtaining a copy 6Permission is hereby granted, free of charge, to any person obtaining a copy
diff --git a/Makefile.gc b/Makefile.gc index 431c094..3fddc9b 100644 --- a/Makefile.gc +++ b/Makefile.gc
@@ -15,7 +15,7 @@ include $(DEVKITPPC)/gamecube_rules
15# SOURCES is a list of directories containing source code 15# SOURCES is a list of directories containing source code
16# INCLUDES is a list of directories containing extra header files 16# INCLUDES is a list of directories containing extra header files
17#--------------------------------------------------------------------------------- 17#---------------------------------------------------------------------------------
18TARGET := linkcabledump_gc 18TARGET := gen3multiboot_gc
19BUILD := build 19BUILD := build
20SOURCES := source 20SOURCES := source
21DATA := data 21DATA := data
diff --git a/Makefile.wii b/Makefile.wii index 4de7f71..15afd9d 100644 --- a/Makefile.wii +++ b/Makefile.wii
@@ -15,7 +15,7 @@ include $(DEVKITPPC)/wii_rules
15# SOURCES is a list of directories containing source code 15# SOURCES is a list of directories containing source code
16# INCLUDES is a list of directories containing extra header files 16# INCLUDES is a list of directories containing extra header files
17#--------------------------------------------------------------------------------- 17#---------------------------------------------------------------------------------
18TARGET := linkcabledump_wii 18TARGET := gen3multiboot_wii
19BUILD := build 19BUILD := build
20SOURCES := source 20SOURCES := source
21DATA := data 21DATA := data
diff --git a/README.md b/README.md index 91d29d0..4483a83 100644 --- a/README.md +++ b/README.md
@@ -1,8 +1,12 @@
1# GBA Link Cable Dumper 1# GBA Gen3 Multiboot
2A GC and Wii Homebrew App to get GBA BIOS, ROMs and saves via the GC GBA Link Cable. 2A GC and Wii homebrew app that sends a binary to the GBA using the different multiboot protocol used by the third generation of Pokémon games (Ruby, Sapphire, Emerald, FireRed, LeafGreen).
3Save Support based on SendSave by Chishm.
4GBA BIOS Dumper by Dark Fader.
5 3
6# Usage 4# Usage
7Just have a GC Controller in Port 1 and a GBA without a game inserted or aborted game launch by holding select+start in Port 2. 5Have a GC Controller in Port 1 and a GBA with Gen3 game in Port 2.
8The bin, gba and sav files dumped will be placed in a folder called "dumps" on your main device (SD Gecko on gamecube and SD/USB on Wii). Please note that dumping GBA ROMs can take a long time (32mb takes about 48 minutes) because of the cable protocol limitations, a estimation will be displayed on screen before you dump it as a reference. 6Put your payload code to do some interesting stuff with the Pokémon game you have in `gba` dir. Example code that changes first character of player name to 'z' on Pokémon Ruby English (v1.0-1.2) provided.
7Recompile, send to Wii or GC, turn on your GBA, hope that your code runs after the initial copyright screen of the game.
8(Code execution rate is for some reason not 100% reliable, PR to fix would be greatly appreciated. Sometimes KeyC derivation fails, sometimes GBA ignores the sent multiboot image, could be due to failure of a few different sends)
9
10# Acknowledgements
11Thanks to FIX94 for your multiboot game dumper, which the multiboot code is loosely based on (differences in crypto & protocol...)
12Without it, this would have taken longer to do than the 2 days or so that it took. \ No newline at end of file
diff --git a/build.bat b/build.bat index aece78f..8a35180 100644 --- a/build.bat +++ b/build.bat
@@ -1,8 +1,9 @@
1@echo off
1cd gba 2cd gba
2make clean 3make clean
3make 4make
4cd .. 5cd ..
5mv -f gba/gba_mb.gba data/gba_mb.gba 6mv -f gba/gba_pkjb.gba data/gba_mb.gba
6make -f Makefile.gc clean 7make -f Makefile.gc clean
7make -f Makefile.gc 8make -f Makefile.gc
8make -f Makefile.wii clean 9make -f Makefile.wii clean
diff --git a/gba/Makefile b/gba/Makefile index 99dfbb6..f9cb296 100644 --- a/gba/Makefile +++ b/gba/Makefile
@@ -7,6 +7,10 @@ ifeq ($(strip $(DEVKITARM)),)
7$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM) 7$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM)
8endif 8endif
9 9
10%_pkjb.elf:
11 @echo linking pkjb
12 @$(LD) -specs=../gba_pkjb.specs $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
13
10include $(DEVKITARM)/gba_rules 14include $(DEVKITARM)/gba_rules
11 15
12#--------------------------------------------------------------------------------- 16#---------------------------------------------------------------------------------
@@ -16,7 +20,7 @@ include $(DEVKITARM)/gba_rules
16# DATA is a list of directories containing data files 20# DATA is a list of directories containing data files
17# INCLUDES is a list of directories containing header files 21# INCLUDES is a list of directories containing header files
18#--------------------------------------------------------------------------------- 22#---------------------------------------------------------------------------------
19TARGET := $(shell basename $(CURDIR))_mb 23TARGET := $(shell basename $(CURDIR))_pkjb
20BUILD := build 24BUILD := build
21SOURCES := source 25SOURCES := source
22DATA := 26DATA :=
@@ -38,8 +42,8 @@ CFLAGS += $(INCLUDE)
38 42
39CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions 43CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
40 44
41ASFLAGS := $(ARCH) 45ASFLAGS := -g $(ARCH)
42LDFLAGS = -g $(ARCH) -Wl,-Map,$(notdir $@).map 46LDFLAGS = $(ARCH) -Wl,-Map,$(notdir $@).map
43 47
44#--------------------------------------------------------------------------------- 48#---------------------------------------------------------------------------------
45# any extra libraries we wish to link with the project 49# any extra libraries we wish to link with the project
@@ -109,6 +113,7 @@ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
109#--------------------------------------------------------------------------------- 113#---------------------------------------------------------------------------------
110$(BUILD): 114$(BUILD):
111 @[ -d $@ ] || mkdir -p $@ 115 @[ -d $@ ] || mkdir -p $@
116 $(CC) -MMD -MP -MF start/pkjb_crt0.d -x assembler-with-cpp $(ASFLAGS) -c start/pkjb_crt0.s -o start/pkjb_crt0.o $(ERROR_FILTER)
112 @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 117 @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
113 118
114all : $(BUILD) 119all : $(BUILD)
@@ -150,7 +155,7 @@ $(OUTPUT).elf : $(OFILES)
150#--------------------------------------------------------------------------------- 155#---------------------------------------------------------------------------------
151 @echo $(notdir $<) 156 @echo $(notdir $<)
152 @$(bin2o) 157 @$(bin2o)
153 158
154#--------------------------------------------------------------------------------- 159#---------------------------------------------------------------------------------
155# This rule creates assembly source files using grit 160# This rule creates assembly source files using grit
156# grit takes an image file and a .grit describing how the file is to be processed 161# grit takes an image file and a .grit describing how the file is to be processed
diff --git a/gba/gba_pkjb.ld b/gba/gba_pkjb.ld new file mode 100644 index 0000000..102cb42 --- /dev/null +++ b/gba/gba_pkjb.ld
@@ -0,0 +1,296 @@
1/* Linker Script Original v1.3 by Jeff Frohwein */
2/* v1.0 - Original release */
3/* v1.1 - Added proper .data section support */
4/* v1.2 - Added support for c++ & iwram overlays */
5/* - Major contributions by Jason Wilkins. */
6/* v1.3 - .ewram section now can be used when */
7/* compiling for MULTIBOOT mode. This fixes */
8/* malloc() in DevKitAdvance which depends */
9/* on __eheap_start instead of end to define*/
10/* the starting location of heap space. */
11/* External global variable __gba_iwram_heap*/
12/* support added to allow labels end, _end, */
13/* & __end__ to point to end of iwram or */
14/* the end of ewram. */
15/* Additions by WinterMute */
16/* v1.4 - .sbss section added for unitialised */
17/* data in ewram */
18/* v1.5 - padding section added to stop EZF */
19/* stripping important data */
20/* v1.6 - added memory sections */
21
22/* This file is released into the public domain */
23/* for commercial or non-commercial use with no */
24/* restrictions placed upon it. */
25
26/* NOTE!!!: This linker script defines the RAM & */
27/* ROM start addresses. In order for it to work */
28/* properly, remove -Ttext and -Tbss linker */
29/* options from your makefile if they are */
30/* present. */
31
32/* You can use the following to view section */
33/* addresses in your .elf file: */
34/* objdump -h file.elf */
35/* Please note that empty sections may incorrectly*/
36/* list the lma address as the vma address for */
37/* some versions of objdump. */
38
39OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
40OUTPUT_ARCH(arm)
41ENTRY(_start)
42
43MEMORY {
44
45 rom : ORIGIN = 0x08000000, LENGTH = 32M
46 iwram : ORIGIN = 0x03000000, LENGTH = 32K
47 ewram : ORIGIN = 0x02000000, LENGTH = 256K
48}
49
50
51
52__text_start = ORIGIN(ewram);
53__eheap_end = ORIGIN(ewram) + LENGTH(ewram);
54__iwram_start = ORIGIN(iwram);
55__iwram_top = ORIGIN(iwram) + LENGTH(iwram);;
56
57__sp_irq = __iwram_top - 0x060;
58__sp_usr = __sp_irq - 0x0a0;
59__irq_flags = 0x03007ff8;
60
61SECTIONS
62{
63 . = __text_start;
64 .init :
65 {
66 KEEP (*(.init))
67 . = ALIGN(4);
68 } >ewram =0xff
69
70 .plt :
71 {
72 *(.plt)
73 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
74 } >ewram
75
76 .text ALIGN (4):
77 {
78 *(EXCLUDE_FILE (*.iwram*) .text)
79 *(.text .stub .text.* .gnu.linkonce.t.*)
80 KEEP (*(.text.*personality*))
81 /* .gnu.warning sections are handled specially by elf32.em. */
82 *(.gnu.warning)
83 *(.glue_7t) *(.glue_7) *(.vfp11_veneer)
84 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
85 } >ewram = 0xff
86
87 __text_end = .;
88 .fini :
89 {
90 KEEP (*(.fini))
91 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
92 } >ewram =0
93
94 .rodata :
95 {
96 *(.rodata)
97 *all.rodata*(*)
98 *(.roda)
99 *(.rodata.*)
100 *(.gnu.linkonce.r*)
101 SORT(CONSTRUCTORS)
102 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
103 } >ewram = 0xff
104
105 .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >ewram
106 __exidx_start = .;
107 .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >ewram
108 __exidx_end = .;
109 /* Ensure the __preinit_array_start label is properly aligned. We
110 could instead move the label definition inside the section, but
111 the linker would then create the section even if it turns out to
112 be empty, which isn't pretty. */
113 . = ALIGN(32 / 8);
114 PROVIDE (__preinit_array_start = .);
115 .preinit_array : { KEEP (*(.preinit_array)) } >ewram = 0xff
116 PROVIDE (__preinit_array_end = .);
117 PROVIDE (__init_array_start = .);
118 .init_array : { KEEP (*(.init_array)) } >ewram = 0xff
119 PROVIDE (__init_array_end = .);
120 PROVIDE (__fini_array_start = .);
121 .fini_array : { KEEP (*(.fini_array)) } >ewram = 0xff
122 PROVIDE (__fini_array_end = .);
123 .ctors :
124 {
125 /* gcc uses crtbegin.o to find the start of the constructors, so
126 we make sure it is first. Because this is a wildcard, it
127 doesn't matter if the user does not actually link against
128 crtbegin.o; the linker won't look for a file to match a
129 wildcard. The wildcard also means that it doesn't matter which
130 directory crtbegin.o is in. */
131 KEEP (*crtbegin.o(.ctors))
132 KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
133 KEEP (*(SORT(.ctors.*)))
134 KEEP (*(.ctors))
135 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
136 } >ewram = 0
137
138 .dtors :
139 {
140 KEEP (*crtbegin.o(.dtors))
141 KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
142 KEEP (*(SORT(.dtors.*)))
143 KEEP (*(.dtors))
144 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
145 } >ewram = 0
146
147 .jcr : { KEEP (*(.jcr)) } >ewram
148 .eh_frame :
149 {
150 KEEP (*(.eh_frame))
151 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
152 } >ewram = 0
153
154 .gcc_except_table :
155 {
156 *(.gcc_except_table)
157 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
158 } >ewram = 0
159
160 __iwram_lma = .;
161
162 .iwram __iwram_start : AT (__iwram_lma)
163 {
164 __iwram_start__ = ABSOLUTE(.) ;
165 *(.iwram)
166 *iwram.*(.text)
167 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
168 __iwram_end__ = ABSOLUTE(.) ;
169 } >iwram = 0xff
170
171 __data_lma = __iwram_lma + SIZEOF(.iwram) ;
172
173 .bss ALIGN(4) (NOLOAD):
174 {
175 __bss_start__ = ABSOLUTE(.);
176 *(.dynbss)
177 *(.gnu.linkonce.b*)
178 *(.bss*)
179 *(COMMON)
180 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
181 __bss_end__ = ABSOLUTE(.) ;
182 }
183
184 .data ALIGN(4) : AT (__data_lma)
185 {
186 __data_start__ = ABSOLUTE(.);
187 *(.data)
188 *(.data.*)
189 *(.gnu.linkonce.d*)
190 CONSTRUCTORS
191 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
192 __data_end__ = ABSOLUTE(.);
193 } >iwram = 0xff
194
195 __iwram_overlay_lma = __data_lma + SIZEOF(.data);
196
197 PROVIDE (edata = .);
198 __iwram_overlay_start = . ;
199
200 OVERLAY ALIGN(4) : NOCROSSREFS AT (__iwram_overlay_lma)
201 {
202 .iwram0 { *(.iwram0) . = ALIGN(4);}
203 .iwram1 { *(.iwram1) . = ALIGN(4);}
204 .iwram2 { *(.iwram2) . = ALIGN(4);}
205 .iwram3 { *(.iwram3) . = ALIGN(4);}
206 .iwram4 { *(.iwram4) . = ALIGN(4);}
207 .iwram5 { *(.iwram5) . = ALIGN(4);}
208 .iwram6 { *(.iwram6) . = ALIGN(4);}
209 .iwram7 { *(.iwram7) . = ALIGN(4);}
210 .iwram8 { *(.iwram8) . = ALIGN(4);}
211 .iwram9 { *(.iwram9) . = ALIGN(4);}
212 } >iwram = 0xff
213
214 __ewram_lma = LOADADDR(.iwram0) + SIZEOF(.iwram0)+SIZEOF(.iwram1)+SIZEOF(.iwram2)+SIZEOF(.iwram3)+SIZEOF(.iwram4)+SIZEOF(.iwram5)+SIZEOF(.iwram6)+SIZEOF(.iwram7)+SIZEOF(.iwram8)+SIZEOF(.iwram9);
215
216 __iwram_overlay_end = __ewram_lma ;
217
218 /* v1.3 */
219 __ewram_start = __ewram_lma ;
220
221 .ewram __ewram_start : AT (__ewram_lma)
222 {
223 *(.ewram)
224 . = ALIGN(4); /* REQUIRED. LD is flaky without it. */
225 __ewram_end = ABSOLUTE(.);
226 } >ewram = 0xff
227
228 __ewram_overlay_lma = __ewram_lma + SIZEOF(.ewram);
229
230 .sbss ALIGN(4)(NOLOAD):
231 {
232 __sbss_start__ = ABSOLUTE(.);
233 *(.sbss)
234 . = ALIGN(4);
235 __sbss_end__ = ABSOLUTE(.);
236 __end__ = ABSOLUTE(.);
237 __eheap_start = ABSOLUTE(.);
238 }
239
240 OVERLAY ALIGN(4): NOCROSSREFS AT (__ewram_overlay_lma)
241 {
242 .ewram0 { *(.ewram0) . = ALIGN(4);}
243 .ewram1 { *(.ewram1) . = ALIGN(4);}
244 .ewram2 { *(.ewram2) . = ALIGN(4);}
245 .ewram3 { *(.ewram3) . = ALIGN(4);}
246 .ewram4 { *(.ewram4) . = ALIGN(4);}
247 .ewram5 { *(.ewram5) . = ALIGN(4);}
248 .ewram6 { *(.ewram6) . = ALIGN(4);}
249 .ewram7 { *(.ewram7) . = ALIGN(4);}
250 .ewram8 { *(.ewram8) . = ALIGN(4);}
251 .ewram9 { *(.ewram9) . = ALIGN(4);}
252 } >ewram = 0xff
253 __ewram_overlay_end = ABSOLUTE(.);
254
255 __eheap_start = __ewram_overlay_end ;
256
257 _end = __ewram_overlay_end;
258 __end__ = __ewram_overlay_end;
259 __rom_end__ = __ewram_overlay_end;
260
261 /* Stabs debugging sections. */
262 .stab 0 : { *(.stab) }
263 .stabstr 0 : { *(.stabstr) }
264 .stab.excl 0 : { *(.stab.excl) }
265 .stab.exclstr 0 : { *(.stab.exclstr) }
266 .stab.index 0 : { *(.stab.index) }
267 .stab.indexstr 0 : { *(.stab.indexstr) }
268 .comment 0 : { *(.comment) }
269 /* DWARF debug sections.
270 Symbols in the DWARF debugging sections are relative to the beginning
271 of the section so we begin them at 0. */
272 /* DWARF 1 */
273 .debug 0 : { *(.debug) }
274 .line 0 : { *(.line) }
275 /* GNU DWARF 1 extensions */
276 .debug_srcinfo 0 : { *(.debug_srcinfo) }
277 .debug_sfnames 0 : { *(.debug_sfnames) }
278 /* DWARF 1.1 and DWARF 2 */
279 .debug_aranges 0 : { *(.debug_aranges) }
280 .debug_pubnames 0 : { *(.debug_pubnames) }
281 /* DWARF 2 */
282 .debug_info 0 : { *(.debug_info) }
283 .debug_abbrev 0 : { *(.debug_abbrev) }
284 .debug_line 0 : { *(.debug_line) }
285 .debug_frame 0 : { *(.debug_frame) }
286 .debug_str 0 : { *(.debug_str) }
287 .debug_loc 0 : { *(.debug_loc) }
288 .debug_macinfo 0 : { *(.debug_macinfo) }
289 /* SGI/MIPS DWARF 2 extensions */
290 .debug_weaknames 0 : { *(.debug_weaknames) }
291 .debug_funcnames 0 : { *(.debug_funcnames) }
292 .debug_typenames 0 : { *(.debug_typenames) }
293 .debug_varnames 0 : { *(.debug_varnames) }
294 .stack 0x80000 : { _stack = .; *(.stack) }
295 /* These must appear regardless of . */
296}
diff --git a/gba/gba_pkjb.specs b/gba/gba_pkjb.specs new file mode 100644 index 0000000..7c9027b --- /dev/null +++ b/gba/gba_pkjb.specs
@@ -0,0 +1,8 @@
1%rename link old_link
2
3*link:
4-T ../gba_pkjb.ld%s %(old_link) --gc-sections
5
6*startfile:
7../start/pkjb_crt0%O%s crti%O%s crtbegin%O%s
8
diff --git a/gba/source/main.c b/gba/source/main.c index ee94c35..ce6969b 100644 --- a/gba/source/main.c +++ b/gba/source/main.c
@@ -1,241 +1,45 @@
1/* 1/*
2 * Copyright (C) 2016 FIX94 2 * Example Gen3-multiboot payload by slipstream/RoL 2017.
3 * Supports only English Ruby, v1.0-1.2.
3 * 4 *
4 * This software may be modified and distributed under the terms 5 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details. 6 * of the MIT license. See the LICENSE file for details.
6 */ 7 */
7#include <gba.h> 8#include <gba.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include "libSave.h"
11 9
12#define REG_WAITCNT *(vu16 *)(REG_BASE + 0x204)
13#define JOY_WRITE 2
14#define JOY_READ 4
15#define JOY_RW 6
16
17u8 save_data[0x20000] __attribute__ ((section (".sbss")));
18
19s32 getGameSize(void)
20{
21 if(*(vu32*)(0x08000004) != 0x51AEFF24)
22 return -1;
23 s32 i;
24 for(i = (1<<20); i < (1<<25); i<<=1)
25 {
26 vu16 *rompos = (vu16*)(0x08000000+i);
27 int j;
28 bool romend = true;
29 for(j = 0; j < 0x1000; j++)
30 {
31 if(rompos[j] != j)
32 {
33 romend = false;
34 break;
35 }
36 }
37 if(romend) break;
38 }
39 return i;
40}
41
42//---------------------------------------------------------------------------------
43// Program entry point
44//---------------------------------------------------------------------------------
45int main(void) { 10int main(void) {
46//--------------------------------------------------------------------------------- 11 // check the ROM code, make sure this game is supported.
47 12 char* ROM = 0x8000000;
48 // the vblank interrupt must be enabled for VBlankIntrWait() to work 13
49 // since the default dispatcher handles the bios flags no vblank handler 14 if ((*(u32*)(&ROM[0xAC])) != 'EVXA') return 0; // Pokémon Ruby english, nothing else supported!
50 // is required 15
51 irqInit(); 16 void(*loadsave)(char a1);
52 irqEnable(IRQ_VBLANK); 17 // get the address of the save loading function.
53 18 switch (ROM[0xBC]) { // version number
54 consoleDemoInit(); 19 case 0:
55 REG_JOYTR = 0; 20 loadsave = 0x8125EC9;
56 // ansi escape sequence to set print co-ordinates 21 break;
57 // /x1b[line;columnH 22 case 1:
58 u32 i; 23 case 2:
59 iprintf("\x1b[9;2HGBA Link Cable Dumper v1.6\n"); 24 loadsave = 0x8125EE9;
60 iprintf("\x1b[10;4HPlease look at the TV\n"); 25 break;
61 // disable this, needs power 26 default:
62 SNDSTAT = 0; 27 return 0; //bail out
63 SNDBIAS = 0;
64 // Set up waitstates for EEPROM access etc.
65 REG_WAITCNT = 0x0317;
66 //clear out previous messages
67 REG_HS_CTRL |= JOY_RW;
68 while (1) {
69 if(REG_HS_CTRL&JOY_READ)
70 {
71 REG_HS_CTRL |= JOY_RW;
72 s32 gamesize = getGameSize();
73 u32 savesize = SaveSize(save_data,gamesize);
74 REG_JOYTR = gamesize;
75 //wait for a cmd receive for safety
76 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
77 REG_HS_CTRL |= JOY_RW;
78 REG_JOYTR = savesize;
79 //wait for a cmd receive for safety
80 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
81 REG_HS_CTRL |= JOY_RW;
82 if(gamesize == -1)
83 {
84 REG_JOYTR = 0;
85 continue; //nothing to read
86 }
87 //game in, send header
88 for(i = 0; i < 0xC0; i+=4)
89 {
90 REG_JOYTR = *(vu32*)(0x08000000+i);
91 while((REG_HS_CTRL&JOY_READ) == 0) ;
92 REG_HS_CTRL |= JOY_RW;
93 }
94 REG_JOYTR = 0;
95 //wait for other side to choose
96 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
97 REG_HS_CTRL |= JOY_RW;
98 u32 choseval = REG_JOYRE;
99 if(choseval == 0)
100 {
101 REG_JOYTR = 0;
102 continue; //nothing to read
103 }
104 else if(choseval == 1)
105 {
106 //disable interrupts
107 u32 prevIrqMask = REG_IME;
108 REG_IME = 0;
109 //dump the game
110 for(i = 0; i < gamesize; i+=4)
111 {
112 REG_JOYTR = *(vu32*)(0x08000000+i);
113 while((REG_HS_CTRL&JOY_READ) == 0) ;
114 REG_HS_CTRL |= JOY_RW;
115 }
116 //restore interrupts
117 REG_IME = prevIrqMask;
118 }
119 else if(choseval == 2)
120 {
121 //disable interrupts
122 u32 prevIrqMask = REG_IME;
123 REG_IME = 0;
124 //backup save
125 switch (savesize){
126 case 0x200:
127 GetSave_EEPROM_512B(save_data);
128 break;
129 case 0x2000:
130 GetSave_EEPROM_8KB(save_data);
131 break;
132 case 0x8000:
133 GetSave_SRAM_32KB(save_data);
134 break;
135 case 0x10000:
136 GetSave_FLASH_64KB(save_data);
137 break;
138 case 0x20000:
139 GetSave_FLASH_128KB(save_data);
140 break;
141 default:
142 break;
143 }
144 //restore interrupts
145 REG_IME = prevIrqMask;
146 //say gc side we read it
147 REG_JOYTR = savesize;
148 //wait for a cmd receive for safety
149 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
150 REG_HS_CTRL |= JOY_RW;
151 //send the save
152 for(i = 0; i < savesize; i+=4)
153 {
154 REG_JOYTR = *(vu32*)(save_data+i);
155 while((REG_HS_CTRL&JOY_READ) == 0) ;
156 REG_HS_CTRL |= JOY_RW;
157 }
158 }
159 else if(choseval == 3 || choseval == 4)
160 {
161 REG_JOYTR = savesize;
162 if(choseval == 3)
163 {
164 //receive the save
165 for(i = 0; i < savesize; i+=4)
166 {
167 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
168 REG_HS_CTRL |= JOY_RW;
169 *(vu32*)(save_data+i) = REG_JOYRE;
170 }
171 }
172 else
173 {
174 //clear the save
175 for(i = 0; i < savesize; i+=4)
176 *(vu32*)(save_data+i) = 0;
177 }
178 //disable interrupts
179 u32 prevIrqMask = REG_IME;
180 REG_IME = 0;
181 //write it
182 switch (savesize){
183 case 0x200:
184 PutSave_EEPROM_512B(save_data);
185 break;
186 case 0x2000:
187 PutSave_EEPROM_8KB(save_data);
188 break;
189 case 0x8000:
190 PutSave_SRAM_32KB(save_data);
191 break;
192 case 0x10000:
193 PutSave_FLASH_64KB(save_data);
194 break;
195 case 0x20000:
196 PutSave_FLASH_128KB(save_data);
197 break;
198 default:
199 break;
200 }
201 //restore interrupts
202 REG_IME = prevIrqMask;
203 //say gc side we're done
204 REG_JOYTR = 0;
205 //wait for a cmd receive for safety
206 while((REG_HS_CTRL&JOY_WRITE) == 0) ;
207 REG_HS_CTRL |= JOY_RW;
208 }
209 REG_JOYTR = 0;
210 }
211 else if(REG_HS_CTRL&JOY_WRITE)
212 {
213 REG_HS_CTRL |= JOY_RW;
214 u32 choseval = REG_JOYRE;
215 if(choseval == 5)
216 {
217 //disable interrupts
218 u32 prevIrqMask = REG_IME;
219 REG_IME = 0;
220 //dump BIOS
221 for (i = 0; i < 0x4000; i+=4)
222 {
223 // the lower bits are inaccurate, so just get it four times :)
224 u32 a = MidiKey2Freq((WaveData *)(i-4), 180-12, 0) * 2;
225 u32 b = MidiKey2Freq((WaveData *)(i-3), 180-12, 0) * 2;
226 u32 c = MidiKey2Freq((WaveData *)(i-2), 180-12, 0) * 2;
227 u32 d = MidiKey2Freq((WaveData *)(i-1), 180-12, 0) * 2;
228 REG_JOYTR = ((a>>24<<24) | (d>>24<<16) | (c>>24<<8) | (b>>24));
229 while((REG_HS_CTRL&JOY_READ) == 0) ;
230 REG_HS_CTRL |= JOY_RW;
231 }
232 //restore interrupts
233 REG_IME = prevIrqMask;
234 }
235 REG_JOYTR = 0;
236 }
237 Halt();
238 } 28 }
29 loadsave(0);
30 // now the save is loaded, we can do what we want with the loaded blocks.
31 // here as a small PoC, changing first letter of player name to 'z'.
32 u8* gSaveBlock2 = 0x2024EA4;
33 gSaveBlock2[0] = 0xee; // 'z'
34 // Now we've done what we want, time to return to the game.
35 // Can't just return, the game will reload the save.
36 // So let's just call the main-loop directly ;)
37 void(*mainloop)() = 0x80002A5;
38 // turn the sound back on before we head back to the game
39 *(vu16 *)(REG_BASE + 0x84) = 0x8f;
40 mainloop();
41 // Anything past here will not be executed.
42 return 0;
239} 43}
240 44
241 45
diff --git a/gba/start/pkjb_crt0.s b/gba/start/pkjb_crt0.s new file mode 100644 index 0000000..1bf5bd7 --- /dev/null +++ b/gba/start/pkjb_crt0.s
@@ -0,0 +1,98 @@
1 .section ".init"
2 .global _start
3 .align
4 .arm
5@---------------------------------------------------------------------------------
6_start:
7@---------------------------------------------------------------------------------
8 b rom_header_end
9
10 .fill 156,1,0 @ Nintendo Logo Character Data (8000004h)
11 .fill 16,1,0 @ Game Title
12 .byte 0x30,0x31 @ Maker Code (80000B0h)
13 .byte 0x96 @ Fixed Value (80000B2h)
14 .byte 0x00 @ Main Unit Code (80000B3h)
15 .byte 0x00 @ Device Type (80000B4h)
16 .fill 7,1,0 @ unused
17 .byte 0x00 @ Software Version No (80000BCh)
18 .byte 0xf0 @ Complement Check (80000BDh)
19 .byte 0x00,0x00 @ Checksum (80000BEh)
20
21@---------------------------------------------------------------------------------
22rom_header_end:
23@---------------------------------------------------------------------------------
24 b start_vector @ This branch must be here for proper
25 @ positioning of the following header.
26
27 .GLOBAL __boot_method, __slave_number
28@---------------------------------------------------------------------------------
29__boot_method:
30@---------------------------------------------------------------------------------
31 .byte 0 @ boot method (0=ROM boot, 3=Multiplay boot)
32@---------------------------------------------------------------------------------
33__slave_number:
34@---------------------------------------------------------------------------------
35 .byte 0 @ slave # (1=slave#1, 2=slave#2, 3=slave#3)
36
37 .byte 0 @ reserved
38 .byte 0 @ reserved
39 .word 0 @ reserved
40 .word 0 @ reserved
41 .word 0 @ reserved
42 .word 0 @ reserved
43 .word 0 @ reserved
44 .word 0 @ reserved
45
46 .fill 4096,1,0 @ 4kb of filler so no useful code gets overwritten when flash bytes get copied over the top.
47 .global start_vector
48 .align
49@---------------------------------------------------------------------------------
50start_vector:
51@---------------------------------------------------------------------------------
52
53@---------------------------------------------------------------------------------
54@ Enter Thumb mode
55@---------------------------------------------------------------------------------
56 add r0, pc, #1
57 bx r0
58
59 .thumb
60@ Turn off sound
61 ldr r1, =0x4000084
62 eor r0, r0, r0
63 strh r0, [r1]
64
65@---------------------------------------------------------------------------------
66@ set heap end
67@---------------------------------------------------------------------------------
68 ldr r1, =fake_heap_end
69 ldr r0, =__eheap_end
70 str r0, [r1]
71@---------------------------------------------------------------------------------
72@ global constructors
73@---------------------------------------------------------------------------------
74 ldr r3, =__libc_init_array
75 push {lr}
76 bl _blx_r3_stub
77@---------------------------------------------------------------------------------
78@ Jump to user code
79@---------------------------------------------------------------------------------
80 mov r0, #0 @ int argc
81 mov r1, #0 @ char *argv[]
82 ldr r3, =main
83 bl _blx_r3_stub
84@; If we're here, turn the sound back on before we return
85 ldr r1, =0x4000084
86 mov r0, #0x8F
87 strh r0, [r1]
88 pop {pc}
89
90@---------------------------------------------------------------------------------
91_blx_r3_stub:
92@---------------------------------------------------------------------------------
93 bx r3
94
95 .align
96 .pool
97 .end
98
diff --git a/source/main.c b/source/main.c index 7fd5683..ad34eff 100644 --- a/source/main.c +++ b/source/main.c
@@ -1,4 +1,5 @@
1/* 1/*
2 * Copyright (c) 2017 slipstream/RoL
2 * Copyright (C) 2016 FIX94 3 * Copyright (C) 2016 FIX94
3 * 4 *
4 * This software may be modified and distributed under the terms 5 * This software may be modified and distributed under the terms
@@ -13,8 +14,6 @@
13#include <sys/types.h> 14#include <sys/types.h>
14#include <sys/stat.h> 15#include <sys/stat.h>
15#include <fcntl.h> 16#include <fcntl.h>
16#include <dirent.h>
17#include <fat.h>
18 17
19//from my tests 50us seems to be the lowest 18//from my tests 50us seems to be the lowest
20//safe si transfer delay in between calls 19//safe si transfer delay in between calls
@@ -27,9 +26,8 @@ void printmain()
27{ 26{
28 printf("\x1b[2J"); 27 printf("\x1b[2J");
29 printf("\x1b[37m"); 28 printf("\x1b[37m");
30 printf("GBA Link Cable Dumper v1.6 by FIX94\n"); 29 printf("Pokemon Gen 3 GBA Multiboot PoC by slipstream/RoL\n");
31 printf("Save Support based on SendSave by Chishm\n"); 30 printf("Based on GBA Link Cable Dumper by FIX94\n\n");
32 printf("GBA BIOS Dumper by Dark Fader\n \n");
33} 31}
34 32
35u8 *resbuf,*cmdbuf; 33u8 *resbuf,*cmdbuf;
@@ -46,21 +44,17 @@ void acb(s32 res, u32 val)
46 resval = val; 44 resval = val;
47} 45}
48 46
49unsigned int docrc(u32 crc, u32 val) 47unsigned int docrc(u32 crc,u32 val) {
50{ 48 u32 result;
51 int i; 49
52 for(i = 0; i < 0x20; i++) 50 result = val ^ crc;
53 { 51 for (int i = 0; i < 0x20; i++) {
54 if((crc^val)&1) 52 if (result & 1) {
55 { 53 result >>= 1;
56 crc>>=1; 54 result ^= 0xA1C1;
57 crc^=0xa1c1; 55 } else result >>= 1;
58 }
59 else
60 crc>>=1;
61 val>>=1;
62 } 56 }
63 return crc; 57 return result;
64} 58}
65 59
66void endproc() 60void endproc()
@@ -70,64 +64,7 @@ void endproc()
70 VIDEO_WaitVSync(); 64 VIDEO_WaitVSync();
71 exit(0); 65 exit(0);
72} 66}
73void fixFName(char *str)
74{
75 u8 i = 0;
76 for(i = 0; i < strlen(str); ++i)
77 {
78 if(str[i] < 0x20 || str[i] > 0x7F)
79 str[i] = '_';
80 else switch(str[i])
81 {
82 case '\\':
83 case '/':
84 case ':':
85 case '*':
86 case '?':
87 case '\"':
88 case '<':
89 case '>':
90 case '|':
91 str[i] = '_';
92 break;
93 default:
94 break;
95 }
96 }
97}
98unsigned int calckey(unsigned int size)
99{
100 unsigned int ret = 0;
101 size=(size-0x200) >> 3;
102 int res1 = (size&0x3F80) << 1;
103 res1 |= (size&0x4000) << 2;
104 res1 |= (size&0x7F);
105 res1 |= 0x380000;
106 int res2 = res1;
107 res1 = res2 >> 0x10;
108 int res3 = res2 >> 8;
109 res3 += res1;
110 res3 += res2;
111 res3 <<= 24;
112 res3 |= res2;
113 res3 |= 0x80808080;
114 67
115 if((res3&0x200) == 0)
116 {
117 ret |= (((res3)&0xFF)^0x4B)<<24;
118 ret |= (((res3>>8)&0xFF)^0x61)<<16;
119 ret |= (((res3>>16)&0xFF)^0x77)<<8;
120 ret |= (((res3>>24)&0xFF)^0x61);
121 }
122 else
123 {
124 ret |= (((res3)&0xFF)^0x73)<<24;
125 ret |= (((res3>>8)&0xFF)^0x65)<<16;
126 ret |= (((res3>>16)&0xFF)^0x64)<<8;
127 ret |= (((res3>>24)&0xFF)^0x6F);
128 }
129 return ret;
130}
131void doreset() 68void doreset()
132{ 69{
133 cmdbuf[0] = 0xFF; //reset 70 cmdbuf[0] = 0xFF; //reset
@@ -135,6 +72,7 @@ void doreset()
135 SI_Transfer(1,cmdbuf,1,resbuf,3,transcb,SI_TRANS_DELAY); 72 SI_Transfer(1,cmdbuf,1,resbuf,3,transcb,SI_TRANS_DELAY);
136 while(transval == 0) ; 73 while(transval == 0) ;
137} 74}
75
138void getstatus() 76void getstatus()
139{ 77{
140 cmdbuf[0] = 0; //status 78 cmdbuf[0] = 0; //status
@@ -142,6 +80,7 @@ void getstatus()
142 SI_Transfer(1,cmdbuf,1,resbuf,3,transcb,SI_TRANS_DELAY); 80 SI_Transfer(1,cmdbuf,1,resbuf,3,transcb,SI_TRANS_DELAY);
143 while(transval == 0) ; 81 while(transval == 0) ;
144} 82}
83
145u32 recv() 84u32 recv()
146{ 85{
147 memset(resbuf,0,32); 86 memset(resbuf,0,32);
@@ -151,6 +90,7 @@ u32 recv()
151 while(transval == 0) ; 90 while(transval == 0) ;
152 return *(vu32*)resbuf; 91 return *(vu32*)resbuf;
153} 92}
93
154void send(u32 msg) 94void send(u32 msg)
155{ 95{
156 cmdbuf[0]=0x15;cmdbuf[1]=(msg>>0)&0xFF;cmdbuf[2]=(msg>>8)&0xFF; 96 cmdbuf[0]=0x15;cmdbuf[1]=(msg>>0)&0xFF;cmdbuf[2]=(msg>>8)&0xFF;
@@ -160,26 +100,7 @@ void send(u32 msg)
160 SI_Transfer(1,cmdbuf,5,resbuf,1,transcb,SI_TRANS_DELAY); 100 SI_Transfer(1,cmdbuf,5,resbuf,1,transcb,SI_TRANS_DELAY);
161 while(transval == 0) ; 101 while(transval == 0) ;
162} 102}
163bool dirExists(const char *path) 103
164{
165 DIR *dir;
166 dir = opendir(path);
167 if(dir)
168 {
169 closedir(dir);
170 return true;
171 }
172 return false;
173}
174void createFile(const char *path, size_t size)
175{
176 int fd = open(path, O_WRONLY|O_CREAT);
177 if(fd >= 0)
178 {
179 ftruncate(fd, size);
180 close(fd);
181 }
182}
183void warnError(char *msg) 104void warnError(char *msg)
184{ 105{
185 puts(msg); 106 puts(msg);
@@ -195,6 +116,68 @@ void fatalError(char *msg)
195 sleep(5); 116 sleep(5);
196 exit(0); 117 exit(0);
197} 118}
119
120u32 genKeyA() {
121 u32 retries = 0;
122 while (true) {
123 u32 key = 0;
124 if (retries > 32) {
125 key = 0xDD654321;
126 } else {
127 key = (rand() & 0x00ffffff) | 0xDD000000;
128 }
129 u32 unk = (key % 2 != 0);
130 u32 v12 = key;
131 for (u32 v13 = 1; v13 < 32; v13++) {
132 v12 >>= 1;
133 unk += (v12 % 2 != 0);
134 }
135 if ((unk >= 10 && unk <= 24)) {
136 if (retries > 4) printf("KeyA retries = %d",retries);
137 printf("KeyA = 0x%08x\n",key);
138 return key;
139 }
140 retries++;
141 }
142}
143
144u32 checkKeyB(u32 KeyBRaw) {
145 if ((KeyBRaw & 0xFF) != 0xEE) {
146 printf("Invalid KeyB - lowest 8 bits should be 0xEE, actually 0x%02x\n",((u8)(KeyBRaw)));
147 return 0;
148 }
149 u32 KeyB = KeyBRaw & 0xffffff00;
150 u32 val = KeyB;
151 u32 unk = (val < 0);
152 for (u32 i = 1; i < 24; i++) {
153 val <<= 1;
154 unk += (val < 0);
155 }
156 if (unk > 14) {
157 printf("Invalid KeyB - high 24 bits bad: 0x%08x\n",KeyB);
158 return 0;
159 }
160 printf("Valid KeyB: 0x%08x\n",KeyB);
161 return KeyB;
162}
163
164u32 deriveKeyC(u32 keyCderive, u32 kcrc) {
165 u32 keyc = 0;
166 u32 keyCi = 0;
167 do {
168 u32 v5 = 0x1000000 * keyCi - 1;
169 u32 keyCattempt = docrc(kcrc,v5);
170 //printf("i = %d; keyCderive = %08x; keyCattempt = %08x\n",keyCi,keyCderive,keyCattempt);
171 if (keyCderive == keyCattempt) {
172 keyc = v5;
173 printf("Found keyC: %08x\n",keyc);
174 return keyc;
175 }
176 keyCi++;
177 } while (keyCi < 256);
178 return keyc;
179}
180
198int main(int argc, char *argv[]) 181int main(int argc, char *argv[])
199{ 182{
200 void *xfb = NULL; 183 void *xfb = NULL;
@@ -216,19 +199,6 @@ int main(int argc, char *argv[])
216 PAD_Init(); 199 PAD_Init();
217 cmdbuf = memalign(32,32); 200 cmdbuf = memalign(32,32);
218 resbuf = memalign(32,32); 201 resbuf = memalign(32,32);
219 u8 *testdump = memalign(32,0x400000);
220 if(!testdump) return 0;
221 if(!fatInitDefault())
222 {
223 printmain();
224 fatalError("ERROR: No usable device found to write dumped files to!");
225 }
226 mkdir("/dumps", S_IREAD | S_IWRITE);
227 if(!dirExists("/dumps"))
228 {
229 printmain();
230 fatalError("ERROR: Could not create dumps folder, make sure you have a supported device connected!");
231 }
232 int i; 202 int i;
233 while(1) 203 while(1)
234 { 204 {
@@ -251,305 +221,98 @@ int main(int argc, char *argv[])
251 } 221 }
252 PAD_ScanPads(); 222 PAD_ScanPads();
253 VIDEO_WaitVSync(); 223 VIDEO_WaitVSync();
254 if(PAD_ButtonsHeld(0)) 224 if(PAD_ButtonsDown(0) & PAD_BUTTON_START)
255 endproc(); 225 endproc();
256 } 226 }
257 if(resval & SI_GBA) 227 if (resval & SI_GBA)
258 { 228 {
259 printf("GBA Found! Waiting on BIOS\n"); 229 printf("GBA Found! Waiting on BIOS\n");
260 resbuf[2]=0; 230 resbuf[2]=0;
261 while(!(resbuf[2]&0x10)) 231 u32 oldresult = 0;
232 u32 newresult = 0;
233 // wait for the BIOS to hand over to the game
234 do {
235 doreset();
236 } while (!(resbuf[1] > 4));
237 printf("BIOS handed over to game, waiting on game\n");
238 do
262 { 239 {
263 doreset(); 240 doreset();
264 getstatus(); 241 } while((resbuf[0] != 0) || !(resbuf[2]&0x10));
265 } 242 // receive the game-code from GBA side.
266 printf("Ready, sending dumper\n"); 243 u32 gamecode = recv();
244 printf("Ready, sending multiboot ROM\n");
267 unsigned int sendsize = ((gba_mb_gba_size+7)&~7); 245 unsigned int sendsize = ((gba_mb_gba_size+7)&~7);
268 unsigned int ourkey = calckey(sendsize); 246 // generate KeyA
247 unsigned int ourkey = genKeyA();
269 //printf("Our Key: %08x\n", ourkey); 248 //printf("Our Key: %08x\n", ourkey);
270 //get current sessionkey 249 printf("Sending game code that we got: 0x%08x\n",__builtin_bswap32(gamecode));
271 u32 sessionkeyraw = recv(); 250 // send the game code back, then KeyA.
272 u32 sessionkey = __builtin_bswap32(sessionkeyraw^0x7365646F); 251 send(__builtin_bswap32(gamecode));
273 //send over our own key 252 send(ourkey);
274 send(__builtin_bswap32(ourkey)); 253 // get KeyB from GBA, check it to make sure its valid, then xor with KeyA to derive the initial CRC value and the sessionkey.
275 unsigned int fcrc = 0x15a0; 254 u32 sessionkeyraw = 0;
276 //send over gba header 255 do {
277 for(i = 0; i < 0xC0; i+=4) 256 sessionkeyraw = recv();
278 send(__builtin_bswap32(*(vu32*)(gba_mb_gba+i))); 257 } while (sessionkeyraw == gamecode);
279 //printf("Header done! Sending ROM...\n"); 258 sessionkeyraw = checkKeyB(__builtin_bswap32(sessionkeyraw));
280 for(i = 0xC0; i < sendsize; i+=4) 259 u32 sessionkey = sessionkeyraw ^ ourkey;
260 u32 kcrc = sessionkey;
261 printf("start kCRC=%08x\n",kcrc);
262 sessionkey = (sessionkey*0x6177614b)+1;
263 // send hacked up send-size in uint32s
264 u32 hackedupsize = (sendsize >> 3) - 1;
265 printf("Sending hacked up size 0x%08x\n",hackedupsize);
266 send(hackedupsize);
267 //unsigned int fcrc = 0x00bb;
268 // send over multiboot binary header, in the clear until the end of the nintendo logo.
269 // GBA checks this, if nintendo logo does not match the one in currently inserted cart's ROM, it will not accept any more data.
270 for(i = 0; i < 0xA0; i+=4) {
271 vu32 rom_dword = *(vu32*)(gba_mb_gba+i);
272 send(__builtin_bswap32(rom_dword));
273 }
274 printf("\n");
275 printf("Header done! Sending ROM...\n");
276 // Add each uint32 of the multiboot image to the checksum, encrypt the uint32 with the session key, increment the session key, send the encrypted uint32.
277 for(i = 0xA0; i < sendsize; i+=4)
281 { 278 {
282 u32 enc = ((gba_mb_gba[i+3]<<24)|(gba_mb_gba[i+2]<<16)|(gba_mb_gba[i+1]<<8)|(gba_mb_gba[i])); 279 u32 dec = (
283 fcrc=docrc(fcrc,enc); 280 ((gba_mb_gba[i+3]) << 24) & 0xff000000 |
281 ((gba_mb_gba[i+2]) << 16) & 0x00ff0000 |
282 ((gba_mb_gba[i+1]) << 8) & 0x0000ff00 |
283 ((gba_mb_gba[i]) << 0) & 0x000000ff
284 );
285 u32 enc = (dec - kcrc) ^ sessionkey;
286 kcrc=docrc(kcrc,dec);
284 sessionkey = (sessionkey*0x6177614B)+1; 287 sessionkey = (sessionkey*0x6177614B)+1;
285 enc^=sessionkey; 288 //enc^=((~(i+(0x20<<20)))+1);
286 enc^=((~(i+(0x20<<20)))+1); 289 //enc^=0x6f646573;//0x20796220;
287 enc^=0x20796220;
288 send(enc); 290 send(enc);
289 } 291 }
290 fcrc |= (sendsize<<16); 292 //fcrc |= (sendsize<<16);
291 //printf("ROM done! CRC: %08x\n", fcrc); 293 printf("ROM done! CRC: %08x\n", kcrc);
292 //send over CRC
293 sessionkey = (sessionkey*0x6177614B)+1;
294 fcrc^=sessionkey;
295 fcrc^=((~(i+(0x20<<20)))+1);
296 fcrc^=0x20796220;
297 send(fcrc);
298 //get crc back (unused) 294 //get crc back (unused)
299 recv(); 295 // Get KeyC derivation material from GBA (eventually)
300 printf("Done!\n"); 296 u32 keyCderive = 0;
301 sleep(2); 297 do {
302 //hm 298 keyCderive = recv();
303 while(1) 299 } while (keyCderive <= 0xfeffffff);
304 { 300 keyCderive = __builtin_bswap32(keyCderive);
305 printmain(); 301 keyCderive >>= 8;
306 printf("Press A once you have a GBA Game inserted.\n"); 302 printf("KeyC derivation material: %08x\n",keyCderive);
307 printf("Press Y to backup the GBA BIOS.\n \n"); 303
308 PAD_ScanPads(); 304 // (try to) find the KeyC, using the checksum of the multiboot image, and the derivation material that GBA sent to us
309 VIDEO_WaitVSync(); 305
310 u32 btns = PAD_ButtonsDown(0); 306 u32 keyc = deriveKeyC(keyCderive,kcrc);
311 if(btns&PAD_BUTTON_START) 307 if (keyc == 0) printf("Could not find keyC - kcrc=0x%08x\n",kcrc);
312 endproc(); 308
313 else if(btns&PAD_BUTTON_A) 309 // derive the boot key from the found KeyC, and send to GBA. if this is not correct, GBA will not jump to the multiboot image it was sent.
314 { 310 u32 bootkey = docrc(0xBB,keyc) | 0xbb000000;
315 if(recv() == 0) //ready 311 printf("BootKey = 0x%08x\n",bootkey);
316 { 312 send(bootkey);
317 printf("Waiting for GBA\n"); 313
318 VIDEO_WaitVSync(); 314 printf("Done! Press any key to start sending again.\n");
319 int gbasize = 0; 315 do { PAD_ScanPads(); } while (!PAD_ButtonsDown(0));
320 while(gbasize == 0)
321 gbasize = __builtin_bswap32(recv());
322 send(0); //got gbasize
323 u32 savesize = __builtin_bswap32(recv());
324 send(0); //got savesize
325 if(gbasize == -1)
326 {
327 warnError("ERROR: No (Valid) GBA Card inserted!\n");
328 continue;
329 }
330 //get rom header
331 for(i = 0; i < 0xC0; i+=4)
332 *(vu32*)(testdump+i) = recv();
333 //print out all the info from the game
334 printf("Game Name: %.12s\n",(char*)(testdump+0xA0));
335 printf("Game ID: %.4s\n",(char*)(testdump+0xAC));
336 printf("Company ID: %.2s\n",(char*)(testdump+0xB0));
337 printf("ROM Size: %02.02f MB\n",((float)(gbasize/1024))/1024.f);
338 if(savesize > 0)
339 printf("Save Size: %02.02f KB\n \n",((float)(savesize))/1024.f);
340 else
341 printf("No Save File\n \n");
342 //generate file paths
343 char gamename[64];
344 sprintf(gamename,"/dumps/%.12s [%.4s%.2s].gba",
345 (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0));
346 fixFName(gamename+7); //fix name behind "/dumps/"
347 char savename[64];
348 sprintf(savename,"/dumps/%.12s [%.4s%.2s].sav",
349 (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0));
350 fixFName(savename+7); //fix name behind "/dumps/"
351 //let the user choose the option
352 printf("Press A to dump this game, it will take about %i minutes.\n",gbasize/1024/1024*3/2);
353 printf("Press B if you want to cancel dumping this game.\n");
354 if(savesize > 0)
355 {
356 printf("Press Y to backup this save file.\n");
357 printf("Press X to restore this save file.\n");
358 printf("Press Z to clear the save file on the GBA Cartridge.\n\n");
359 }
360 else
361 printf("\n");
362 int command = 0;
363 while(1)
364 {
365 PAD_ScanPads();
366 VIDEO_WaitVSync();
367 u32 btns = PAD_ButtonsDown(0);
368 if(btns&PAD_BUTTON_START)
369 endproc();
370 else if(btns&PAD_BUTTON_A)
371 {
372 command = 1;
373 break;
374 }
375 else if(btns&PAD_BUTTON_B)
376 break;
377 else if(savesize > 0)
378 {
379 if(btns&PAD_BUTTON_Y)
380 {
381 command = 2;
382 break;
383 }
384 else if(btns&PAD_BUTTON_X)
385 {
386 command = 3;
387 break;
388 }
389 else if(btns&PAD_TRIGGER_Z)
390 {
391 command = 4;
392 break;
393 }
394 }
395 }
396 if(command == 1)
397 {
398 FILE *f = fopen(gamename,"rb");
399 if(f)
400 {
401 fclose(f);
402 command = 0;
403 warnError("ERROR: Game already dumped!\n");
404 }
405 }
406 else if(command == 2)
407 {
408 FILE *f = fopen(savename,"rb");
409 if(f)
410 {
411 fclose(f);
412 command = 0;
413 warnError("ERROR: Save already backed up!\n");
414 }
415 }
416 else if(command == 3)
417 {
418 size_t readsize = 0;
419 FILE *f = fopen(savename,"rb");
420 if(f)
421 {
422 fseek(f,0,SEEK_END);
423 readsize = ftell(f);
424 if(readsize != savesize)
425 {
426 command = 0;
427 warnError("ERROR: Save has the wrong size, aborting restore!\n");
428 }
429 else
430 {
431 rewind(f);
432 fread(testdump,readsize,1,f);
433 }
434 fclose(f);
435 }
436 else
437 {
438 command = 0;
439 warnError("ERROR: No Save to restore!\n");
440 }
441 }
442 send(command);
443 //let gba prepare
444 sleep(1);
445 if(command == 0)
446 continue;
447 else if(command == 1)
448 {
449 //create base file with size
450 printf("Preparing file...\n");
451 createFile(gamename,gbasize);
452 FILE *f = fopen(gamename,"wb");
453 if(!f)
454 fatalError("ERROR: Could not create file! Exit...");
455 printf("Dumping...\n");
456 u32 bytes_read = 0;
457 while(gbasize > 0)
458 {
459 int toread = (gbasize > 0x400000 ? 0x400000 : gbasize);
460 int j;
461 for(j = 0; j < toread; j+=4)
462 {
463 *(vu32*)(testdump+j) = recv();
464 bytes_read+=4;
465 if((bytes_read&0xFFFF) == 0)
466 printf("\r%02.02f MB done",(float)(bytes_read/1024)/1024.f);
467 }
468 fwrite(testdump,toread,1,f);
469 gbasize -= toread;
470 }
471 printf("\nClosing file\n");
472 fclose(f);
473 printf("Game dumped!\n");
474 sleep(5);
475 }
476 else if(command == 2)
477 {
478 //create base file with size
479 printf("Preparing file...\n");
480 createFile(savename,savesize);
481 FILE *f = fopen(savename,"wb");
482 if(!f)
483 fatalError("ERROR: Could not create file! Exit...");
484 printf("Waiting for GBA\n");
485 VIDEO_WaitVSync();
486 u32 readval = 0;
487 while(readval != savesize)
488 readval = __builtin_bswap32(recv());
489 send(0); //got savesize
490 printf("Receiving...\n");
491 for(i = 0; i < savesize; i+=4)
492 *(vu32*)(testdump+i) = recv();
493 printf("Writing save...\n");
494 fwrite(testdump,savesize,1,f);
495 fclose(f);
496 printf("Save backed up!\n");
497 sleep(5);
498 }
499 else if(command == 3 || command == 4)
500 {
501 u32 readval = 0;
502 while(readval != savesize)
503 readval = __builtin_bswap32(recv());
504 if(command == 3)
505 {
506 printf("Sending save\n");
507 VIDEO_WaitVSync();
508 for(i = 0; i < savesize; i+=4)
509 send(__builtin_bswap32(*(vu32*)(testdump+i)));
510 }
511 printf("Waiting for GBA\n");
512 while(recv() != 0)
513 VIDEO_WaitVSync();
514 printf(command == 3 ? "Save restored!\n" : "Save cleared!\n");
515 send(0);
516 sleep(5);
517 }
518 }
519 }
520 else if(btns&PAD_BUTTON_Y)
521 {
522 const char *biosname = "/dumps/gba_bios.bin";
523 FILE *f = fopen(biosname,"rb");
524 if(f)
525 {
526 fclose(f);
527 warnError("ERROR: BIOS already backed up!\n");
528 }
529 else
530 {
531 //create base file with size
532 printf("Preparing file...\n");
533 createFile(biosname,0x4000);
534 f = fopen(biosname,"wb");
535 if(!f)
536 fatalError("ERROR: Could not create file! Exit...");
537 //send over bios dump command
538 send(5);
539 //the gba might still be in a loop itself
540 sleep(1);
541 //lets go!
542 printf("Dumping...\n");
543 for(i = 0; i < 0x4000; i+=4)
544 *(vu32*)(testdump+i) = recv();
545 fwrite(testdump,0x4000,1,f);
546 printf("Closing file\n");
547 fclose(f);
548 printf("BIOS dumped!\n");
549 sleep(5);
550 }
551 }
552 }
553 } 316 }
554 } 317 }
555 return 0; 318 return 0;