mirror of
https://github.com/coderkei/akmenu-next.git
synced 2025-06-19 17:35:38 -04:00
1614 lines
70 KiB
C++
1614 lines
70 KiB
C++
/*
|
|
gbapatcher.cpp
|
|
Copyright (C) 2008-2009 somebody
|
|
Copyright (C) 2009 yellow wood goblin
|
|
|
|
SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
|
|
#include "gbapatcher.h"
|
|
#include <stdarg.h>
|
|
#ifdef __TEST
|
|
#include <stdio.h>
|
|
#else
|
|
#include "globalsettings.h"
|
|
#endif
|
|
|
|
#define sizeofa(array) (sizeof(array) / sizeof(array[0]))
|
|
|
|
#define CHECK_SIZES(n, c, s) \
|
|
struct __check_##n##_sizeof { \
|
|
char c1[c - s]; \
|
|
char c2[s - c]; \
|
|
char e; \
|
|
} // tnx to yjh
|
|
#define CHECK_SIZEOF(n, s) CHECK_SIZES(n, sizeof(n), s)
|
|
|
|
CGbaWriter::~CGbaWriter() {}
|
|
|
|
CGbaPatcher::CGbaPatcher(u32 aSize, CGbaWriter* aWriter, u32* aData, u8 aRamPage)
|
|
: iCount(0),
|
|
iCount2(0),
|
|
iCount3(0),
|
|
iCount4(0),
|
|
iSize(aSize),
|
|
iData(aData),
|
|
iTrimSize(aSize),
|
|
iResultSize(aSize),
|
|
iSaveSize(128 * 1024),
|
|
iWriter(aWriter),
|
|
iRamPage(aRamPage) {
|
|
/*
|
|
#ifdef __TEST
|
|
iData=(u32*)globalBuffer;
|
|
#else
|
|
iData=(u32*)0x08060000;
|
|
#endif
|
|
*/
|
|
}
|
|
|
|
#ifdef __TEST
|
|
void CGbaPatcher::DumpPatchInfo(void) {
|
|
for (u32 ii = 0; ii < iCount; ii++) {
|
|
switch (iPatchInfo[ii].iType) {
|
|
case ESRAMLabel:
|
|
printf("ESRAMLabel");
|
|
break;
|
|
case EEEPROMLabel:
|
|
printf("EEEPROMLabel");
|
|
break;
|
|
case EEEPROMRead:
|
|
printf("EEEPROMRead");
|
|
break;
|
|
case EEEPROMWrite:
|
|
printf("EEEPROMWrite");
|
|
break;
|
|
case EEEPROMWrite124:
|
|
printf("EEEPROMWrite124");
|
|
break;
|
|
case EEEPROMWrite126:
|
|
printf("EEEPROMWrite126");
|
|
break;
|
|
case EFLASH1M10XLabel:
|
|
printf("EFLASH1M10XLabel");
|
|
break;
|
|
case EFLASH1M102_1:
|
|
printf("EFLASH1M102_1");
|
|
break;
|
|
case EFLASH1M102_2:
|
|
printf("EFLASH1M102_2");
|
|
break;
|
|
case EFLASH1M102_3:
|
|
printf("EFLASH1M102_3");
|
|
break;
|
|
case EFLASH1M102_4:
|
|
printf("EFLASH1M102_4");
|
|
break;
|
|
case EFLASH1M102_5:
|
|
printf("EFLASH1M102_5");
|
|
break;
|
|
case EFLASH1M103_1:
|
|
printf("EFLASH1M103_1");
|
|
break;
|
|
case EFLASH1M103_2:
|
|
printf("EFLASH1M103_2");
|
|
break;
|
|
case EFLASH1M103_3:
|
|
printf("EFLASH1M103_3");
|
|
break;
|
|
case EFLASH1M103_4:
|
|
printf("EFLASH1M103_4");
|
|
break;
|
|
case EFLASHLabel:
|
|
printf("EFLASHLabel");
|
|
break;
|
|
case EFLASH_1:
|
|
printf("EFLASH_1");
|
|
break;
|
|
case EFLASH_2:
|
|
printf("EFLASH_2");
|
|
break;
|
|
case EFLASH_3:
|
|
printf("EFLASH_3");
|
|
break;
|
|
case EFLASH_4:
|
|
printf("EFLASH_4");
|
|
break;
|
|
case EFLASHV123_1:
|
|
printf("EFLASHV123_1");
|
|
break;
|
|
case EFLASHV123_2:
|
|
printf("EFLASHV123_2");
|
|
break;
|
|
case EFLASHV123_3:
|
|
printf("EFLASHV123_3");
|
|
break;
|
|
case EFLASHV123_4:
|
|
printf("EFLASHV123_4");
|
|
break;
|
|
case EFLASHV123_5:
|
|
printf("EFLASHV123_5");
|
|
break;
|
|
case EFLASH512Label:
|
|
printf("EFLASH512Label");
|
|
break;
|
|
case EFLASH512_1:
|
|
printf("EFLASH512_1");
|
|
break;
|
|
case EFLASH512_2:
|
|
printf("EFLASH512_2");
|
|
break;
|
|
default:
|
|
printf("Unknown_%d", iPatchInfo[ii].iType);
|
|
break;
|
|
}
|
|
printf(": 0x%x\n", iPatchInfo[ii].iOffset * 4);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
inline int test_printf(const char* format, ...) {
|
|
#ifdef __TEST
|
|
va_list args;
|
|
va_start(args, format);
|
|
int ret = vprintf(format, args);
|
|
va_end(args);
|
|
return ret;
|
|
#else
|
|
return 0;
|
|
#endif //__TEST
|
|
}
|
|
|
|
void CGbaPatcher::Add(u32 anOffset, TPatchType aType) {
|
|
if (iCount < EMax) {
|
|
SPatchInfo info = {anOffset, aType};
|
|
iPatchInfo[iCount++] = info;
|
|
}
|
|
}
|
|
|
|
void CGbaPatcher::Add2(u32 anOffset, u32 aValue) {
|
|
if (iCount2 < (EMax * 2)) {
|
|
SPatchInfo2 info = {anOffset, aValue};
|
|
iPatchInfo2[iCount2++] = info;
|
|
}
|
|
}
|
|
|
|
void CGbaPatcher::Add3(u32 aLocation, u32 anAddress, u32 aRa, u32 aRb) {
|
|
if (iCount3 < EMax) {
|
|
SPatchInfo3 info = {aLocation, anAddress, aRa, aRb};
|
|
iPatchInfo3[iCount3++] = info;
|
|
}
|
|
}
|
|
|
|
void CGbaPatcher::Add4(u32 anOffset, u16 aValue) {
|
|
if (iCount4 < EMax) {
|
|
SPatchInfo4 info = {anOffset, aValue};
|
|
iPatchInfo4[iCount4++] = info;
|
|
}
|
|
}
|
|
|
|
u32 CGbaPatcher::Patch(void) {
|
|
switch (setjmp(iJumpBuf)) {
|
|
case 0:
|
|
PatchInternal();
|
|
break;
|
|
case 1:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return iSaveSize;
|
|
}
|
|
|
|
void CGbaPatcher::Error(const char* anError) {
|
|
#ifdef __TEST
|
|
printf("error: %s\n", anError);
|
|
#else
|
|
#endif
|
|
longjmp(iJumpBuf, 1);
|
|
}
|
|
|
|
void CGbaPatcher::PatchInternal(void) {
|
|
u32 search_size = iSize / 4;
|
|
for (u32 ii = 0; ii < search_size; ii++) {
|
|
switch (Data()[ii]) {
|
|
case 0x4d415253: // SRAM_V|SRAM_F_V
|
|
if (Data()[ii + 1] == 0x565f465f || (Data()[ii + 1] & 0xffff) == 0x565f) {
|
|
Add(ii, ESRAMLabel);
|
|
ii++;
|
|
}
|
|
break;
|
|
case 0x52504545: // EEPROM_V
|
|
if (Data()[ii + 1] == 0x565f4d4f) {
|
|
Add(ii, EEEPROMLabel);
|
|
ii++;
|
|
}
|
|
case 0xb0a2b570: // eeprom 121/122/124 read
|
|
if (Data()[ii + 1] == 0x04001c0d && Data()[ii + 2] == 0x48030c03 &&
|
|
Data()[ii + 3] == 0x88806800 && Data()[ii + 4] == 0xd3054283) {
|
|
Add(ii, EEEPROMRead);
|
|
ii += 4;
|
|
}
|
|
break;
|
|
case 0xb0a9b530: // eeprom 121/122 write
|
|
if (Data()[ii + 1] == 0x04001c0d && Data()[ii + 2] == 0x48030c04 &&
|
|
Data()[ii + 3] == 0x88806800 && Data()[ii + 4] == 0xd3054284) {
|
|
Add(ii, EEEPROMWrite);
|
|
ii += 4;
|
|
}
|
|
break;
|
|
case 0xb0acb5f0: // eeprom 124 write
|
|
if (Data()[ii + 1] == 0x04001c0d && Data()[ii + 2] == 0x06120c01 &&
|
|
Data()[ii + 3] == 0x48030e17 && Data()[ii + 4] == 0x88806800 &&
|
|
Data()[ii + 5] == 0xd3054281) {
|
|
Add(ii, EEEPROMWrite124);
|
|
ii += 5;
|
|
}
|
|
break;
|
|
case 0x4647b5f0: // eeprom 126 write
|
|
if (Data()[ii + 1] == 0xb0acb480 && Data()[ii + 2] == 0x04001c0e &&
|
|
Data()[ii + 3] == 0x06120c05 && Data()[ii + 4] == 0x46900e12 &&
|
|
Data()[ii + 5] == 0x68004803 && Data()[ii + 6] == 0x42858880 &&
|
|
Data()[ii + 7] == 0x4802d306) {
|
|
Add(ii, EEEPROMWrite126);
|
|
ii += 7;
|
|
}
|
|
break;
|
|
case 0x53414c46:
|
|
// FLASH1M_V10X
|
|
if (Data()[ii + 1] == 0x5f4d3148 && (Data()[ii + 2] & 0xfeffffff) == 0x32303156) {
|
|
Add(ii, EFLASH1M10XLabel);
|
|
ii += 2;
|
|
}
|
|
// FLASH_V1
|
|
else if (Data()[ii + 1] == 0x31565f48) {
|
|
Add(ii, EFLASHLabel);
|
|
ii++;
|
|
}
|
|
// FLASH512_V13
|
|
else if (Data()[ii + 1] == 0x32313548 && Data()[ii + 2] == 0x3331565f) {
|
|
Add(ii, EFLASH512Label);
|
|
ii += 2;
|
|
}
|
|
break;
|
|
case 0x0e000600: // FLASH1M_V102 code1
|
|
if (Data()[ii + 1] == 0x21aa4b05 && Data()[ii + 2] == 0x4a057019) {
|
|
Add(ii, EFLASH1M102_1);
|
|
ii += 2;
|
|
}
|
|
break;
|
|
case 0xfd88f7ff: // FLASH1M_V102 code2
|
|
if (Data()[ii + 1] == 0x0c030400 && Data()[ii + 2] == 0x24014a03 &&
|
|
Data()[ii + 3] == 0x0000e007) {
|
|
Add(ii, EFLASH1M102_2);
|
|
ii += 2;
|
|
}
|
|
break;
|
|
case 0xb090b5f0:
|
|
// FLASH1M_V102 code3
|
|
if (Data()[ii + 1] == 0x0c060400 && Data()[ii + 2] == 0x68004803 &&
|
|
Data()[ii + 3] == 0x42868940 && Data()[ii + 4] == 0x4802d306 &&
|
|
Data()[ii + 5] == 0x0000e052) {
|
|
Add(ii, EFLASH1M102_3);
|
|
ii += 5;
|
|
}
|
|
// FLASH1M_V103 code3
|
|
else if (Data()[ii + 1] == 0x0c060400 && Data()[ii + 2] == 0x68004803 &&
|
|
Data()[ii + 3] == 0x42868940 && Data()[ii + 4] == 0x4802d306 &&
|
|
Data()[ii + 5] == 0x0000e054) {
|
|
Add(ii, EFLASH1M103_3);
|
|
ii += 5;
|
|
}
|
|
// FLASH1M_V103 code4
|
|
else if (Data()[ii + 1] == 0x04011c0e && Data()[ii + 2] == 0x06120c0c &&
|
|
Data()[ii + 3] == 0x4d180e17 && Data()[ii + 4] == 0x68406828 &&
|
|
Data()[ii + 5] == 0xd2374286) {
|
|
Add(ii, EFLASH1M103_4);
|
|
ii += 5;
|
|
}
|
|
// FLASH1M_V102 code5
|
|
else if (Data()[ii + 1] == 0x04001c0f && Data()[ii + 2] == 0x48030c04 &&
|
|
Data()[ii + 3] == 0x89406800 && Data()[ii + 4] == 0xd3054284 &&
|
|
Data()[ii + 5] == 0xe0404801) {
|
|
Add(ii, EFLASH1M102_5);
|
|
ii += 5;
|
|
}
|
|
// FLASH_V123 code5
|
|
else if (Data()[ii + 1] == 0x04001c0f && Data()[ii + 2] == 0x2c0f0c04 &&
|
|
Data()[ii + 3] == 0x4801d904) {
|
|
Add(ii, EFLASHV123_5);
|
|
ii += 3;
|
|
}
|
|
// FLASH512_V13 code5
|
|
else if (Data()[ii + 1] == 0x04001c0f && Data()[ii + 2] == 0x48030c04 &&
|
|
Data()[ii + 3] == 0x89406800 && Data()[ii + 4] == 0xd3054284 &&
|
|
Data()[ii + 5] == 0xe0414801) {
|
|
Add(ii, EFLASH512_2);
|
|
ii += 5;
|
|
}
|
|
break;
|
|
case 0x4c0ab510: // FLASH1M_V102 code4
|
|
if (Data()[ii + 1] == 0x702222aa && Data()[ii + 2] == 0x22554b09 &&
|
|
Data()[ii + 3] == 0x22a0701a && Data()[ii + 4] == 0x78027022 &&
|
|
Data()[ii + 5] == 0x4b07700a && Data()[ii + 6] == 0x681b7802 &&
|
|
Data()[ii + 7] == 0xf0002001) {
|
|
Add(ii, EFLASH1M102_4);
|
|
ii += 7;
|
|
}
|
|
break;
|
|
case 0xb093b590: // FLASH_V1 code1
|
|
if (Data()[ii + 1] == 0x1d39466f && Data()[ii + 2] == 0xf0001c08 &&
|
|
(Data()[ii + 3] & 0xffffff00) == 0x1d38f900 && Data()[ii + 4] == 0x64791c41 &&
|
|
Data()[ii + 5] == 0x21aa4809 && Data()[ii + 6] == 0x48097001 &&
|
|
Data()[ii + 7] == 0x70012155) {
|
|
Add(ii, EFLASH_1);
|
|
ii += 7;
|
|
}
|
|
break;
|
|
case 0xb092b580: // FLASH_V1 code2
|
|
if (Data()[ii + 1] == 0x481f466f && Data()[ii + 2] == 0x880a491e &&
|
|
Data()[ii + 3] == 0x1c114b1e && Data()[ii + 4] == 0x4b1e4019 &&
|
|
Data()[ii + 5] == 0x8a12681a && Data()[ii + 6] == 0x1c0a4311 &&
|
|
Data()[ii + 7] == 0x481c8002) {
|
|
Add(ii, EFLASH_2);
|
|
ii += 7;
|
|
}
|
|
break;
|
|
case 0xb094b580:
|
|
// FLASH_V1 code3
|
|
if (Data()[ii + 1] == 0x1c39466f && Data()[ii + 2] == 0x1c388008 &&
|
|
Data()[ii + 3] == 0x290f8801 && Data()[ii + 4] == 0x4801d904 &&
|
|
Data()[ii + 5] == 0x0000e056 && Data()[ii + 6] == 0x000080ff &&
|
|
Data()[ii + 7] == 0x49234823) {
|
|
Add(ii, EFLASH_3);
|
|
ii += 7;
|
|
}
|
|
// FLASH_V1 code4
|
|
else if (Data()[ii + 1] == 0x6079466f && Data()[ii + 2] == 0x80081c39 &&
|
|
Data()[ii + 3] == 0x88011c38 && Data()[ii + 4] == 0xd903290f &&
|
|
Data()[ii + 5] == 0xe0734800 && Data()[ii + 6] == 0x000080ff &&
|
|
Data()[ii + 7] == 0x88011c38) {
|
|
Add(ii, EFLASH_4);
|
|
ii += 7;
|
|
}
|
|
break;
|
|
case 0xffaaf7ff: // FLASH_V123 code1
|
|
if (Data()[ii + 1] == 0x0c030400 && Data()[ii + 2] == 0x24014a03 &&
|
|
Data()[ii + 3] == 0x0000e007) {
|
|
Add(ii, EFLASHV123_1);
|
|
ii += 3;
|
|
}
|
|
break;
|
|
case 0xb0a0b5f0:
|
|
// FLASH_V123 code2
|
|
if (Data()[ii + 1] == 0x1c161c0d && Data()[ii + 2] == 0x04001c1f &&
|
|
Data()[ii + 3] == 0x4a080c04) {
|
|
Add(ii, EFLASHV123_2);
|
|
ii += 3;
|
|
}
|
|
// FLASH512_V13 code5
|
|
else if (Data()[ii + 1] == 0x1c161c0d && Data()[ii + 2] == 0x04031C1F &&
|
|
Data()[ii + 3] == 0x4a0f0c1c) {
|
|
Add(ii, EFLASH512_1);
|
|
ii += 3;
|
|
}
|
|
break;
|
|
case 0xb090b570: // FLASH_V123 code3
|
|
if (Data()[ii + 1] == 0x88294d15 && Data()[ii + 2] == 0x40314e15 &&
|
|
Data()[ii + 3] == 0x68004815) {
|
|
Add(ii, EFLASHV123_3);
|
|
ii += 3;
|
|
}
|
|
break;
|
|
case 0x4646b570: // FLASH_V123 code4
|
|
if (Data()[ii + 1] == 0xb090b440 && Data()[ii + 2] == 0x0c030400 &&
|
|
Data()[ii + 3] == 0xd83b2b0f) {
|
|
Add(ii, EFLASHV123_4);
|
|
ii += 3;
|
|
}
|
|
break;
|
|
case 0x701020aa: // FLASH1M_V103 code1
|
|
if (Data()[ii + 1] == 0x20554905 && Data()[ii + 2] == 0x20907008 &&
|
|
Data()[ii + 3] == 0xa9107010) {
|
|
Add(ii, EFLASH1M103_1);
|
|
ii += 3;
|
|
}
|
|
break;
|
|
case 0xf0010500: // FLASH1M_V103 code2a
|
|
if (Data()[ii + 1] == 0x0600f8d3 && Data()[ii + 2] == 0x43040e00 &&
|
|
Data()[ii + 3] == 0x20aa4907 && Data()[ii + 4] == 0x4a077008 &&
|
|
Data()[ii + 5] == 0x70102055 && Data()[ii + 6] == 0x700820f0 &&
|
|
Data()[ii + 7] == 0xa9107008) {
|
|
Add(ii, EFLASH1M103_2);
|
|
ii += 7;
|
|
}
|
|
break;
|
|
case 0xf0050500: // FLASH1M_V103 code2b
|
|
if (Data()[ii + 1] == 0x0600F945 && Data()[ii + 2] == 0x43040e00 &&
|
|
Data()[ii + 3] == 0x20aa4907 && Data()[ii + 4] == 0x4a077008 &&
|
|
Data()[ii + 5] == 0x70102055 && Data()[ii + 6] == 0x700820f0 &&
|
|
Data()[ii + 7] == 0xa9107008) {
|
|
Add(ii, EFLASH1M103_2);
|
|
ii += 7;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
#ifdef __TEST
|
|
DumpPatchInfo();
|
|
#endif
|
|
iWriter->Open();
|
|
if (!PatchNes() && !PatchSRAM() && !PatchEEPROM() && !PatchFLASH1M_V10X()) PatchFLASH();
|
|
PatchDragonBallZ();
|
|
if (!PatchSleep()) {
|
|
#ifdef __TEST
|
|
if (__COMMON_SLEEP) {
|
|
#else
|
|
if (gs().gbaSleepHack) {
|
|
#endif
|
|
CommonSleepSearch();
|
|
CommonSleepPatch();
|
|
}
|
|
}
|
|
iWriter->Close();
|
|
}
|
|
|
|
bool CGbaPatcher::PatchSRAM(void) {
|
|
test_printf("CGbaPatcher::PatchSRAM\n");
|
|
bool res = false;
|
|
for (u32 ii = 0; ii < iCount; ii++) {
|
|
if (iPatchInfo[ii].iType == ESRAMLabel) {
|
|
res = true;
|
|
iSaveSize = 32 * 1024;
|
|
break;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
bool CGbaPatcher::PatchEEPROM(void) {
|
|
test_printf("CGbaPatcher::PatchEEPROM\n");
|
|
bool res = false;
|
|
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
|
|
};
|
|
u32 eeprom_ver = 0, eeprom_count = 0;
|
|
for (u32 ii = 0; ii < iCount; ii++) {
|
|
if (iPatchInfo[ii].iType == EEEPROMLabel) {
|
|
u32 ver = Data()[iPatchInfo[ii].iOffset + 2] & 0xffffff;
|
|
ver = 100 * ((ver & 0xff) - '0') + 10 * (((ver & 0xff00) >> 8) - '0') +
|
|
(((ver & 0xff0000) >> 16) - '0');
|
|
test_printf("eeprom ver: %d\n", ver);
|
|
if (eeprom_count) {
|
|
if (ver != eeprom_ver) Error("EEPROM: two different versions");
|
|
} else {
|
|
eeprom_ver = ver;
|
|
}
|
|
eeprom_count++;
|
|
}
|
|
}
|
|
if (eeprom_ver == 111) {
|
|
res = true;
|
|
iSaveSize = 512;
|
|
PatchEEPROM111();
|
|
} else if (eeprom_count) {
|
|
res = true;
|
|
iSaveSize = 8 * 1024;
|
|
for (u32 ii = 0; ii < iCount; ii++) {
|
|
switch (iPatchInfo[ii].iType) {
|
|
case EEEPROMRead:
|
|
if (eeprom_ver == 120 || eeprom_ver == 121 || eeprom_ver == 122 ||
|
|
eeprom_ver == 124 || eeprom_ver == 126)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_eeprom_1,
|
|
sizeof(patch_eeprom_1));
|
|
else
|
|
Error("EEEPROMRead: invalid version");
|
|
break;
|
|
case EEEPROMWrite:
|
|
if (eeprom_ver == 120 || eeprom_ver == 121 || eeprom_ver == 122)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_eeprom_2,
|
|
sizeof(patch_eeprom_2));
|
|
else
|
|
Error("EEEPROMWrite: invalid version");
|
|
break;
|
|
case EEEPROMWrite124:
|
|
if (eeprom_ver == 124)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_eeprom_2,
|
|
sizeof(patch_eeprom_2));
|
|
else
|
|
Error("EEEPROMWrite124: invalid version");
|
|
break;
|
|
case EEEPROMWrite126:
|
|
if (eeprom_ver == 126)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_eeprom_2,
|
|
sizeof(patch_eeprom_2));
|
|
else
|
|
Error("EEEPROMWrite126: invalid version");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
bool CGbaPatcher::PatchFLASH1M_V10X(void) {
|
|
test_printf("CGbaPatcher::PatchFLASH1M_V10X\n");
|
|
bool res = false;
|
|
const u8 patch_flash_1[] = {
|
|
0x00, 0xb5, // PUSH {LR}
|
|
0x00, 0xf0, 0x55, 0xfb, // BL Save3a
|
|
0x02, 0xbc, // POP {R1}
|
|
0x08, 0x47 // BX R1
|
|
};
|
|
const u8 patch_flash_2[] = {
|
|
0x13, 0x23, 0x1b, 0x02, // MOVL R3, 0x1300
|
|
0x62, 0x20, // MOV R0, #0x62
|
|
0x03, 0x43 // ORR R3, R0
|
|
};
|
|
const u8 patch_flash_3[] = {
|
|
0x00, 0xb5, // PUSH {LR}
|
|
0x00, 0x20, // MOV R0, #0
|
|
0x02, 0xbc, // POP {R1}
|
|
0x08, 0x47, // BX R1
|
|
// Save3a:
|
|
0x70, 0xb4, // PUSH {R4-R6}
|
|
0x0a, 0x49, // LDR R1, =0x9FE0000
|
|
0xd2, 0x22, 0x12, 0x02, // MOVL R2, 0xD200
|
|
0x0a, 0x80, // STRH R2, [R1]
|
|
0x09, 0x49, // LDR R1, =0x8000000
|
|
0x15, 0x23, 0x1b, 0x02, // MOVL R3, 0x1500
|
|
0x0b, 0x80, // STRH R3, [R1]
|
|
0x08, 0x49, // LDR R1, =0x8020000
|
|
0x0a, 0x80, // STRH R2, [R1]
|
|
0x08, 0x49, // LDR R1, =0x8040000
|
|
0x0b, 0x80, // STRH R3, [R1]
|
|
0x08, 0x49, // LDR R1, =0x9C00000
|
|
0x00, 0x01, // LSL R0, R0, #4
|
|
0x10, 0x30, // ADD R0, #0x10
|
|
0x08, 0x80, // STRH R0, [R1]
|
|
0x07, 0x49, // LDR R1, =0x9FC0000
|
|
0x0b, 0x80, // STRH R3, [R1]
|
|
0x70, 0xbc, // POP {R4-R6}
|
|
0x70, 0x47, // BX LR
|
|
0x00, // DCB 0
|
|
0x00, // DCB 0
|
|
0x00, 0x00, 0xfe, 0x09, // DCD 0x9FE0000
|
|
0x00, 0x00, 0x00, 0x08, // DCD 0x8000000
|
|
0x00, 0x00, 0x02, 0x08, // DCD 0x8020000
|
|
0x00, 0x00, 0x04, 0x08, // DCD 0x8040000
|
|
0x00, 0x00, 0xc0, 0x09, // DCD 0x9C00000
|
|
0x00, 0x00, 0xfc, 0x09 // DCD 0x9FC0000
|
|
};
|
|
const u8 patch_flash_4[] = {
|
|
0x00, 0x00 // LSL R0, R0, #0
|
|
};
|
|
const u32 patch_flash_4_offsets[] = {0x06, 0x0c, 0x10};
|
|
const u8 patch_flash_5[] = {
|
|
0x7c, 0xb5, // PUSH {R2-R6,LR}
|
|
0x00, 0x06, // LSL R0, R0, #0x18
|
|
0x04, 0x0f, // LSR R4, R0, #0x1C
|
|
0x00, 0x01, // LSL R0, R0, #4
|
|
0x00, 0x0c, // LSR R0, R0, #0x10
|
|
0x0a, 0x1c, // ADD R2, R1, #0
|
|
0xe0, 0x21, 0x09, 0x05, // MOVL R1, 0xE000000
|
|
0x09, 0x18, // ADD R1, R1, R0
|
|
0x01, 0x23, 0x1b, 0x03, // MOVL R3, 0x1000
|
|
0x0e, 0x48, // LDR R0, =0x9FE0000
|
|
0xd2, 0x25, 0x2d, 0x02, // MOVL R5, 0xD200
|
|
0x05, 0x80, // STRH R5, [R0]
|
|
0x0d, 0x48, // LDR R0, =0x8000000
|
|
0x15, 0x26, 0x36, 0x02, // MOVL R6, 0x1500
|
|
0x06, 0x80, // STRH R6, [R0]
|
|
0x0c, 0x48, // LDR R0, =0x8020000
|
|
0x05, 0x80, // STRH R5, [R0]
|
|
0x0c, 0x48, // LDR R0, =0x8040000
|
|
0x06, 0x80, // STRH R6, [R0]
|
|
0x0c, 0x48, // LDR R0, =0x9C00000
|
|
0x24, 0x01, // LSL R4, R4, #4
|
|
0x10, 0x34, // ADD R4, #0x10
|
|
0x04, 0x80, // STRH R4, [R0]
|
|
0x0b, 0x48, // LDR R0, =0x9FC0000
|
|
0x06, 0x80, // STRH R6, [R0]
|
|
// l1:
|
|
0x10, 0x78, // LDRB R0, [R2]
|
|
0x08, 0x70, // STRB R0, [R1]
|
|
0x01, 0x3b, // SUB R3, #1
|
|
0x01, 0x32, // ADD R2, #1
|
|
0x01, 0x31, // ADD R1, #1
|
|
0x00, 0x2b, // CMP R3, #0
|
|
0xf8, 0xd1, // BNE l1
|
|
0x00, 0x20, // MOV R0, #0
|
|
0x7c, 0xbc, // POP {R2-R6}
|
|
0x02, 0xbc, // POP {R1}
|
|
0x08, 0x47, // BX R1
|
|
0x00, 0x00, 0xfe, 0x09, // DCD 0x9FE0000
|
|
0x00, 0x00, 0x00, 0x08, // DCD 0x8000000
|
|
0x00, 0x00, 0x02, 0x08, // DCD 0x8020000
|
|
0x00, 0x00, 0x04, 0x08, // DCD 0x8040000
|
|
0x00, 0x00, 0xc0, 0x09, // DCD 0x9C00000
|
|
0x00, 0x00, 0xfc, 0x09 // DCD 0x9FC0000
|
|
};
|
|
const u8 patch_flash_6[] = {
|
|
0x00, 0xb5, // PUSH {LR}
|
|
0x00, 0xf0, 0x5b, 0xfb, // BL Save6a
|
|
0x02, 0xbc, // POP {R1}
|
|
0x08, 0x47 // BX R1
|
|
};
|
|
const u8 patch_flash_7a[] = {
|
|
0x10, 0x78 // LDRB R0, [R2]
|
|
};
|
|
const u8 patch_flash_7b[] = {
|
|
0x08, 0x78 // LDRB R0, [R1]
|
|
};
|
|
const u8 patch_flash_8[] = {
|
|
0x1b, 0x24, 0x24, 0x01, // MOVL R4, 0x1B0
|
|
0x24, 0x01, // LSL R4, R4, #4
|
|
0x32, 0x20, // MOV R0, #0x32
|
|
0x04, 0x43, // ORR R4, R0
|
|
0x07, 0x49, // LDR R1, =0xE005555
|
|
0xaa, 0x20, // MOV R0, #0xAA
|
|
0x08, 0x78, // LDRB R0, [R1]
|
|
0x07, 0x4a, // LDR R2, =0xE002AAA
|
|
0x55, 0x20, // MOV R0, #0x55
|
|
0x10, 0x78, // LDRB R0, [R2]
|
|
0xf0, 0x20, // MOV R0, #0xF0
|
|
0x08, 0x78, // LDRB R0, [R1]
|
|
0x08, 0x78 // LDRB R0, [R1]
|
|
|
|
};
|
|
const u8 patch_flash_9[] = {
|
|
0x00, 0xb5, // PUSH {LR}
|
|
0x00, 0x20, // MOV R0, #0
|
|
0x02, 0xbc, // POP {R1}
|
|
0x08, 0x47 // BX R1
|
|
};
|
|
const u8 patch_flash_a[] = {
|
|
0x78, 0xb5, // PUSH {R3-R6,LR}
|
|
0x00, 0x06, // LSL R0, R0, #0x18
|
|
0x03, 0x0f, // LSR R3, R0, #0x1C
|
|
0x00, 0x01, // LSL R0, R0, #4
|
|
0x00, 0x04, // LSL R0, R0, #0x10
|
|
0x40, 0x18, // ADD R0, R0, R1
|
|
0xe0, 0x21, 0x09, 0x05, // MOVL R1, 0xE000000
|
|
0x09, 0x18, // ADD R1, R1, R0
|
|
0x0b, 0x48, // LDR R0, =0x9FE0000
|
|
0xd2, 0x25, 0x2d, 0x02, // MOVL R5, 0xD200
|
|
0x05, 0x80, // STRH R5, [R0]
|
|
0x0a, 0x48, // LDR R0, =0x8000000
|
|
0x15, 0x26, 0x36, 0x02, // MOVL R6, 0x1500
|
|
0x06, 0x80, // STRH R6, [R0]
|
|
0x09, 0x48, // LDR R0, =0x8020000
|
|
0x05, 0x80, // STRH R5, [R0]
|
|
0x09, 0x48, // LDR R0, =0x8040000
|
|
0x06, 0x80, // STRH R6, [R0]
|
|
0x09, 0x48, // LDR R0, =0x9C00000
|
|
0x1b, 0x01, // LSL R3, R3, #4
|
|
0x10, 0x33, // ADD R3, #0x10
|
|
0x03, 0x80, // STRH R3, [R0]
|
|
0x08, 0x48, // LDR R0, =0x9FC0000
|
|
0x06, 0x80, // STRH R6, [R0]
|
|
0x0a, 0x70, // STRB R2, [R1]
|
|
0x00, 0x20, // MOV R0, #0
|
|
0x78, 0xbc, // POP {R3-R6}
|
|
0x02, 0xbc, // POP {R1}
|
|
0x08, 0x47, // BX R1
|
|
0x00, 0x00, 0xfe, 0x09, // DCD 0x9FE0000
|
|
0x00, 0x00, 0x00, 0x08, // DCD 0x8000000
|
|
0x00, 0x00, 0x02, 0x08, // DCD 0x8020000
|
|
0x00, 0x00, 0x04, 0x08, // DCD 0x8040000
|
|
0x00, 0x00, 0xc0, 0x09, // DCD 0x9C00000
|
|
0x00, 0x00, 0xfc, 0x09 // DCD 0x9FC0000
|
|
};
|
|
u32 flash_ver = 0, flash_count = 0;
|
|
for (u32 ii = 0; ii < iCount; ii++) {
|
|
if (iPatchInfo[ii].iType == EFLASH1M10XLabel) {
|
|
u32 ver = Data()[iPatchInfo[ii].iOffset + 2] & 0xffffff00;
|
|
ver = 100 * (((ver & 0xff00) >> 8) - '0') + 10 * (((ver & 0xff0000) >> 16) - '0') +
|
|
(((ver & 0xff000000) >> 24) - '0');
|
|
test_printf("flash ver: %d\n", ver);
|
|
if (flash_count) {
|
|
if (ver != flash_ver) Error("FLASH1M: two different versions");
|
|
} else {
|
|
flash_ver = ver;
|
|
}
|
|
flash_count++;
|
|
break;
|
|
}
|
|
}
|
|
if (flash_count) {
|
|
res = true;
|
|
iSaveSize = 128 * 1024;
|
|
for (u32 ii = 0; ii < iCount; ii++) {
|
|
switch (iPatchInfo[ii].iType) {
|
|
case EFLASH1M102_1:
|
|
if (flash_ver == 102)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_1,
|
|
sizeof(patch_flash_1));
|
|
else if (flash_ver == 103)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_6,
|
|
sizeof(patch_flash_6));
|
|
else
|
|
Error("EFLASH1M102_1: invalid version");
|
|
break;
|
|
case EFLASH1M102_2:
|
|
if (flash_ver == 102 || flash_ver == 103)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_2,
|
|
sizeof(patch_flash_2));
|
|
else
|
|
Error("EFLASH1M102_2: invalid version");
|
|
break;
|
|
case EFLASH1M102_3:
|
|
if (flash_ver == 102) {
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_3,
|
|
sizeof(patch_flash_3));
|
|
u8 patch_fix[2] = {iRamPage, 0x30};
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4 + 38, patch_fix,
|
|
sizeof(patch_fix));
|
|
} else
|
|
Error("EFLASH1M102_3: invalid version");
|
|
break;
|
|
case EFLASH1M102_4:
|
|
if (flash_ver == 102) {
|
|
for (u32 jj = 0; jj < sizeofa(patch_flash_4_offsets); jj++)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4 + patch_flash_4_offsets[jj],
|
|
patch_flash_4, sizeof(patch_flash_4));
|
|
} else if (flash_ver == 103)
|
|
; // do nothing
|
|
else
|
|
Error("EFLASH1M102_4: invalid version");
|
|
break;
|
|
case EFLASH1M102_5:
|
|
if (flash_ver == 102 || flash_ver == 103) {
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_5,
|
|
sizeof(patch_flash_5));
|
|
u8 patch_fix[2] = {iRamPage, 0x34};
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4 + 50, patch_fix,
|
|
sizeof(patch_fix));
|
|
} else
|
|
Error("EFLASH1M102_5: invalid version");
|
|
break;
|
|
case EFLASH1M103_1:
|
|
if (flash_ver == 102)
|
|
; // do nothing
|
|
else if (flash_ver == 103) {
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4 + 0x02, patch_flash_7a,
|
|
sizeof(patch_flash_7a));
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4 + 0x08, patch_flash_7b,
|
|
sizeof(patch_flash_7b));
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4 + 0x0c, patch_flash_7a,
|
|
sizeof(patch_flash_7a));
|
|
} else
|
|
Error("EFLASH1M103_1: invalid version");
|
|
break;
|
|
case EFLASH1M103_2:
|
|
if (flash_ver == 103) {
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4 + 2, patch_flash_8,
|
|
sizeof(patch_flash_8));
|
|
} else
|
|
Error("EFLASH1M103_2: invalid version");
|
|
break;
|
|
case EFLASHV123_3:
|
|
if (flash_ver == 102)
|
|
; // do nothing
|
|
else if (flash_ver == 103) {
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_9,
|
|
sizeof(patch_flash_9));
|
|
} else
|
|
Error("FLASH1M103, EFLASHV123_3: invalid version");
|
|
break;
|
|
case EFLASH1M103_3:
|
|
if (flash_ver == 103) {
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_3,
|
|
sizeof(patch_flash_3));
|
|
u8 patch_fix[2] = {iRamPage, 0x30};
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4 + 38, patch_fix,
|
|
sizeof(patch_fix));
|
|
} else
|
|
Error("EFLASH1M103_3: invalid version");
|
|
break;
|
|
case EFLASH1M103_4:
|
|
if (flash_ver == 103) {
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_a,
|
|
sizeof(patch_flash_a));
|
|
u8 patch_fix[2] = {iRamPage, 0x33};
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4 + 46, patch_fix,
|
|
sizeof(patch_fix));
|
|
} else
|
|
Error("EFLASH1M103_4: invalid version");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
bool CGbaPatcher::PatchFLASH(void) {
|
|
test_printf("CGbaPatcher::PatchFLASH\n");
|
|
bool res = false;
|
|
const u8 patch_flash_1[] = {
|
|
0x00, 0xb5, // PUSH {LR}
|
|
0x1b, 0x20, 0x00, 0x02, // MOVL R0, 0x1B00
|
|
0x32, 0x21, // MOV R1, #0x32
|
|
0x08, 0x43, // ORR R0, R1
|
|
0x02, 0xbc, // POP {R1}
|
|
0x08, 0x47 // BX R1
|
|
};
|
|
const u8 patch_flash_2[] = {
|
|
0x00, 0xb5, // PUSH {LR}
|
|
0x00, 0x20, // MOV R0, #0
|
|
0x02, 0xbc, // POP {R1}
|
|
0x08, 0x47 // BX R1
|
|
};
|
|
const u8 patch_flash_3[] = {
|
|
0x1b, 0x23, 0x1b, 0x02, // MOVL R3, 0x1B00
|
|
0x32, 0x20, // MOV R0, #0x32
|
|
0x03, 0x43 // ORR R3, R0
|
|
|
|
};
|
|
const u8 patch_flash_4[] = {
|
|
0x7c, 0xb5, // PUSH {R2-R6,LR}
|
|
0x00, 0x07, // LSL R0, R0, #0x1C
|
|
0x00, 0x0c, // LSR R0, R0, #0x10
|
|
0x0a, 0x1c, // ADD R2, R1, #0
|
|
0xe0, 0x21, 0x09, 0x05, // MOVL R1, 0xE000000
|
|
0x09, 0x18, // ADD R1, R1, R0
|
|
0x01, 0x23, 0x1b, 0x03, // MOVL R3, 0x1000
|
|
// l1:
|
|
0x10, 0x78, // LDRB R0, [R2]
|
|
0x08, 0x70, // STRB R0, [R1]
|
|
0x01, 0x3b, // SUB R3, #1
|
|
0x01, 0x32, // ADD R2, #1
|
|
0x01, 0x31, // ADD R1, #1
|
|
0x00, 0x2b, // CMP R3, #0
|
|
0xf8, 0xd1, // BNE l1
|
|
0x00, 0x20, // MOV R0, #0
|
|
0x7c, 0xbc, // POP {R2-R6}
|
|
0x02, 0xbc, // POP {R1}
|
|
0x08, 0x47 // BX R1
|
|
};
|
|
const u8 patch_flash_5[] = {
|
|
0x70, 0xb5, // PUSH {R4-R6,LR}
|
|
0xa0, 0xb0, // SUB SP, SP, #0x80
|
|
0x00, 0x03, // LSL R0, R0, #0xC
|
|
0x40, 0x18, // ADD R0, R0, R1
|
|
0xe0, 0x21, 0x09, 0x05, // MOVL R1, 0xE000000
|
|
0x09, 0x18, // ADD R1, R1, R0
|
|
// l1:
|
|
0x08, 0x78, // LDRB R0, [R1]
|
|
0x10, 0x70, // STRB R0, [R2]
|
|
0x01, 0x3b, // SUB R3, #1
|
|
0x01, 0x32, // ADD R2, #1
|
|
0x01, 0x31, // ADD R1, #1
|
|
0x00, 0x2b, // CMP R3, #0
|
|
0xf8, 0xd1, // BNE l1
|
|
0x00, 0x20, // MOV R0, #0
|
|
0x20, 0xb0, // ADD SP, SP, #0x80
|
|
0x70, 0xbc, // POP {R4-R6}
|
|
0x02, 0xbc, // POP {R1}
|
|
0x08, 0x47 // BX R1
|
|
};
|
|
const u8 patch_flash_6[] = {
|
|
0x7c, 0xb5, // PUSH {R2-R6,LR}
|
|
0x90, 0xb0, // SUB SP, SP, #0x40
|
|
0x00, 0x03, // LSL R0, R0, #0xC
|
|
0x0a, 0x1c, // ADD R2, R1, #0
|
|
0xe0, 0x21, 0x09, 0x05, // MOVL R1, 0xE000000
|
|
0x09, 0x18, // ADD R1, R1, R0
|
|
0x01, 0x23, 0x1b, 0x03, // MOVL R3, 0x1000
|
|
// l1
|
|
0x10, 0x78, // LDRB R0, [R2]
|
|
0x08, 0x70, // STRB R0, [R1]
|
|
0x01, 0x3b, // SUB R3, #1
|
|
0x01, 0x32, // ADD R2, #1
|
|
0x01, 0x31, // ADD R1, #1
|
|
0x00, 0x2b, // CMP R3, #0
|
|
0xf8, 0xd1, // BNE l1
|
|
0x00, 0x20, // MOV R0, #0
|
|
0x10, 0xb0, // ADD SP, SP, #0x40
|
|
0x7c, 0xbc, // POP {R2-R6}
|
|
0x02, 0xbc, // POP {R1}
|
|
0x08, 0x47 // BX R1
|
|
};
|
|
u32 flash_ver = 0, flash_count = 0;
|
|
for (u32 ii = 0; ii < iCount; ii++) {
|
|
if (iPatchInfo[ii].iType == EFLASHLabel) {
|
|
u32 ver = Data()[iPatchInfo[ii].iOffset + 2] & 0xffff;
|
|
ver = 100 * (((Data()[iPatchInfo[ii].iOffset + 1] & 0xff000000) >> 24) - '0') +
|
|
10 * ((ver & 0xff) - '0') + (((ver & 0xff00) >> 8) - '0');
|
|
test_printf("flash ver: %d\n", ver);
|
|
if (flash_count) {
|
|
if (ver != flash_ver) Error("FLASH: two different versions");
|
|
} else {
|
|
flash_ver = ver;
|
|
}
|
|
flash_count++;
|
|
} else if (iPatchInfo[ii].iType == EFLASH512Label) {
|
|
u32 ver = 130 + ((Data()[iPatchInfo[ii].iOffset + 3] & 0xff) - '0');
|
|
test_printf("flash 512 ver: %d\n", ver);
|
|
if (flash_count) {
|
|
if (ver != flash_ver) Error("FLASH512: two different versions");
|
|
} else {
|
|
flash_ver = ver;
|
|
}
|
|
flash_count++;
|
|
}
|
|
}
|
|
if (flash_count) {
|
|
res = true;
|
|
iSaveSize = 64 * 1024;
|
|
for (u32 ii = 0; ii < iCount; ii++) {
|
|
switch (iPatchInfo[ii].iType) {
|
|
case EFLASH1M102_2:
|
|
if (flash_ver == 130 || flash_ver == 131 || flash_ver == 133)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_3,
|
|
sizeof(patch_flash_3));
|
|
else
|
|
Error("EFLASH512/EFLASH1M102_2: invalid version");
|
|
break;
|
|
case EFLASH_1:
|
|
if (flash_ver == 120 || flash_ver == 121)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_1,
|
|
sizeof(patch_flash_1));
|
|
else
|
|
Error("EFLASH_1: invalid version");
|
|
break;
|
|
case EFLASH_2:
|
|
if (flash_ver == 120 || flash_ver == 121)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_2,
|
|
sizeof(patch_flash_2));
|
|
else
|
|
Error("EFLASH_2: invalid version");
|
|
break;
|
|
case EFLASH_3:
|
|
if (flash_ver == 120 || flash_ver == 121)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_2,
|
|
sizeof(patch_flash_2));
|
|
else
|
|
Error("EFLASH_3: invalid version");
|
|
break;
|
|
case EFLASH_4:
|
|
if (flash_ver == 120 || flash_ver == 121)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_4,
|
|
sizeof(patch_flash_4));
|
|
else
|
|
Error("EFLASH_4: invalid version");
|
|
break;
|
|
case EFLASHV123_1:
|
|
if (flash_ver == 123 || flash_ver == 124 || flash_ver == 125 ||
|
|
flash_ver == 126)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_3,
|
|
sizeof(patch_flash_3));
|
|
else
|
|
Error("EFLASHV123_1: invalid version");
|
|
break;
|
|
case EFLASHV123_2:
|
|
if (flash_ver == 123 || flash_ver == 124 || flash_ver == 125 ||
|
|
flash_ver == 126)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_5,
|
|
sizeof(patch_flash_5));
|
|
else
|
|
Error("EFLASHV123_2: invalid version");
|
|
break;
|
|
case EFLASHV123_3:
|
|
if (flash_ver == 123 || flash_ver == 124 || flash_ver == 125 ||
|
|
flash_ver == 126 || flash_ver == 130 || flash_ver == 131 ||
|
|
flash_ver == 133)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_2,
|
|
sizeof(patch_flash_2));
|
|
else
|
|
Error("EFLASHV123_3: invalid version");
|
|
break;
|
|
case EFLASHV123_4:
|
|
if (flash_ver == 123 || flash_ver == 124 || flash_ver == 125 ||
|
|
flash_ver == 126 || flash_ver == 130 || flash_ver == 131 ||
|
|
flash_ver == 133)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_2,
|
|
sizeof(patch_flash_2));
|
|
else
|
|
Error("EFLASHV123_4: invalid version");
|
|
break;
|
|
case EFLASHV123_5:
|
|
if (flash_ver == 123 || flash_ver == 124 || flash_ver == 125 ||
|
|
flash_ver == 126)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_6,
|
|
sizeof(patch_flash_6));
|
|
else
|
|
Error("EFLASHV123_5: invalid version");
|
|
break;
|
|
case EFLASH512_1:
|
|
if (flash_ver == 130 || flash_ver == 131 || flash_ver == 133)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_5,
|
|
sizeof(patch_flash_5));
|
|
else
|
|
Error("EFLASH512_1: invalid version");
|
|
break;
|
|
case EFLASH512_2:
|
|
if (flash_ver == 130 || flash_ver == 131 || flash_ver == 133)
|
|
iWriter->Write(iPatchInfo[ii].iOffset * 4, patch_flash_6,
|
|
sizeof(patch_flash_6));
|
|
else
|
|
Error("EFLASH512_2: invalid version");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
bool CGbaPatcher::PatchSleep(void) {
|
|
test_printf("CGbaPatcher::PatchSleep\n");
|
|
bool res = false;
|
|
const u32 baldur_style = 0;
|
|
const u32 rayman3_style = 10;
|
|
const u32 zelda2_style = 16;
|
|
const u32 mario_style = 33;
|
|
const u32 drilldozer_style = 47;
|
|
const u32 drmario_style = 48;
|
|
const u32 coloris_style = 50;
|
|
const u32 dialhex_style = 51;
|
|
const u32 goldensun2_style = 52;
|
|
const u32 nes_style = 57;
|
|
const u32 goldensun_e_style = 69;
|
|
const u32 goldensun_style = 70;
|
|
const u32 prince_style = 74;
|
|
const u32 scurge_style = 76;
|
|
const u32 game_codes[] = {
|
|
// 0
|
|
0x50444742, // Baldur's Gate - Dark Alliance (Europe) (En,Fr,De,Es,It).gba
|
|
0x45444742, // Baldur's Gate - Dark Alliance (USA).gba
|
|
0x45574342, // Catwoman (USA, Europe) (En,Fr,De,Es,It,Nl).gba
|
|
0x50434142, // Action Man - Robot Atak (Europe) (En,Fr,De,Es,It).gba
|
|
0x45384842, // Harry Potter and the Goblet of Fire (USA, Europe)
|
|
// (En,Fr,De,Es,It,Nl,Da).gba
|
|
0x45385242, // Ghost Rider (USA, Europe) (En,Fr,De,Es,It,Nl).gba
|
|
0x50373242, // Top Spin 2 (Europe) (En,Fr,De,Es,It).gba
|
|
0x45373242, // Top Spin 2 (USA) (En,Fr,De,Es,It).gba
|
|
0x45504842, // Harry Potter - Quidditch World Cup (USA, Europe)
|
|
// (En,Fr,De,Es,It,Nl,Da).gba
|
|
0x4A504842, // Harry Potter - Quidditch World Cup (Japan).gba
|
|
// 10
|
|
0x505a5941, // Rayman 3 (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da,Fi).gba
|
|
0x455a5941, // Rayman 3 (USA) (En,Fr,Es).gba
|
|
0x50355842, // Rayman 10th Anniversary - Rayman Advance + Rayman 3 (Europe)
|
|
// (En,Fr,De,Es,It+En,Fr,De,Es,It,Nl,Sv,No,Da,Fi).gba
|
|
0x45355842, // Rayman 10th Anniversary - Rayman Advance + Rayman 3 (USA)
|
|
// (En,Fr,De,Es,It+En,Fr,Es).gba
|
|
0x505A5742, // 2 Games in 1 - Winnie the Pooh's Rumbly Tumbly Adventure + Rayman 3
|
|
// (Europe) (En,Fr,De,Es,It,Nl+En,Fr,De,Es,It,Nl,Sv,No,Da,Fi).gba
|
|
0x4a553341, // Mother 3 (Japan).gba
|
|
// 16
|
|
0x50584d42, // Metroid - Zero Mission (Europe) (En,Fr,De,Es,It).gba
|
|
0x4a584d42, // Metroid - Zero Mission (Japan).gba
|
|
0x45584d42, // Metroid - Zero Mission (USA).gba
|
|
0x43584d42, // Miteluode - Lingdian Renwu (China).gba
|
|
0x504d5a42, // Legend of Zelda, The - The Minish Cap (Europe) (En,Fr,De,Es,It).gba
|
|
0x454d5a42, // Legend of Zelda, The - The Minish Cap (USA).gba
|
|
0x45485a42, // Legend of Zelda, The - The Minish Cap (USA) (Kiosk Demo).gba
|
|
0x4a4d5a42, // Zelda no Densetsu - Fushigi no Boushi (Japan).gba
|
|
0x50544d41, // Metroid Fusion (Europe) (En,Fr,De,Es,It).gba
|
|
0x4a544d41, // Metroid Fusion (Japan).gba
|
|
0x45544d41, // Metroid Fusion (USA, Australia).gba
|
|
0x43544d41, // Miteluode Ronghe (China).gba
|
|
0x504c5a41, // Legend of Zelda, The - A Link to the Past & Four Swords (Europe)
|
|
// (En,Fr,De,Es,It).gba
|
|
0x454c5a41, // Legend of Zelda, The - A Link to the Past & Four Swords (USA,
|
|
// Australia).gba
|
|
0x4a4c5a41, // Zelda no Densetsu - Kamigami no Triforce & 4tsu no Tsurugi (Japan).gba
|
|
0x4a324141, // Super Mario Advance 2 - Super Mario World + Mario Brothers (Japan).gba
|
|
0x45383842, // Mario & Luigi - Superstar Saga (USA) (Kiosk Demo).gba
|
|
// 33
|
|
0x50413341, // Super Mario Advance 3 - Yoshi's Island (Europe) (En,Fr,De,Es,It).gba
|
|
0x45413341, // Super Mario Advance 3 - Yoshi's Island (USA).gba
|
|
0x4a413341, // Super Mario Advance 3 - Yoshi's Island + Mario Brothers (Japan).gba
|
|
0x43413341, // Yaoxi Dao (China).gba
|
|
0x4a345841, // Super Mario Advance 4 - Super Mario 3 + Mario Brothers (Japan).gba
|
|
0x4a345841, // Super Mario Advance 4 - Super Mario 3 + Mario Brothers (Japan) (Rev
|
|
// 2).gba
|
|
0x50345841, // Super Mario Advance 4 - Super Mario Bros. 3 (Europe)
|
|
// (En,Fr,De,Es,It).gba
|
|
0x50345841, // Super Mario Advance 4 - Super Mario Bros. 3 (Europe) (En,Fr,De,Es,It)
|
|
// (Rev 1).gba
|
|
0x45345841, // Super Mario Advance 4 - Super Mario Bros. 3 (USA).gba
|
|
0x45345841, // Super Mario Advance 4 - Super Mario Bros. 3 (USA, Australia) (Rev 1).gba
|
|
0x50383841, // Mario & Luigi - Superstar Saga (Europe) (En,Fr,De,Es,It).gba
|
|
0x45383841, // Mario & Luigi - Superstar Saga (USA, Australia).gba
|
|
0x4a383841, // Mario & Luigi RPG (Japan).gba
|
|
0x4a345841, // Super Mario Advance 4 - Super Mario 3 + Mario Brothers (Japan) (Rev
|
|
// 1).gba
|
|
// 47
|
|
0x45393456, // Drill Dozer (USA).gba
|
|
// 48
|
|
0x50505a42, // 2 Games in 1 - Dr. Mario & Puzzle League (Europe) (En,Fr,De,Es,It).gba
|
|
0x45505a42, // 2 Games in 1 - Dr. Mario & Puzzle League (USA, Australia).gba
|
|
// 50
|
|
0x4a415642, // bit Generations - Coloris (Japan).gba
|
|
// 51
|
|
0x4a425642, // bit Generations - Dialhex (Japan).gba
|
|
// 52
|
|
0x45464741, // Golden Sun - The Lost Age (USA, Europe).gba
|
|
0x44464741, // Golden Sun - Die vergessene Epoche (Germany).gba
|
|
0x46464741, // Golden Sun - L'Age Perdu (France).gba
|
|
0x49464741, // Golden Sun - L'Era Perduta (Italy).gba
|
|
0x53464741, // Golden Sun - La Edad Perdida (Spain).gba
|
|
// 57
|
|
0x454d4246, // Classic NES Series - Bomberman (USA, Europe).gba
|
|
0x45444146, // Classic NES Series - Castlevania (USA, Europe).gba
|
|
0x454b4446, // Classic NES Series - Donkey Kong (USA, Europe).gba
|
|
0x454d4446, // Classic NES Series - Dr. Mario (USA, Europe).gba
|
|
0x45424546, // Classic NES Series - Excitebike (USA, Europe).gba
|
|
0x45434946, // Classic NES Series - Ice Climber (USA, Europe).gba
|
|
0x454c5a46, // Classic NES Series - Legend of Zelda (USA, Europe).gba
|
|
0x45524d46, // Classic NES Series - Metroid (USA, Europe).gba
|
|
0x45375046, // Classic NES Series - Pac-Man (USA, Europe).gba
|
|
0x454d5346, // Classic NES Series - Super Mario Bros. (USA, Europe).gba
|
|
0x45565846, // Classic NES Series - Xevious (USA, Europe).gba
|
|
0x45424c46, // Classic NES Series - Zelda II - The Adventure of Link (USA, Europe).gba
|
|
// 69
|
|
0x45534741, // Golden Sun (USA, Europe).gba
|
|
// 70
|
|
0x46534741, // Golden Sun (France).gba
|
|
0x44534741, // Golden Sun (Germany).gba
|
|
0x49534741, // Golden Sun (Italy).gba
|
|
0x53534741, // Golden Sun (Spain).gba
|
|
// 74
|
|
0x50595042, // Prince of Persia - The Sands of Time (Europe) (En,Fr,De,Es,It,Nl).gba
|
|
0x45595042, // Prince of Persia - The Sands of Time (USA) (En,Fr,Es).gba
|
|
// 76
|
|
0x50564842, // Scurge - Hive (Europe) (En,Fr,De,Es,It).gba
|
|
0x45564842 // Scurge - Hive (USA) (En,Fr,Es).gba
|
|
// 78
|
|
};
|
|
const u8 game_rev[] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // baldur style
|
|
0, 0, 0, 0, 0, 0, // rayman3 style
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // zelda2 style
|
|
0, 0, 0, 0, 0, 2, 0, 1, 0, 1, 0, 0, 0, 1, // mario style
|
|
0, // drilldozer style
|
|
0, 0, // drmario style
|
|
0, // coloris
|
|
0, // dialhex
|
|
0, 0, 0, 0, 0, // goldensun2 style
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // nes style
|
|
0, 0, 0, 0, 0, // goldensun style
|
|
0, 0, // prince style
|
|
0, 0 // scurge - hive
|
|
};
|
|
CHECK_SIZEOF(game_codes, 78 * 4);
|
|
CHECK_SIZEOF(game_rev, 78);
|
|
const u32 offsets_baldur[] = {0x6a32b4, 0x6a32b8, 0x2e320, 0x29f98, 0x6012c,
|
|
0x2e19c, 0x5e744, 0x5e780, 0x5e07a2, 0x5e07a2};
|
|
const u8 patch_sleep_baldur[] = {
|
|
0x08, 0x46 // MOV R0, R1
|
|
};
|
|
const u32 offsets_rayman3[] = {0x15aba, 0x15aca, 0x15ac2, 0x15ad2, 0x815aba, 0x188e};
|
|
const u8 patch_sleep_rayman3[] = {
|
|
0x40, 0x22 // MOV R2, #0x40
|
|
};
|
|
const u32 offsets_zelda2[] = {0x721f4, 0x720c4, 0x720a8, 0x75350, 0x55e04, 0x56284,
|
|
0x561dc, 0x56108, 0x7ee26, 0x7f72a, 0x7ee26, 0x7f72a,
|
|
0x68f1e, 0x68352, 0x68e8a, 0x4ca, 0x366e};
|
|
const u8 patch_sleep_zelda2[] = {
|
|
0x40, 0x21 // MOV R1, #0x40
|
|
};
|
|
const u32 offsets_mario[] = {
|
|
0x2a1c, 0xfd9d2, 0x2978, 0xfb8e6, 0x2978, 0xfb686, 0x2978,
|
|
0xfc02e, 0x56e, 0xb4ea8, 0x56e, 0xb67b8, 0x56e, 0xb9220,
|
|
0x56e, 0xb9700, 0x56e, 0xb61c0, 0x56e, 0xb68a0, 0x18aae,
|
|
0xf504c4, 0x18a9a, 0xf504c4, 0x18aae, 0xf504c4, 0x56e, 0xb6368,
|
|
};
|
|
const u8 patch_sleep_drilldozer[] = {
|
|
0x40, 0x23 // MOV R3, #0x40
|
|
};
|
|
const u8 patch_sleep_drilldozer2[] = {
|
|
0x30, 0x88 // LDRH R0, [R6]
|
|
};
|
|
const u32 offsets_drmario[] = {0x91830, 0x422d0a, 0x91830, 0x41b5d0};
|
|
const u8 patch_sleep_puzzleleague[] = {
|
|
0x88, 0x21 // MOV R1, #0x88
|
|
};
|
|
const u8 patch_sleep_drmario[] = {
|
|
0xc0, 0x46 // NOP
|
|
};
|
|
const u8 patch_sleep_coloris1[] = {
|
|
0xc0, 0x1a // SUB R0, R0, R3
|
|
};
|
|
const u8 patch_sleep_coloris2[] = {
|
|
0x40, 0x18 // ADD R0, R0, R1
|
|
};
|
|
const u8 patch_sleep_coloris3[] = {
|
|
0x00, 0x10 // DCD 0x1000
|
|
};
|
|
const u8 patch_sleep_dialhex1[] = {
|
|
0x2f, 0x88 // LDRH R7, [R5]
|
|
};
|
|
const u8 patch_sleep_dialhex2[] = {
|
|
0x10, 0x1c, // ADD R0, R2, #0
|
|
0xc0, 0x46 // NOP
|
|
};
|
|
const u8 patch_sleep_dialhex3[] = {
|
|
0x38, 0x1c, // ADD R0, R7, #0
|
|
0x00, 0x27, // MOV R7, #0
|
|
0x17, 0x80, // STRH R7, [R2]
|
|
0xc0, 0x46 // NOP
|
|
};
|
|
const u32 offsets_goldensun2[] = {0x137ac, 0x17270, 0x137d8, 0x1729c};
|
|
const u8 patch_sleep_goldensun2[] = {
|
|
0x03, 0xf0, 0x64, 0xfd, // BL xxx
|
|
0x03, 0xdf, // SWI 3
|
|
0x03, 0xf0, 0x63, 0xfd // BL yyy
|
|
};
|
|
const u8 patch_sleep_common[] = {
|
|
0x00, 0x20, // MOV R0, #0
|
|
0x00, 0xe0, // B loc_6
|
|
0x01, 0x20, // MOV R0, #1
|
|
// loc_6:
|
|
0x03, 0x4b, // LDR R3, =0x4000200
|
|
0x03, 0x49, // LDR R1, =0x2000
|
|
0x1a, 0x88, // LDRH R2, [R3]
|
|
0x4a, 0x40, // EOR R2, R1
|
|
0x1a, 0x80, // STRH R2, [R3]
|
|
0x19, 0xdf, // SWI 0x19
|
|
0x70, 0x47, // BX LR
|
|
0x00, 0x02, 0x00, 0x04, // dword_14 DCD 0x4000200
|
|
0x00, 0x20, 0x00, 0x00 // dword_18 DCD 0x2000
|
|
|
|
};
|
|
const u32 offsets_nes[] = {0xbf8, 0x1788, 0x870, 0xc54, 0x7ec, 0x85c,
|
|
0xac4, 0xb78, 0xb10, 0x85c, 0x9b8, 0x2e2c};
|
|
const u8 patch_sleep_nes1[] = {
|
|
0x00, 0x00, 0x9f, 0xe5, // LDR R0, =0x80FFB40
|
|
0x10, 0xff, 0x2f, 0xe1, // BX R0
|
|
0x40, 0xfb, 0x0f, 0x08 // DCD 0x80FFB40
|
|
};
|
|
const u8 patch_sleep_nes2[] = {
|
|
0x30, 0x40, 0x2d, 0xe9, // STMFD SP!, {R4,R5,LR}
|
|
0x28, 0x50, 0x9f, 0xe5, // LDR R5, =0x4000200
|
|
0x01, 0x3a, 0xa0, 0xe3, // MOV R3, #0x1000
|
|
0xb0, 0x40, 0xd5, 0xe1, // LDRH R4, [R5]
|
|
0xb0, 0x30, 0xc5, 0xe1, // STRH R3, [R5]
|
|
0x00, 0x00, 0xa0, 0xe3, // MOV R0, #0
|
|
0x00, 0x00, 0x19, 0xef, // SWI 0x190000
|
|
0x00, 0x00, 0x03, 0xef, // SWI 0x30000
|
|
0x01, 0x00, 0xa0, 0xe3, // MOV R0, #1
|
|
0x00, 0x00, 0x19, 0xef, // SWI 0x190000
|
|
0xb0, 0x40, 0xc5, 0xe1, // STRH R4, [R5]
|
|
0x30, 0x40, 0xbd, 0xe8, // LDMFD SP!, {R4,R5,LR}
|
|
0x1e, 0xff, 0x2f, 0xe1, // BX LR
|
|
0x00, 0x02, 0x00, 0x04 // DCD 0x4000200
|
|
};
|
|
const u32 offsets_goldensun[] = {0x33fe, 0x6cec, 0x341e, 0x6d0c,
|
|
0x342e, 0x6d1c, 0x344e, 0x6d3c};
|
|
const u8 patch_sleep_goldensun[] = {
|
|
0x03, 0xf0, 0x79, 0xfc, // BL xxx
|
|
0x03, 0xdf, // SWI 3
|
|
0x03, 0xf0, 0x78, 0xfc // BL yyy
|
|
};
|
|
const u32 offsets_prince[] = {0x72a40, 0x72a40};
|
|
const u8 patch_sleep_prince[] = {
|
|
0x40, 0x26 // MOV R6, #0x40
|
|
};
|
|
s32 index = -1;
|
|
u32 code = Data()[43];
|
|
u8 rev = (Data()[47]) & 0xff;
|
|
for (u32 ii = 0; ii < sizeofa(game_codes); ii++) {
|
|
if (code == game_codes[ii] && rev == game_rev[ii]) {
|
|
index = ii;
|
|
break;
|
|
}
|
|
}
|
|
if (index != -1) {
|
|
res = true;
|
|
switch (index) {
|
|
case baldur_style:
|
|
case baldur_style + 1:
|
|
case baldur_style + 2:
|
|
case baldur_style + 3:
|
|
case baldur_style + 4:
|
|
case baldur_style + 5:
|
|
case baldur_style + 6:
|
|
case baldur_style + 7:
|
|
case baldur_style + 8:
|
|
case baldur_style + 9:
|
|
iWriter->Write(offsets_baldur[index - baldur_style], patch_sleep_baldur,
|
|
sizeof(patch_sleep_baldur));
|
|
break;
|
|
case rayman3_style:
|
|
case rayman3_style + 1:
|
|
case rayman3_style + 2:
|
|
case rayman3_style + 3:
|
|
case rayman3_style + 4:
|
|
case rayman3_style + 5:
|
|
iWriter->Write(offsets_rayman3[index - rayman3_style], patch_sleep_rayman3,
|
|
sizeof(patch_sleep_rayman3));
|
|
break;
|
|
case zelda2_style:
|
|
case zelda2_style + 1:
|
|
case zelda2_style + 2:
|
|
case zelda2_style + 3:
|
|
case zelda2_style + 4:
|
|
case zelda2_style + 5:
|
|
case zelda2_style + 6:
|
|
case zelda2_style + 7:
|
|
case zelda2_style + 8:
|
|
case zelda2_style + 9:
|
|
case zelda2_style + 10:
|
|
case zelda2_style + 11:
|
|
case zelda2_style + 12:
|
|
case zelda2_style + 13:
|
|
case zelda2_style + 14:
|
|
case zelda2_style + 15:
|
|
case zelda2_style + 16:
|
|
iWriter->Write(offsets_zelda2[index - zelda2_style], patch_sleep_zelda2,
|
|
sizeof(patch_sleep_zelda2));
|
|
break;
|
|
case mario_style:
|
|
case mario_style + 1:
|
|
case mario_style + 2:
|
|
case mario_style + 3:
|
|
case mario_style + 4:
|
|
case mario_style + 5:
|
|
case mario_style + 6:
|
|
case mario_style + 7:
|
|
case mario_style + 8:
|
|
case mario_style + 9:
|
|
case mario_style + 10:
|
|
case mario_style + 11:
|
|
case mario_style + 12:
|
|
case mario_style + 13: {
|
|
u32 pos = (index - mario_style) * 2;
|
|
iWriter->Write(offsets_mario[pos++], patch_sleep_zelda2,
|
|
sizeof(patch_sleep_zelda2));
|
|
iWriter->Write(offsets_mario[pos], patch_sleep_zelda2, sizeof(patch_sleep_zelda2));
|
|
} break;
|
|
case drilldozer_style: {
|
|
u32 pos = 0x2bd70;
|
|
iWriter->Write(pos, patch_sleep_drilldozer, sizeof(patch_sleep_drilldozer));
|
|
iWriter->Write(pos + 6, patch_sleep_baldur, sizeof(patch_sleep_baldur));
|
|
iWriter->Write(pos + 104, patch_sleep_drilldozer2, sizeof(patch_sleep_drilldozer2));
|
|
} break;
|
|
case drmario_style:
|
|
case drmario_style + 1: {
|
|
u32 pos = (index - drmario_style) * 2;
|
|
iWriter->Write(offsets_drmario[pos++], patch_sleep_puzzleleague,
|
|
sizeof(patch_sleep_puzzleleague));
|
|
iWriter->Write(offsets_drmario[pos], patch_sleep_drmario,
|
|
sizeof(patch_sleep_drmario));
|
|
} break;
|
|
case coloris_style:
|
|
iWriter->Write(0x7fd8, patch_sleep_coloris1, sizeof(patch_sleep_coloris1));
|
|
iWriter->Write(0x7fda, patch_sleep_drmario, sizeof(patch_sleep_drmario));
|
|
iWriter->Write(0x7ff8, patch_sleep_coloris2, sizeof(patch_sleep_coloris2));
|
|
iWriter->Write(0x803c, patch_sleep_coloris3, sizeof(patch_sleep_coloris3));
|
|
break;
|
|
case dialhex_style:
|
|
iWriter->Write(0x7f1e, patch_sleep_dialhex1, sizeof(patch_sleep_dialhex1));
|
|
iWriter->Write(0x7f24, patch_sleep_dialhex2, sizeof(patch_sleep_dialhex2));
|
|
iWriter->Write(0x7f46, patch_sleep_dialhex3, sizeof(patch_sleep_dialhex3));
|
|
break;
|
|
case goldensun2_style:
|
|
case goldensun2_style + 1:
|
|
case goldensun2_style + 2:
|
|
case goldensun2_style + 3:
|
|
case goldensun2_style + 4: {
|
|
u32 pos = (index - goldensun2_style) ? 2 : 0;
|
|
res = false;
|
|
for (u32 ii = 0; ii < iCount; ii++) {
|
|
if (iPatchInfo[ii].iType == EFLASHV123_3 &&
|
|
iPatchInfo[ii].iOffset * 4 == offsets_goldensun2[pos + 1]) {
|
|
res = true;
|
|
iWriter->Write(offsets_goldensun2[pos++], patch_sleep_goldensun2,
|
|
sizeof(patch_sleep_goldensun2));
|
|
iWriter->Write(offsets_goldensun2[pos] + 8, patch_sleep_common,
|
|
sizeof(patch_sleep_common));
|
|
}
|
|
}
|
|
} break;
|
|
case nes_style:
|
|
case nes_style + 1:
|
|
case nes_style + 2:
|
|
case nes_style + 3:
|
|
case nes_style + 4:
|
|
case nes_style + 5:
|
|
case nes_style + 6:
|
|
case nes_style + 7:
|
|
case nes_style + 8:
|
|
case nes_style + 9:
|
|
case nes_style + 10:
|
|
case nes_style + 11:
|
|
iWriter->Write(offsets_nes[index - nes_style], patch_sleep_nes1,
|
|
sizeof(patch_sleep_nes1));
|
|
iWriter->Write(0xffb40, patch_sleep_nes2, sizeof(patch_sleep_nes2));
|
|
break;
|
|
case goldensun_e_style:
|
|
// yep, bug in game, no any patching needed :)
|
|
break;
|
|
case goldensun_style: // goldensun style
|
|
case goldensun_style + 1:
|
|
case goldensun_style + 2:
|
|
case goldensun_style + 3: {
|
|
u32 pos = (index - goldensun_style) * 2;
|
|
res = false;
|
|
for (u32 ii = 0; ii < iCount; ii++) {
|
|
if (iPatchInfo[ii].iType == EFLASHV123_3 &&
|
|
iPatchInfo[ii].iOffset * 4 == offsets_goldensun[pos + 1]) {
|
|
res = true;
|
|
iWriter->Write(offsets_goldensun[pos++], patch_sleep_goldensun,
|
|
sizeof(patch_sleep_goldensun));
|
|
iWriter->Write(offsets_goldensun[pos] + 8, patch_sleep_common,
|
|
sizeof(patch_sleep_common));
|
|
}
|
|
}
|
|
} break;
|
|
case prince_style:
|
|
case prince_style + 1:
|
|
iWriter->Write(offsets_prince[index - prince_style], patch_sleep_prince,
|
|
sizeof(patch_sleep_prince));
|
|
iWriter->Write(offsets_prince[index - prince_style] + 6, patch_sleep_baldur,
|
|
sizeof(patch_sleep_baldur));
|
|
break;
|
|
case scurge_style:
|
|
case scurge_style + 1: {
|
|
u8 byte = 0x10;
|
|
iWriter->Write(0x6349, &byte, sizeof(byte));
|
|
} break;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
void CGbaPatcher::PatchEEPROM111(void) {
|
|
const u32 game_codes[] = {
|
|
0x4a414d41, // 0002
|
|
0x45485441, // 0033
|
|
0x45595241, // 0046
|
|
0x50595241, // 0051
|
|
0x44485441, // 0053
|
|
0x46485441 // 0059
|
|
};
|
|
const u32 patch_1_offsets[] = {0xb666c, 0x37570, 0x485ec, 0x485ec, 0x37580, 0x37520};
|
|
const u32 patch_1_data[] = {0x083eba71, 0x087ffaf1, 0x087b75b1,
|
|
0x087b71a1, 0x087ff641, 0x087fe2a1};
|
|
const u32 patch_2_offsets[] = {0xb6940, 0x37844, 0x488c0, 0x488c0, 0x37854, 0x377f4};
|
|
const u32 patch_3_offsets[] = {0x3eba70, 0x7ffaf0, 0x7b75b0, 0x7b71a0, 0x7ff640, 0x7fe2a0};
|
|
const u32 patch_3_data[] = {0x080b668d, 0x08037591, 0x0804860d,
|
|
0x0804860d, 0x080375a1, 0x08037541};
|
|
const u8 patch_3[] = {
|
|
0x39, 0x68, 0x27, 0x48, 0x81, 0x42, 0x23, 0xd0, 0x89, 0x1c, 0x08, 0x88, 0x01, 0x28,
|
|
0x02, 0xd1, 0x24, 0x48, 0x78, 0x60, 0x33, 0xe0, 0x00, 0x23, 0x00, 0x22, 0x89, 0x1c,
|
|
0x10, 0xb4, 0x01, 0x24, 0x08, 0x68, 0x20, 0x40, 0x5b, 0x00, 0x03, 0x43, 0x89, 0x1c,
|
|
0x52, 0x1c, 0x06, 0x2a, 0xf7, 0xd1, 0x10, 0xbc, 0x39, 0x60, 0xdb, 0x01, 0x02, 0x20,
|
|
0x00, 0x02, 0x1b, 0x18, 0x0e, 0x20, 0x00, 0x06, 0x1b, 0x18, 0x7b, 0x60, 0x39, 0x1c,
|
|
0x08, 0x31, 0x08, 0x88, 0x09, 0x38, 0x08, 0x80, 0x16, 0xe0, 0x15, 0x49, 0x00, 0x23,
|
|
0x00, 0x22, 0x10, 0xb4, 0x01, 0x24, 0x08, 0x68, 0x20, 0x40, 0x5b, 0x00, 0x03, 0x43,
|
|
0x89, 0x1c, 0x52, 0x1c, 0x06, 0x2a, 0xf7, 0xd1, 0x10, 0xbc, 0xdb, 0x01, 0x02, 0x20,
|
|
0x00, 0x02, 0x1b, 0x18, 0x0e, 0x20, 0x00, 0x06, 0x1b, 0x18, 0x08, 0x3b, 0x3b, 0x60,
|
|
0x0b, 0x48, 0x39, 0x68, 0x01, 0x60, 0x0a, 0x48, 0x79, 0x68, 0x01, 0x60, 0x0a, 0x48,
|
|
0x39, 0x1c, 0x08, 0x31, 0x0a, 0x88, 0x80, 0x21, 0x09, 0x06, 0x0a, 0x43, 0x02, 0x60,
|
|
0x07, 0x48, 0x00, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e,
|
|
0x04, 0x00, 0x00, 0x0e, 0xd4, 0x00, 0x00, 0x04, 0xd8, 0x00, 0x00, 0x04, 0xdc, 0x00,
|
|
0x00, 0x04};
|
|
|
|
s32 index = -1;
|
|
for (u32 ii = 0; ii < sizeofa(game_codes); ii++) {
|
|
if (Data()[43] == game_codes[ii] && Data()[patch_1_offsets[ii] / 4] == 0x6839480e) {
|
|
index = ii;
|
|
break;
|
|
}
|
|
}
|
|
if (index == -1) return;
|
|
u32 patch_1_2[2];
|
|
patch_1_2[0] = 0x47004800;
|
|
patch_1_2[1] = patch_1_data[index];
|
|
iWriter->Write(patch_1_offsets[index], (u8*)patch_1_2, sizeof(patch_1_2));
|
|
patch_1_2[0] = 0x20e0e027;
|
|
patch_1_2[1] = 0x88010500;
|
|
iWriter->Write(patch_2_offsets[index], (u8*)patch_1_2, sizeof(patch_1_2));
|
|
iWriter->Write(patch_3_offsets[index], patch_3, sizeof(patch_3));
|
|
iWriter->Write(patch_3_offsets[index] + sizeof(patch_3), (u8*)(patch_3_data + index),
|
|
sizeof(patch_3_data[0]));
|
|
}
|
|
|
|
bool CGbaPatcher::PatchDragonBallZ(void) {
|
|
bool res = false;
|
|
const u32 game_codes[] = {
|
|
0x45464c42, // 2 Games in 1 - Dragon Ball Z - The Legacy of Goku I & II (USA).gba
|
|
0x50474c41, // Dragon Ball Z - The Legacy of Goku (Europe) (En,Fr,De,Es,It).gba
|
|
0x45474c41, // Dragon Ball Z - The Legacy of Goku (USA).gba
|
|
0x50464c41, // Dragon Ball Z - The Legacy of Goku II (Europe) (En,Fr,De,Es,It).gba
|
|
0x45464c41, // Dragon Ball Z - The Legacy of Goku II (USA).gba
|
|
0x4a464c41 // Dragon Ball Z - The Legacy of Goku II International (Japan).gba
|
|
};
|
|
const u32 patch_1_offsets[] = {0x033C, 0x0340, 0x0356, 0x035A, 0x035E, 0x0384, 0x0388,
|
|
0x494C, 0x4950, 0x4978, 0x497C, 0x998E, 0x9992};
|
|
const u32 patch_2_offsets[] = {0x356, 0x35e, 0x37e, 0x382};
|
|
s32 index = -1;
|
|
for (u32 ii = 0; ii < sizeofa(game_codes); ii++) {
|
|
if (Data()[43] == game_codes[ii]) {
|
|
index = ii;
|
|
break;
|
|
}
|
|
}
|
|
if (index != -1) {
|
|
u16 patch = 0;
|
|
res = true;
|
|
switch (index) {
|
|
case 0: // 2in1 us
|
|
for (u32 ii = 0; ii < sizeofa(patch_2_offsets); ii++) {
|
|
iWriter->Write(patch_2_offsets[ii] + 0x40000, (u8*)&patch, sizeof(patch));
|
|
}
|
|
patch = 0x1001;
|
|
iWriter->Write(0xbb9016, (u8*)&patch, sizeof(patch));
|
|
break;
|
|
case 1: // I eu
|
|
patch = 0x46c0;
|
|
for (u32 ii = 0; ii < sizeofa(patch_1_offsets); ii++) {
|
|
iWriter->Write(patch_1_offsets[ii], (u8*)&patch, sizeof(patch));
|
|
}
|
|
break;
|
|
case 2: // I us
|
|
for (u32 ii = 0; ii < sizeofa(patch_2_offsets); ii++) {
|
|
iWriter->Write(patch_2_offsets[ii], (u8*)&patch, sizeof(patch));
|
|
}
|
|
break;
|
|
case 3: // II eu
|
|
patch = 0x1001;
|
|
iWriter->Write(0x6f42b2, (u8*)&patch, sizeof(patch));
|
|
break;
|
|
case 4: // II us
|
|
patch = 0x1001;
|
|
iWriter->Write(0x3b8e9e, (u8*)&patch, sizeof(patch));
|
|
break;
|
|
case 5: // II jp
|
|
patch = 0x1001;
|
|
iWriter->Write(0x3fc8f6, (u8*)&patch, sizeof(patch));
|
|
break;
|
|
default:
|
|
res = false;
|
|
break;
|
|
}
|
|
}
|
|
return res;
|
|
}
|