akmenu-next/arm9/source/gbapatcher.cpp
2024-10-04 22:35:39 -07:00

1830 lines
54 KiB
C++

/*
gbapatcher.cpp
Copyright (C) 2008-2009 somebody
Copyright (C) 2009 yellow wood goblin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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;
}