mirror of
https://github.com/ApacheThunder/GBA-Exploader.git
synced 2025-06-18 19:45:39 -04:00

* 3 in 1 Plus remaining issue with x button option to boot to nor flash game after having completed a norflash flash operation has now been resolved. :D * NorFlash menu appearing when hitting L after entering rumble selection menu on Omega/Omega DE has been resolved. NorFlash menu now fully disabled for Omega to avoid possible bricking of this cart. * Screen init process for GBA Frame loader optimized.
602 lines
22 KiB
C
602 lines
22 KiB
C
#include <nds.h>
|
|
#include "find.h"
|
|
#include "sc_patches.h"
|
|
|
|
#include "io_sc_common.h"
|
|
|
|
#define SAVE_TYPE_COUNT 25
|
|
|
|
u32 romSize;
|
|
|
|
// SRAM Patches
|
|
|
|
static const u8 flash1M_V102_find1[48] = {
|
|
0xaa,0x21,0x19,0x70,0x05,0x4a,0x55,0x21,0x11,0x70,0xb0,0x21,0x19,0x70,0xe0,0x21,
|
|
0x09,0x05,0x08,0x70,0x70,0x47,0x55,0x55,0x00,0x0e,0xaa,0x2a,0x00,0x0e,0x30,0xb5,
|
|
0x91,0xb0,0x68,0x46,0x00,0xf0,0xf3,0xf8,0x6d,0x46,0x01,0x35,0x06,0x4a,0xaa,0x20
|
|
};
|
|
static const u8 flash1M_V102_replace1[136] = {
|
|
0x80,0x21,0x09,0x02,0x09,0x22,0x12,0x06,0x9f,0x44,0x11,0x80,0x03,0x49,0xc3,0x02,
|
|
0xc9,0x18,0x11,0x80,0x70,0x47,0xfe,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x30,0xb5,
|
|
0x91,0xb0,0x68,0x46,0x00,0xf0,0xf3,0xf8,0x6d,0x46,0x01,0x35,0x06,0x4a,0xaa,0x20,
|
|
0x00,0x00,0x05,0x49,0x55,0x20,0x00,0x00,0x90,0x20,0x00,0x00,0x10,0xa9,0x03,0x4a,
|
|
0x10,0x1c,0x08,0xe0,0x00,0x00,0x55,0x55,0x00,0x0e,0xaa,0x2a,0x00,0x0e,0x20,0x4e,
|
|
0x00,0x00,0x08,0x88,0x01,0x38,0x08,0x80,0x08,0x88,0x00,0x28,0xf9,0xd1,0x0c,0x48,
|
|
0x13,0x20,0x13,0x20,0x00,0x06,0x04,0x0c,0xe0,0x20,0x00,0x05,0x62,0x20,0x62,0x20,
|
|
0x00,0x06,0x00,0x0e,0x04,0x43,0x07,0x49,0xaa,0x20,0x00,0x00,0x07,0x4a,0x55,0x20,
|
|
0x00,0x00,0xf0,0x20,0x00,0x00,0x00,0x00
|
|
};
|
|
static const u8 flash1M_V102_find2[24] = {
|
|
0x14,0x49,0xaa,0x24,0x0c,0x70,0x13,0x4b,0x55,0x22,0x1a,0x70,0x80,0x20,0x08,0x70,
|
|
0x0c,0x70,0x1a,0x70,0x10,0x20,0x08,0x70
|
|
};
|
|
static const u8 flash1M_V102_replace2[24] = {
|
|
0x0e,0x21,0x09,0x06,0xff,0x24,0x80,0x22,0x13,0x4b,0x52,0x02,0x01,0x3a,0x8c,0x54,
|
|
0xfc,0xd1,0x00,0x00,0x00,0x00,0x00,0x00
|
|
};
|
|
static const u8 flash1M_V102_find3[22] = {
|
|
0xaa,0x25,0x0d,0x70,0x13,0x4b,0x55,0x22,0x1a,0x70,0x80,0x20,0x08,0x70,0x0d,0x70,
|
|
0x1a,0x70,0x30,0x20,0x20,0x70
|
|
};
|
|
static const u8 flash1M_V102_replace3[22] = {
|
|
0xff,0x25,0x08,0x22,0x00,0x00,0x52,0x02,0x01,0x3a,0xa5,0x54,0xfc,0xd1,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00
|
|
};
|
|
static const u8 flash1M_V102_find4[12] = {
|
|
0x22,0x70,0x09,0x4b,0x55,0x22,0x1a,0x70,0xa0,0x22,0x22,0x70
|
|
};
|
|
static const u8 flash1M_V102_replace4[12] = {
|
|
0x00,0x00,0x09,0x4b,0x55,0x22,0x00,0x00,0xa0,0x22,0x00,0x00
|
|
};
|
|
|
|
|
|
static const u8 flash1M_V103_find1[98] = {
|
|
0x05,0x4b,0xaa,0x21,0x19,0x70,0x05,0x4a,0x55,0x21,0x11,0x70,0xb0,0x21,0x19,0x70,
|
|
0xe0,0x21,0x09,0x05,0x08,0x70,0x70,0x47,0x55,0x55,0x00,0x0e,0xaa,0x2a,0x00,0x0e,
|
|
0x30,0xb5,0x91,0xb0,0x68,0x46,0x00,0xf0,0xf3,0xf8,0x6d,0x46,0x01,0x35,0x06,0x4a,
|
|
0xaa,0x20,0x10,0x70,0x05,0x49,0x55,0x20,0x08,0x70,0x90,0x20,0x10,0x70,0x10,0xa9,
|
|
0x03,0x4a,0x10,0x1c,0x08,0xe0,0x00,0x00,0x55,0x55,0x00,0x0e,0xaa,0x2a,0x00,0x0e,
|
|
0x20,0x4e,0x00,0x00,0x08,0x88,0x01,0x38,0x08,0x80,0x08,0x88,0x00,0x28,0xf9,0xd1,
|
|
0x0c,0x48
|
|
};
|
|
static const u8 flash1M_V103_replace1[138] = {
|
|
0x05,0x4b,0x80,0x21,0x09,0x02,0x09,0x22,0x12,0x06,0x9f,0x44,0x11,0x80,0x03,0x49,
|
|
0xc3,0x02,0xc9,0x18,0x11,0x80,0x70,0x47,0xfe,0xff,0xff,0x01,0x00,0x00,0x00,0x00,
|
|
0x30,0xb5,0x91,0xb0,0x68,0x46,0x00,0xf0,0xf3,0xf8,0x6d,0x46,0x01,0x35,0x06,0x4a,
|
|
0xaa,0x20,0x00,0x00,0x05,0x49,0x55,0x20,0x00,0x00,0x90,0x20,0x00,0x00,0x10,0xa9,
|
|
0x03,0x4a,0x10,0x1c,0x08,0xe0,0x00,0x00,0x55,0x55,0x00,0x0e,0xaa,0x2a,0x00,0x0e,
|
|
0x20,0x4e,0x00,0x00,0x08,0x88,0x01,0x38,0x08,0x80,0x08,0x88,0x00,0x28,0xf9,0xd1,
|
|
0x0c,0x48,0x13,0x20,0x13,0x20,0x00,0x06,0x04,0x0c,0xe0,0x20,0x00,0x05,0x62,0x20,
|
|
0x62,0x20,0x00,0x06,0x00,0x0e,0x04,0x43,0x07,0x49,0xaa,0x20,0x00,0x00,0x07,0x4a,
|
|
0x55,0x20,0x00,0x00,0xf0,0x20,0x00,0x00,0x00,0x00
|
|
};
|
|
static const u8 flash1M_V103_find2[24] = {
|
|
0x14,0x49,0xaa,0x24,0x0c,0x70,0x13,0x4b,0x55,0x22,0x1a,0x70,0x80,0x20,0x08,0x70,
|
|
0x0c,0x70,0x1a,0x70,0x10,0x20,0x08,0x70
|
|
};
|
|
static const u8 flash1M_V103_replace2[24] = {
|
|
0x0e,0x21,0x09,0x06,0xff,0x24,0x80,0x22,0x13,0x4b,0x52,0x02,0x01,0x3a,0x8c,0x54,
|
|
0xfc,0xd1,0x00,0x00,0x00,0x00,0x00,0x00
|
|
};
|
|
static const u8 flash1M_V103_find3[22] = {
|
|
0xaa,0x25,0x0d,0x70,0x14,0x4b,0x55,0x22,0x1a,0x70,0x80,0x20,0x08,0x70,0x0d,0x70,
|
|
0x1a,0x70,0x30,0x20,0x20,0x70
|
|
};
|
|
static const u8 flash1M_V103_replace3[22] = {
|
|
0xff,0x25,0x08,0x22,0x00,0x00,0x52,0x02,0x01,0x3a,0xa5,0x54,0xfc,0xd1,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00
|
|
};
|
|
static const u8 flash1M_V103_find4[12] = {
|
|
0x10,0x70,0x0b,0x49,0x55,0x20,0x08,0x70,0xa0,0x20,0x10,0x70
|
|
};
|
|
static const u8 flash1M_V103_replace4[12] = {
|
|
0x00,0x00,0x0b,0x49,0x55,0x20,0x00,0x00,0xa0,0x20,0x00,0x00
|
|
};
|
|
static const u8 flash1M_V103_find5[12] = {
|
|
0x22,0x70,0x09,0x4b,0x55,0x22,0x1a,0x70,0xa0,0x22,0x22,0x70
|
|
};
|
|
static const u8 flash1M_V103_replace5[12] = {
|
|
0x00,0x00,0x09,0x4b,0x55,0x22,0x00,0x00,0xa0,0x22,0x00,0x00
|
|
};
|
|
|
|
|
|
// FLASH512_V130, V131, and V133 have all the same patches.
|
|
// Patches are from gbatemp thread, but gbata doesn't actually support V133.
|
|
static const u8 flash512_V13X_find1[38] = {
|
|
0xf0,0xb5,0xa0,0xb0,0x0d,0x1c,0x16,0x1c,0x1f,0x1c,0x03,0x04,0x1c,0x0c,0x0f,0x4a,
|
|
0x10,0x88,0x0f,0x49,0x08,0x40,0x03,0x21,0x08,0x43,0x10,0x80,0x0d,0x48,0x00,0x68,
|
|
0x01,0x68,0x80,0x20,0x80,0x02
|
|
};
|
|
static const u8 flash512_V13X_replace1[38] = {
|
|
0x70,0xb5,0xa0,0xb0,0x00,0x03,0x40,0x18,0xe0,0x21,0x09,0x05,0x09,0x18,0x08,0x78,
|
|
0x10,0x70,0x01,0x3b,0x01,0x32,0x01,0x31,0x00,0x2b,0xf8,0xd1,0x00,0x20,0x20,0xb0,
|
|
0x70,0xbc,0x02,0xbc,0x08,0x47
|
|
};
|
|
static const u8 flash512_V13X_find2[8] = {
|
|
0xff,0xf7,0x88,0xfd,0x00,0x04,0x03,0x0c
|
|
};
|
|
static const u8 flash512_V13X_replace2[8] = {
|
|
0x1b,0x23,0x1b,0x02,0x32,0x20,0x03,0x43
|
|
};
|
|
static const u8 flash512_V13X_find3[8] = {
|
|
0x70,0xb5,0x90,0xb0,0x15,0x4d,0x29,0x88
|
|
};
|
|
static const u8 flash512_V13X_find4[8] = {
|
|
0x70,0xb5,0x46,0x46,0x40,0xb4,0x90,0xb0
|
|
};
|
|
static const u8 flash512_V13X_replace3_4[8] = {
|
|
0x00,0xb5,0x00,0x20,0x02,0xbc,0x08,0x47
|
|
};
|
|
static const u8 flash512_V13X_find5[24] = {
|
|
0xf0,0xb5,0x90,0xb0,0x0f,0x1c,0x00,0x04,0x04,0x0c,0x03,0x48,0x00,0x68,0x40,0x89,
|
|
0x84,0x42,0x05,0xd3,0x01,0x48,0x41,0xe0
|
|
};
|
|
static const u8 flash512_V13X_replace5[42] = {
|
|
0x7c,0xb5,0x90,0xb0,0x00,0x03,0x0a,0x1c,0xe0,0x21,0x09,0x05,0x09,0x18,0x01,0x23,
|
|
0x1b,0x03,0x10,0x78,0x08,0x70,0x01,0x3b,0x01,0x32,0x01,0x31,0x00,0x2b,0xf8,0xd1,
|
|
0x00,0x20,0x10,0xb0,0x7c,0xbc,0x02,0xbc,0x08,0x47
|
|
};
|
|
|
|
|
|
// Encompasses FLASH_V120 and V121.
|
|
static const u8 flash_V12X_find1[12] = {
|
|
0x90,0xb5,0x93,0xb0,0x6f,0x46,0x39,0x1d,0x08,0x1c,0x00,0xf0
|
|
};
|
|
static const u8 flash_V12X_replace1[14] = {
|
|
0x00,0xb5,0x3d,0x20,0x00,0x02,0x1f,0x21,0x08,0x43,0x02,0xbc,0x08,0x47
|
|
};
|
|
static const u8 flash_V12X_find2[35] = {
|
|
0x80,0xb5,0x94,0xb0,0x6f,0x46,0x39,0x1c,0x08,0x80,0x38,0x1c,0x01,0x88,0x0f,0x29,
|
|
0x04,0xd9,0x01,0x48,0x56,0xe0,0x00,0x00,0xff,0x80,0x00,0x00,0x23,0x48,0x23,0x49,
|
|
0x0a,0x88,0x23
|
|
};
|
|
static const u8 flash_V12X_replace2[36] = {
|
|
0x7c,0xb5,0x00,0x07,0x00,0x0c,0xe0,0x21,0x09,0x05,0x09,0x18,0x01,0x23,0x1b,0x03,
|
|
0xff,0x20,0x08,0x70,0x01,0x3b,0x01,0x31,0x00,0x2b,0xfa,0xd1,0x00,0x20,0x7c,0xbc,
|
|
0x02,0xbc,0x08,0x47
|
|
};
|
|
static const u8 flash_V12X_find3[42] = {
|
|
0x80,0xb5,0x94,0xb0,0x6f,0x46,0x79,0x60,0x39,0x1c,0x08,0x80,0x38,0x1c,0x01,0x88,
|
|
0x0f,0x29,0x03,0xd9,0x00,0x48,0x73,0xe0,0xff,0x80,0x00,0x00,0x38,0x1c,0x01,0x88,
|
|
0x08,0x1c,0xff,0xf7,0x21,0xfe,0x39,0x1c,0x0c,0x31
|
|
};
|
|
static const u8 flash_V12X_replace3[42] = {
|
|
0x7c,0xb5,0x90,0xb0,0x00,0x03,0x0a,0x1c,0xe0,0x21,0x09,0x05,0x09,0x18,0x01,0x23,
|
|
0x1b,0x03,0x10,0x78,0x08,0x70,0x01,0x3b,0x01,0x32,0x01,0x31,0x00,0x2b,0xf8,0xd1,
|
|
0x00,0x20,0x10,0xb0,0x7c,0xbc,0x08,0xbc,0x08,0x47
|
|
};
|
|
|
|
// Encompasses FLASH_V123, V124, V125, and V126.
|
|
// FIXME for FLASH_V125 and FLASH_V126: Medabots/Metarot and Super Monkey Ball Jr. (U) don't patch 1:1 with gbata.
|
|
static const u8 flash_V12Y_find1[8] = {
|
|
0xff,0xf7,0xaa,0xff,0x00,0x04,0x03,0x0c
|
|
};
|
|
static const u8 flash_V12Y_replace1[8] = {
|
|
0x1b,0x23,0x1b,0x02,0x32,0x20,0x03,0x43
|
|
};
|
|
static const u8 flash_V12Y_find2[6] = {
|
|
0x70,0xb5,0x90,0xb0,0x15,0x4d
|
|
};
|
|
static const u8 flash_V12Y_replace2[4] = {
|
|
0x00,0x20,0x70,0x47/*,0x15,0x4d*/
|
|
};
|
|
// Patch 3 differs from GBATemp tutorial.
|
|
// The added bytes at the end have significance.
|
|
static const u8 flash_V12Y_find3[9] = {
|
|
0x70,0xb5,0x46,0x46,0x40,0xb4,0x90,0xb0,0x00
|
|
};
|
|
static const u8 flash_V12Y_replace3[4] = {
|
|
0x00,0x20,0x70,0x47/*,0x40,0xb4,0x90,0xb0,0x00*/
|
|
};
|
|
static const u8 flash_V12Y_find4[38] = {
|
|
0xf0,0xb5,0x90,0xb0,0x0f,0x1c,0x00,0x04,0x04,0x0c,0x0f,0x2c,0x04,0xd9,0x01,0x48,
|
|
0x40,0xe0,0x00,0x00,0xff,0x80,0x00,0x00,0x20,0x1c,0xff,0xf7,0xd7,0xfe,0x00,0x04,
|
|
0x05,0x0c,0x00,0x2d,0x35,0xd1
|
|
};
|
|
static const u8 flash_V12Y_replace4[38] = {
|
|
0x70,0xb5,0x00,0x03,0x0a,0x1c,0xe0,0x21,0x09,0x05,0x41,0x18,0x01,0x23,0x1b,0x03,
|
|
0x10,0x78,0x08,0x70,0x01,0x3b,0x01,0x32,0x01,0x31,0x00,0x2b,0xf8,0xd1,0x00,0x20,
|
|
0x70,0xbc,0x02,0xbc,0x08,0x47
|
|
};
|
|
|
|
|
|
bool flash_patchV120(const struct save_type* type) {
|
|
u8* func1 = memsearch8((u8*)0x08000000, romSize, flash_V12X_find1, sizeof(flash_V12X_find1), true);
|
|
if (!func1)
|
|
return false;
|
|
twoByteCpy((u16*)func1, (const u16*)flash_V12X_replace1, sizeof(flash_V12X_replace1));
|
|
|
|
u8* func2 = memsearch8((u8*)0x08000000, romSize, flash_V12X_find2, sizeof(flash_V12X_find2), true);
|
|
if (!func2)
|
|
return false;
|
|
twoByteCpy((u16*)func2, (const u16*)flash_V12X_replace2, sizeof(flash_V12X_replace2));
|
|
|
|
u8* func3 = memsearch8((u8*)0x08000000, romSize, flash_V12X_find3, sizeof(flash_V12X_find3), true);
|
|
if (!func3)
|
|
return false;
|
|
twoByteCpy((u16*)func3, (const u16*)flash_V12X_replace3, sizeof(flash_V12X_replace3));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool flash_patchV123(const struct save_type* type) {
|
|
u8* func1 = memsearch8((u8*)0x08000000, romSize, flash_V12Y_find1, sizeof(flash_V12Y_find1), true);
|
|
if (!func1)
|
|
return false;
|
|
twoByteCpy((u16*)func1, (const u16*)flash_V12Y_replace1, sizeof(flash_V12Y_replace1));
|
|
|
|
u8* func2 = memsearch8((u8*)0x08000000, romSize, flash_V12Y_find2, sizeof(flash_V12Y_find2), true);
|
|
if (!func2)
|
|
return false;
|
|
twoByteCpy((u16*)func2, (const u16*)flash_V12Y_replace2, sizeof(flash_V12Y_replace2));
|
|
|
|
u8* func3 = memsearch8((u8*)0x08000000, romSize, flash_V12Y_find3, sizeof(flash_V12Y_find3), true);
|
|
if (!func3)
|
|
return false;
|
|
twoByteCpy((u16*)func3, (const u16*)flash_V12Y_replace3, sizeof(flash_V12Y_replace3));
|
|
|
|
u8* func4 = memsearch8((u8*)0x08000000, romSize, flash_V12Y_find4, sizeof(flash_V12Y_find4), true);
|
|
if (!func4)
|
|
return false;
|
|
twoByteCpy((u16*)func4, (const u16*)flash_V12Y_replace4, sizeof(flash_V12Y_replace4));
|
|
|
|
return true;
|
|
}
|
|
|
|
/*bool flash_patchV126(const struct save_type* type)
|
|
{
|
|
}*/
|
|
|
|
bool flash_patch512V130(const struct save_type* type) {
|
|
u32* romPos = (u32*)0x08000000;
|
|
u32 curRomSize = romSize;
|
|
u32 startSig[4] = {0};
|
|
startSig[0] = *(u32*)0x08000000;
|
|
startSig[1] = *(u32*)0x08000004;
|
|
startSig[2] = *(u32*)0x08000008;
|
|
startSig[3] = *(u32*)0x0800000C;
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
if (i != 0) {
|
|
while (romPos < romPos+romSize) {
|
|
// Look for another ROM in 2 in 1 game packs
|
|
romPos += 0x100000;
|
|
curRomSize -= 0x100000;
|
|
if (curRomSize <= 0) break;
|
|
if (romPos[0] == startSig[0]
|
|
&& romPos[1] == startSig[1]
|
|
&& romPos[2] == startSig[2]
|
|
&& romPos[3] == startSig[3]) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (romPos >= romPos+romSize) break;
|
|
}
|
|
|
|
u8* func1 = memsearch8((u8*)romPos, curRomSize, flash512_V13X_find1, sizeof(flash512_V13X_find1), true);
|
|
if (!func1)
|
|
return false;
|
|
twoByteCpy((u16*)func1, (const u16*)flash512_V13X_replace1, sizeof(flash512_V13X_replace1));
|
|
|
|
u8* func2 = memsearch8((u8*)romPos, curRomSize, flash512_V13X_find2, sizeof(flash512_V13X_find2), true);
|
|
if (!func2)
|
|
return false;
|
|
twoByteCpy((u16*)func2, (const u16*)flash512_V13X_replace2, sizeof(flash512_V13X_replace2));
|
|
|
|
u8* func3 = memsearch8((u8*)romPos, curRomSize, flash512_V13X_find3, sizeof(flash512_V13X_find3), true);
|
|
if (!func3)
|
|
return false;
|
|
twoByteCpy((u16*)func3, (const u16*)flash512_V13X_replace3_4, sizeof(flash512_V13X_replace3_4));
|
|
|
|
u8* func4 = memsearch8((u8*)romPos, curRomSize, flash512_V13X_find4, sizeof(flash512_V13X_find4), true);
|
|
if (!func4)
|
|
return false;
|
|
twoByteCpy((u16*)func4, (const u16*)flash512_V13X_replace3_4, sizeof(flash512_V13X_replace3_4));
|
|
|
|
u8* func5 = memsearch8((u8*)romPos, curRomSize, flash512_V13X_find5, sizeof(flash512_V13X_find5), true);
|
|
if (!func5)
|
|
return false;
|
|
twoByteCpy((u16*)func5, (const u16*)flash512_V13X_replace5, sizeof(flash512_V13X_replace5));
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool flash_patch1MV102(const struct save_type* type) {
|
|
u8* func1 = memsearch8((u8*)0x08000000, romSize, flash1M_V102_find1, sizeof(flash1M_V102_find1), true);
|
|
if (!func1)
|
|
return false;
|
|
twoByteCpy((u16*)func1, (const u16*)flash1M_V102_replace1, sizeof(flash1M_V102_replace1));
|
|
|
|
u8* func2 = memsearch8((u8*)0x08000000, romSize, flash1M_V102_find2, sizeof(flash1M_V102_find2), true);
|
|
if (!func2)
|
|
return false;
|
|
twoByteCpy((u16*)func2, (const u16*)flash1M_V102_replace2, sizeof(flash1M_V102_replace2));
|
|
|
|
u8* func3 = memsearch8((u8*)0x08000000, romSize, flash1M_V102_find3, sizeof(flash1M_V102_find3), true);
|
|
if (!func3)
|
|
return false;
|
|
twoByteCpy((u16*)func3, (const u16*)flash1M_V102_replace3, sizeof(flash1M_V102_replace3));
|
|
|
|
u8* func4 = memsearch8((u8*)0x08000000, romSize, flash1M_V102_find4, sizeof(flash1M_V102_find4), true);
|
|
if (!func4)
|
|
return false;
|
|
twoByteCpy((u16*)func4, (const u16*)flash1M_V102_replace4, sizeof(flash1M_V102_replace4));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool flash_patch1MV103(const struct save_type* type) {
|
|
u8* func1 = memsearch8((u8*)0x08000000, romSize, flash1M_V103_find1, sizeof(flash1M_V103_find1), true);
|
|
if (!func1)
|
|
return false;
|
|
twoByteCpy((u16*)func1, (const u16*)flash1M_V103_replace1, sizeof(flash1M_V103_replace1));
|
|
|
|
u8* func2 = memsearch8((u8*)0x08000000, romSize, flash1M_V103_find2, sizeof(flash1M_V103_find2), true);
|
|
if (!func2)
|
|
return false;
|
|
twoByteCpy((u16*)func2, (const u16*)flash1M_V103_replace2, sizeof(flash1M_V103_replace2));
|
|
|
|
u8* func3 = memsearch8((u8*)0x08000000, romSize, flash1M_V103_find3, sizeof(flash1M_V103_find3), true);
|
|
if (!func3)
|
|
return false;
|
|
twoByteCpy((u16*)func3, (const u16*)flash1M_V103_replace3, sizeof(flash1M_V103_replace3));
|
|
|
|
u8* func4 = memsearch8((u8*)0x08000000, romSize, flash1M_V103_find4, sizeof(flash1M_V103_find4), true);
|
|
if (!func4)
|
|
return false;
|
|
twoByteCpy((u16*)func4, (const u16*)flash1M_V103_replace4, sizeof(flash1M_V103_replace4));
|
|
|
|
u8* func5 = memsearch8((u8*)0x08000000, romSize, flash1M_V103_find5, sizeof(flash1M_V103_find5), true);
|
|
if (!func5)
|
|
return false;
|
|
twoByteCpy((u16*)func5, (const u16*)flash1M_V103_replace5, sizeof(flash1M_V103_replace5));
|
|
|
|
return true;
|
|
}
|
|
|
|
//todo: Moero!! Jaleco Collection (Japan) reports EEPROM_V124, but the signatures below don't work!
|
|
|
|
static const u8 sReadEepromDwordV111Sig[0x10] = { 0xB0, 0xB5, 0xAA, 0xB0, 0x6F, 0x46, 0x79, 0x60, 0x39, 0x1C, 0x08, 0x80, 0x38, 0x1C, 0x01, 0x88 };
|
|
|
|
static const u8 sReadEepromDwordV120Sig[0x10] = { 0x70, 0xB5, 0xA2, 0xB0, 0x0D, 0x1C, 0x00, 0x04, 0x03, 0x0C, 0x03, 0x48, 0x00, 0x68, 0x80, 0x88 };
|
|
|
|
static const u8 sProgramEepromDwordV111Sig[0x10] = { 0x80, 0xB5, 0xAA, 0xB0, 0x6F, 0x46, 0x79, 0x60, 0x39, 0x1C, 0x08, 0x80, 0x38, 0x1C, 0x01, 0x88 };
|
|
|
|
//changed in EEPROM_V124
|
|
static const u8 sProgramEepromDwordV120Sig[0x10] = { 0x30, 0xB5, 0xA9, 0xB0, 0x0D, 0x1C, 0x00, 0x04, 0x04, 0x0C, 0x03, 0x48, 0x00, 0x68, 0x80, 0x88 };
|
|
|
|
//changed in EEPROM_V126
|
|
static const u8 sProgramEepromDwordV124Sig[0x10] = { 0xF0, 0xB5, 0xAC, 0xB0, 0x0D, 0x1C, 0x00, 0x04, 0x01, 0x0C, 0x12, 0x06, 0x17, 0x0E, 0x03, 0x48 };
|
|
|
|
static const u8 sProgramEepromDwordV126Sig[0x10] = { 0xF0, 0xB5, 0x47, 0x46, 0x80, 0xB4, 0xAC, 0xB0, 0x0E, 0x1C, 0x00, 0x04, 0x05, 0x0C, 0x12, 0x06 };
|
|
|
|
//not in EEPROM_V111
|
|
//could be used to identify the eeprom size, but not strictly needed
|
|
/*static u16 identifyEeprom(u16 kbitSize)
|
|
{
|
|
return 0;
|
|
}*/
|
|
|
|
const u8 patch_eeprom_1[] = {
|
|
0x00,0x04, // LSL R0, R0, #0x10
|
|
0x0a,0x1c, // ADD R2, R1, #0
|
|
0x40,0x0b, // LSR R0, R0, #0xD
|
|
0xe0,0x21,0x09,0x05, // MOVL R1, 0xE000000
|
|
0x41,0x18, // ADD R1, R0, R1
|
|
0x07,0x31, // ADD R1, #7
|
|
0x00,0x23, // MOV R3, #0
|
|
//l1:
|
|
0x08,0x78, // LDRB R0, [R1]
|
|
0x10,0x70, // STRB R0, [R2]
|
|
0x01,0x33, // ADD R3, #1
|
|
0x01,0x32, // ADD R2, #1
|
|
0x01,0x39, // SUB R1, #1
|
|
0x07,0x2b, // CMP R3, #7
|
|
0xf8,0xd9, // BLS l1
|
|
0x00,0x20, // MOV R0, #0
|
|
0x70,0x47 // BX LR
|
|
};
|
|
|
|
const u8 patch_eeprom_2[] = {
|
|
0x00,0x04, // LSL R0, R0, #0x10
|
|
0x0a,0x1c, // ADD R2, R1, #0
|
|
0x40,0x0b, // LSR R0, R0, #0xD
|
|
0xe0,0x21,0x09,0x05, // MOVL R1, 0xE000000
|
|
0x41,0x18, // ADD R1, R0, R1
|
|
0x07,0x31, // ADD R1, #7
|
|
0x00,0x23, // MOV R3, #0
|
|
//l1:
|
|
0x10,0x78, // LDRB R0, [R2]
|
|
0x08,0x70, // STRB R0, [R1]
|
|
0x01,0x33, // ADD R3, #1
|
|
0x01,0x32, // ADD R2, #1
|
|
0x01,0x39, // SUB R1, #1
|
|
0x07,0x2b, // CMP R3, #7
|
|
0xf8,0xd9, // BLS l1
|
|
0x00,0x20, // MOV R0, #0
|
|
0x70,0x47 // BX LR
|
|
};
|
|
|
|
bool eeprom_patchV111(const struct save_type* type) {
|
|
u8* readFunc = memsearch8((u8*)0x08000000, romSize, sReadEepromDwordV111Sig, 0x10, true);
|
|
if (!readFunc)
|
|
return false;
|
|
twoByteCpy((u16*)readFunc, (const u16*)patch_eeprom_1, sizeof(patch_eeprom_1));
|
|
|
|
u8* progFunc = memsearch8((u8*)0x08000000, romSize, sProgramEepromDwordV111Sig, 0x10, true);
|
|
if (!progFunc)
|
|
return false;
|
|
twoByteCpy((u16*)progFunc, (const u16*)patch_eeprom_2, sizeof(patch_eeprom_2));
|
|
return true;
|
|
}
|
|
|
|
bool eeprom_patchV120(const struct save_type* type) {
|
|
u32* romPos = (u32*)0x08000000;
|
|
u32 curRomSize = romSize;
|
|
u32 startSig[4] = {0};
|
|
startSig[0] = *(u32*)0x08000000;
|
|
startSig[1] = *(u32*)0x08000004;
|
|
startSig[2] = *(u32*)0x08000008;
|
|
startSig[3] = *(u32*)0x0800000C;
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
if (i != 0) {
|
|
while (romPos < romPos+romSize) {
|
|
// Look for another ROM in 2-3 in 1 game packs
|
|
romPos += 0x100000;
|
|
curRomSize -= 0x100000;
|
|
if (curRomSize <= 0) break;
|
|
if (romPos[0] == startSig[0]
|
|
&& romPos[1] == startSig[1]
|
|
&& romPos[2] == startSig[2]
|
|
&& romPos[3] == startSig[3]) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (romPos >= romPos+romSize) break;
|
|
}
|
|
|
|
u8* readFunc = memsearch8((u8*)romPos, curRomSize, sReadEepromDwordV120Sig, 0x10, true);
|
|
if (!readFunc)
|
|
return false;
|
|
twoByteCpy((u16*)readFunc, (const u16*)patch_eeprom_1, sizeof(patch_eeprom_1));
|
|
|
|
u8* progFunc = memsearch8((u8*)romPos, curRomSize, sProgramEepromDwordV120Sig, 0x10, true);
|
|
if (!progFunc)
|
|
return false;
|
|
twoByteCpy((u16*)progFunc, (const u16*)patch_eeprom_2, sizeof(patch_eeprom_2));
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool eeprom_patchV124(const struct save_type* type) {
|
|
u32* romPos = (u32*)0x08000000;
|
|
u32 curRomSize = romSize;
|
|
u32 startSig[4] = {0};
|
|
startSig[0] = *(u32*)0x08000000;
|
|
startSig[1] = *(u32*)0x08000004;
|
|
startSig[2] = *(u32*)0x08000008;
|
|
startSig[3] = *(u32*)0x0800000C;
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
if (i != 0) {
|
|
while (romPos < romPos+romSize) {
|
|
// Look for another ROM in 2 in 1 game packs
|
|
romPos += 0x100000;
|
|
curRomSize -= 0x100000;
|
|
if (curRomSize <= 0) break;
|
|
if (romPos[0] == startSig[0]
|
|
&& romPos[1] == startSig[1]
|
|
&& romPos[2] == startSig[2]
|
|
&& romPos[3] == startSig[3]) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (romPos >= romPos+romSize) break;
|
|
}
|
|
|
|
u8* readFunc = memsearch8((u8*)romPos, curRomSize, sReadEepromDwordV120Sig, 0x10, true);
|
|
if (!readFunc)
|
|
return false;
|
|
twoByteCpy((u16*)readFunc, (const u16*)patch_eeprom_1, sizeof(patch_eeprom_1));
|
|
|
|
u8* progFunc = memsearch8((u8*)romPos, curRomSize, sProgramEepromDwordV124Sig, 0x10, true);
|
|
if (!progFunc)
|
|
return false;
|
|
twoByteCpy((u16*)progFunc, (const u16*)patch_eeprom_2, sizeof(patch_eeprom_2));
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool eeprom_patchV126(const struct save_type* type) {
|
|
u8* readFunc = memsearch8((u8*)0x08000000, romSize, sReadEepromDwordV120Sig, 0x10, true);
|
|
if (!readFunc)
|
|
return false;
|
|
twoByteCpy((u16*)readFunc, (const u16*)patch_eeprom_1, sizeof(patch_eeprom_1));
|
|
|
|
u8* progFunc = memsearch8((u8*)0x08000000, romSize, sProgramEepromDwordV126Sig, 0x10, true);
|
|
if (!progFunc)
|
|
return false;
|
|
twoByteCpy((u16*)progFunc, (const u16*)patch_eeprom_2, sizeof(patch_eeprom_2));
|
|
return true;
|
|
}
|
|
|
|
|
|
static const struct save_type sSaveTypes[SAVE_TYPE_COUNT] = {
|
|
{"EEPROM_V111", 12, SAVE_TYPE_EEPROM_V111, 512, eeprom_patchV111},
|
|
{"EEPROM_V120", 12, SAVE_TYPE_EEPROM_V120, 8 * 1024, eeprom_patchV120},
|
|
{"EEPROM_V121", 12, SAVE_TYPE_EEPROM_V121, 8 * 1024, eeprom_patchV120},
|
|
{"EEPROM_V122", 12, SAVE_TYPE_EEPROM_V122, 8 * 1024, eeprom_patchV120},
|
|
{"EEPROM_V124", 12, SAVE_TYPE_EEPROM_V124, 8 * 1024, eeprom_patchV124},
|
|
{"EEPROM_V125", 12, SAVE_TYPE_EEPROM_V125, 8 * 1024, eeprom_patchV124},
|
|
{"EEPROM_V126", 12, SAVE_TYPE_EEPROM_V126, 8 * 1024, eeprom_patchV126},
|
|
|
|
{"FLASH_V120", 11, SAVE_TYPE_FLASH_V120, 64 * 1024, flash_patchV120},
|
|
{"FLASH_V121", 11, SAVE_TYPE_FLASH_V121, 64 * 1024, flash_patchV120},
|
|
{"FLASH_V123", 11, SAVE_TYPE_FLASH_V123, 64 * 1024, flash_patchV123},
|
|
{"FLASH_V124", 11, SAVE_TYPE_FLASH_V124, 64 * 1024, flash_patchV123},
|
|
{"FLASH_V125", 11, SAVE_TYPE_FLASH_V125, 64 * 1024, flash_patchV123},
|
|
{"FLASH_V126", 11, SAVE_TYPE_FLASH_V126, 64 * 1024, /*flash_patchV126*/ flash_patchV123},
|
|
{"FLASH512_V130", 14, SAVE_TYPE_FLASH512_V130, 64 * 1024, flash_patch512V130},
|
|
{"FLASH512_V131", 14, SAVE_TYPE_FLASH512_V131, 64 * 1024, flash_patch512V130},
|
|
{"FLASH512_V133", 14, SAVE_TYPE_FLASH512_V133, 64 * 1024, flash_patch512V130},
|
|
{"FLASH1M_V102", 13, SAVE_TYPE_FLASH1M_V102, 128 * 1024, flash_patch1MV102},
|
|
{"FLASH1M_V103", 13, SAVE_TYPE_FLASH1M_V103, 128 * 1024, flash_patch1MV103},
|
|
|
|
//sram does not require patching
|
|
{"SRAM_F_V100", 12, SAVE_TYPE_SRAM_F_V100, 32 * 1024, NULL},
|
|
{"SRAM_F_V102", 12, SAVE_TYPE_SRAM_F_V102, 32 * 1024, NULL},
|
|
{"SRAM_F_V103", 12, SAVE_TYPE_SRAM_F_V103, 32 * 1024, NULL},
|
|
|
|
{"SRAM_V110", 10, SAVE_TYPE_SRAM_V110, 32 * 1024, NULL},
|
|
{"SRAM_V111", 10, SAVE_TYPE_SRAM_V111, 32 * 1024, NULL},
|
|
{"SRAM_V112", 10, SAVE_TYPE_SRAM_V112, 32 * 1024, NULL},
|
|
{"SRAM_V113", 10, SAVE_TYPE_SRAM_V113, 32 * 1024, NULL},
|
|
};
|
|
|
|
const struct save_type* save_findTag() {
|
|
u32 curAddr = 0x080000C0;
|
|
char saveTag[16];
|
|
while (curAddr < 0x08000000+romSize) {
|
|
u32 fst = *(u32*)curAddr;
|
|
// tonccpy(&saveTag, (u8*)curAddr, 16);
|
|
((u32*)saveTag)[0] = ((u32*)curAddr)[0];
|
|
((u32*)saveTag)[1] = ((u32*)curAddr)[1];
|
|
((u32*)saveTag)[2] = ((u32*)curAddr)[2];
|
|
((u32*)saveTag)[3] = ((u32*)curAddr)[3];
|
|
enum SaveType type = SAVE_TYPE_NONE;
|
|
if (fst == 0x53414C46 && (saveTag[5] == '_' || saveTag[5] == '5' || saveTag[5] == '1')) {
|
|
//FLAS
|
|
type = SAVE_TYPE_FLASH;
|
|
} else if (fst == 0x4D415253) {
|
|
//SRAM
|
|
type = SAVE_TYPE_SRAM;
|
|
} else if (fst == 0x52504545 && saveTag[6] == '_') {
|
|
//EEPR
|
|
type = SAVE_TYPE_EEPROM;
|
|
}
|
|
|
|
if (type != SAVE_TYPE_NONE) {
|
|
for (int i = 0; i < SAVE_TYPE_COUNT; i++) {
|
|
if (strncmp(saveTag, sSaveTypes[i].tag, sSaveTypes[i].tagLength) != 0)continue;
|
|
return &sSaveTypes[i];
|
|
}
|
|
}
|
|
curAddr += 4;
|
|
}
|
|
return NULL;
|
|
}
|
|
|