diosmios/Patches.c

875 lines
29 KiB
C

#include "Patches.h"
#include "CardPatches.c"
#include "DVDPatches.c"
#include "FwritePatches.c"
#include "CheatCode.c"
extern u32 DOLSize;
unsigned char OSReportDM[] =
{
0x7C, 0x08, 0x02, 0xA6, 0x90, 0x01, 0x00, 0x04, 0x90, 0xE1, 0x00, 0x08, 0x3C, 0xE0, 0xC0, 0x00,
0x90, 0x67, 0x18, 0x60, 0x90, 0x87, 0x18, 0x64, 0x90, 0xA7, 0x18, 0x68, 0x90, 0xC7, 0x18, 0x6C,
0x90, 0xE7, 0x18, 0x70, 0x91, 0x07, 0x18, 0x74, 0x80, 0x07, 0x18, 0x60, 0x7C, 0x00, 0x18, 0x00,
0x41, 0x82, 0xFF, 0xF8, 0x80, 0xE1, 0x00, 0x08, 0x80, 0x01, 0x00, 0x04, 0x7C, 0x08, 0x03, 0xA6,
0x4E, 0x80, 0x00, 0x20,
} ;
// Audio streaming replacement functions copied from Swiss r92
u32 __dvdLowAudioStatusNULL[17] = {
// execute function(1); passed in on r4
0x9421FFC0, // stwu sp, -0x0040 (sp)
0x7C0802A6, // mflr r0
0x90010000, // stw r0, 0 (sp)
0x7C8903A6, // mtctr r4
0x3C80CC00, // lis r4, 0xCC00
0x2E830000, // cmpwi cr5, r3, 0
0x4196000C, // beq- cr5, +0xC ?
0x38600001, // li r3, 1
0x48000008, // b +0x8 ?
0x38600000, // li r3, 0
0x90646020, // stw r3, 0x6020 (r4)
0x38600001, // li r3, 1
0x4E800421, // bctrl
0x80010000, // lwz r0, 0 (sp)
0x7C0803A6, // mtlr r0
0x38210040, // addi sp, sp, 64
0x4E800020 // blr
};
u32 __dvdLowAudioConfigNULL[10] = {
// execute callback(1); passed in on r5 without actually touching the drive!
0x9421FFC0, // stwu sp, -0x0040 (sp)
0x7C0802A6, // mflr r0
0x90010000, // stw r0, 0 (sp)
0x7CA903A6, // mtctr r5
0x38600001, // li r3, 1
0x4E800421, // bctrl
0x80010000, // lwz r0, 0 (sp)
0x7C0803A6, // mtlr r0
0x38210040, // addi sp, sp, 64
0x4E800020 // blr
};
u32 __dvdLowReadAudioNULL[] = {
// execute callback(1); passed in on r6 without actually touching the drive!
0x9421FFC0, // stwu sp, -0x0040 (sp)
0x7C0802A6, // mflr r0
0x90010000, // stw r0, 0 (sp)
0x7CC903A6, // mtctr r6
0x38600001, // li r3, 1
0x4E800421, // bctr;
0x80010000, // lwz r0, 0 (sp)
0x7C0803A6, // mtlr r0
0x38210040, // addi sp, sp, 64
0x4E800020
};
u32 __GXSetVAT_patch[31] = {
/*0x8122ce00,*/ 0x39400000, 0x896904f2, 0x7d284b78,
0x556007ff, 0x41820050, 0x38e00008, 0x3cc0cc01,
0x98e68000, 0x61400070, 0x61440080, 0x61430090,
0x98068000, 0x38000000, 0x80a8001c, 0x90a68000,
0x98e68000, 0x98868000, 0x8088003c, 0x90868000,
0x98e68000, 0x98668000, 0x8068005c, 0x90668000,
0x98068000, 0x556bf87f, 0x394a0001, 0x39080004,
0x4082ffa0, 0x38000000, 0x980904f2, 0x4e800020
};
FuncPattern FPatterns[] =
{
{ 0xCC, 17, 10, 5, 3, 2, DVDInquiryAsync, sizeof(DVDInquiryAsync), "DVDInquiryAsync", 0, 0 },
{ 0xC8, 16, 9, 5, 3, 3, DVDSeekAbsAsyncPrio, sizeof(DVDSeekAbsAsyncPrio), "DVDSeekAbsAsyncPrio", 0, 0 },
{ 0xD4, 13, 8, 11, 2, 7, (u8*)NULL, 0xdead0004, "AIResetStreamSampleCount", 0, 0 },
{ 0x94, 18, 10, 2, 0, 2, (u8*)__dvdLowReadAudioNULL, sizeof(__dvdLowReadAudioNULL), "DVDLowReadAudio", 0, 0 },
{ 0x88, 18, 8, 2, 0, 2, (u8*)__dvdLowAudioStatusNULL, sizeof(__dvdLowAudioStatusNULL), "DVDLowAudioStatus", 0, 0 },
{ 0x98, 19, 8, 2, 1, 3, (u8*)__dvdLowAudioConfigNULL, sizeof(__dvdLowAudioConfigNULL), "DVDLowAudioConfig", 0, 0 },
{ 0x308, 40, 18, 10, 23, 17, patch_fwrite_GC, sizeof(patch_fwrite_GC), "__fwrite A", 1, 0 },
{ 0x338, 48, 20, 10, 24, 16, patch_fwrite_GC, sizeof(patch_fwrite_GC), "__fwrite B", 1, 0 },
{ 0x2D8, 41, 17, 8, 21, 13, patch_fwrite_GC, sizeof(patch_fwrite_GC), "__fwrite C", 1, 0 },
{ 0x98, 8, 3, 0, 3, 5, (u8*)NULL, 0xdead0001, "__GXSetVAT", 0, 0 },
{ 0x3A8, 86, 13, 27, 17, 24, (u8*)NULL, 0xdead000B, "PADRead A", 2, 0 },
{ 0x2FC, 73, 8, 23, 16, 15, (u8*)NULL, 0xdead000B, "PADRead B", 2, 0 },
{ 0x3B0, 87, 13, 27, 17, 25, (u8*)NULL, 0xdead000B, "PADRead C", 2, 0 },
{ 0x334, 78, 7, 20, 17, 19, (u8*)NULL, 0xdead000B, "PADRead D", 2, 0 },
};
FuncPattern CPatterns[] =
{
{ 0x14C, 28, 12, 7, 12, 4, CARDFreeBlocks, sizeof(CARDFreeBlocks), "CARDFreeBlocks A", 1, 0 },
{ 0x11C, 24, 10, 7, 10, 4, CARDFreeBlocks, sizeof(CARDFreeBlocks), "CARDFreeBlocks B", 1, 0 },
{ 0xC0, 22, 5, 2, 5, 10, CARDGetSerialNo, sizeof(CARDGetSerialNo),"CARDGetSerialNo", 0, 0 },
{ 0x84, 12, 5, 3, 4, 2, CARDGetEncoding, sizeof(CARDGetEncoding),"CARDGetEncoding", 0, 0 },
{ 0x80, 11, 5, 3, 4, 2, CARDGetMemSize, sizeof(CARDGetMemSize), "CARDGetMemSize", 0, 0 },
{ 0x94, 11, 6, 3, 5, 4, __CARDSync, sizeof(__CARDSync), "__CARDSync", 0, 0 },
{ 0x50, 6, 3, 2, 2, 2, CARDCheck, sizeof(CARDCheck), "CARDCheck", 0, 0 },
//{ 0x24, 4, 2, 1, 0, 2, CARDCheckAsync, sizeof(CARDCheckAsync), "CARDCheckAsync", 0, 0 },
{ 0x58C, 82, 11, 18, 41, 57, CARDCheckEX, sizeof(CARDCheckEX), "CARDCheckExAsync", 0, 0 },
{ 0x34, 4, 2, 1, 2, 2, CARDProbe, sizeof(CARDProbe), "CARDProbe", 2, 0 },
//{ 0x1C, 2, 2, 1, 0, 2, CARDProbe, sizeof(CARDProbe), "CARDProbe B", 2, 0 }, //This is causing more trouble than a hack...
{ 0x178, 20, 6, 6, 20, 4, CARDProbeEX, sizeof(CARDProbeEX), "CARDProbeEx A", 3, 0 },
{ 0x198, 22, 6, 5, 19, 4, CARDProbeEX, sizeof(CARDProbeEX), "CARDProbeEx B", 3, 0 },
{ 0x160, 17, 6, 5, 18, 4, CARDProbeEX, sizeof(CARDProbeEX), "CARDProbeEx C", 3, 0 },
{ 0x19C, 32, 14, 11, 12, 3, CARDMountAsync, sizeof(CARDMountAsync), "CARDMountAsync A", 4, 0 },
{ 0x184, 30, 14, 11, 10, 3, CARDMountAsync, sizeof(CARDMountAsync), "CARDMountAsync B", 4, 0 },
{ 0xA8, 15, 8, 6, 3, 2, CARDCheck, sizeof(CARDCheck), "CARDUnMount", 0, 0 },
{ 0x174, 23, 6, 7, 14, 5, CARDOpen, sizeof(CARDOpen), "CARDOpen A", 5, 0 },
{ 0x118, 14, 6, 6, 11, 4, CARDOpen, sizeof(CARDOpen), "CARDOpen B", 5, 0 },
{ 0x170, 23, 6, 7, 14, 5, CARDOpen, sizeof(CARDOpen), "CARDOpen C", 5, 0 },
{ 0x15C, 27, 6, 5, 15, 6, CARDFastOpen, sizeof(CARDFastOpen), "CARDFastOpen A", 11, 0 },
{ 0x100, 20, 10, 4, 10, 4, CARDFastOpen, sizeof(CARDFastOpen), "CARDFastOpen B", 11, 0 },
{ 0x50, 8, 4, 2, 2, 3, CARDClose, sizeof(CARDClose), "CARDClose", 0, 0 },
{ 0x21C, 44, 6, 13, 19, 12, CARDCreate, sizeof(CARDCreate), "CARDCreateAsync A", 6, 0 },
{ 0x214, 42, 6, 13, 19, 12, CARDCreate, sizeof(CARDCreate), "CARDCreateAsync B", 6, 0 },
{ 0x10C, 25, 6, 9, 9, 5, CARDDelete, sizeof(CARDDelete), "CARDDeleteAsync A", 12, 0 },
{ 0x10C, 25, 6, 9, 9, 5, CARDDelete, sizeof(CARDDelete), "CARDDeleteAsync C", 12, 0 },
{ 0x128, 24, 7, 9, 12, 5, CARDFastDelete, sizeof(CARDFastDelete), "CARDFastDelete", 0, 0 },
{ 0x144, 27, 3, 8, 10, 9, CARDRead, sizeof(CARDRead), "CARDReadAsync A", 7, 0 },
{ 0x140, 30, 7, 7, 10, 10, CARDRead, sizeof(CARDRead), "CARDReadAsync B", 7, 0 },
{ 0x140, 27, 3, 8, 10, 9, CARDRead, sizeof(CARDRead), "CARDReadAsync C", 7, 0 },
{ 0x110, 24, 4, 8, 9, 6, CARDWrite, sizeof(CARDWrite), "CARDWriteAsync A", 8, 0 },
{ 0x10C, 23, 4, 8, 9, 6, CARDWrite, sizeof(CARDWrite), "CARDWriteAsync B", 8, 0 },
{ 0x1F8, 37, 3, 17, 18, 9, CARDRename, sizeof(CARDRename), "CARDRenameAsync", 0, 0 },
{ 0x128, 25, 9, 9, 6, 5, CARDGetStats, sizeof(CARDGetStats), "CARDGetStatus A", 9, 0 },
{ 0x110, 25, 9, 8, 6, 5, CARDGetStats, sizeof(CARDGetStats), "CARDGetStatus B", 9, 0 },
{ 0x124, 25, 9, 9, 6, 5, CARDGetStats, sizeof(CARDGetStats), "CARDGetStatus C", 9, 0 },
{ 0x170, 29, 9, 9, 12, 5, CARDSetStats, sizeof(CARDSetStats), "CARDSetStatusAsync A", 10, 0 },
{ 0x16C, 29, 9, 9, 12, 5, CARDSetStats, sizeof(CARDSetStats), "CARDSetStatusAsync B", 10, 0 },
};
u32 CardLowestOff = 0;
void PatchB( u32 dst, u32 src )
{
u32 newval = (dst - src);
newval&= 0x03FFFFFC;
newval|= 0x48000000;
write32( src, newval );
}
void PatchBL( u32 dst, u32 src )
{
u32 newval = (dst - src);
newval&= 0x03FFFFFC;
newval|= 0x48000001;
write32( src, newval );
}
void MPattern( u8 *Data, u32 Length, FuncPattern *FunctionPattern )
{
u32 i;
memset( FunctionPattern, 0, sizeof(FuncPattern) );
for( i = 0; i < Length; i+=4 )
{
u32 word = read32( (u32)Data + i );
if( (word & 0xFC000003) == 0x48000001 )
FunctionPattern->FCalls++;
if( (word & 0xFC000003) == 0x48000000 )
FunctionPattern->Branch++;
if( (word & 0xFFFF0000) == 0x40800000 )
FunctionPattern->Branch++;
if( (word & 0xFFFF0000) == 0x41800000 )
FunctionPattern->Branch++;
if( (word & 0xFFFF0000) == 0x40810000 )
FunctionPattern->Branch++;
if( (word & 0xFFFF0000) == 0x41820000 )
FunctionPattern->Branch++;
if( (word & 0xFC000000) == 0x80000000 )
FunctionPattern->Loads++;
if( (word & 0xFF000000) == 0x38000000 )
FunctionPattern->Loads++;
if( (word & 0xFF000000) == 0x3C000000 )
FunctionPattern->Loads++;
if( (word & 0xFC000000) == 0x90000000 )
FunctionPattern->Stores++;
if( (word & 0xFC000000) == 0x94000000 )
FunctionPattern->Stores++;
if( (word & 0xFF000000) == 0x7C000000 )
FunctionPattern->Moves++;
if( word == 0x4E800020 )
break;
}
FunctionPattern->Length = i;
}
bool CPattern( FuncPattern *FPatA, FuncPattern *FPatB )
{
if( memcmp( FPatA, FPatB, sizeof(u32) * 6 ) == 0 )
return true;
else
return false;
}
void DoCardPatches( char *ptr, u32 size, u32 SectionOffset )
{
u32 i,j,k,offset,fail,FoundCardFuncStart=0;
dbgprintf("DoCardPatches( 0x%p, %d, 0x%X)\n", ptr, size, SectionOffset );
for( i=0; i < size; i+=4 )
{
if( read32( (u32)ptr + i) == 0x7C630214 && read32( (u32)ptr + i + 4) == 0x806300B8 )
{
dbgprintf("Found [CARDGetXferredBytes] @ 0x%08X\n", (u32)ptr + i - 12 );
memcpy( ptr + i - 12, CARDGetXferredBytes, sizeof(CARDGetXferredBytes) );
}
if( read32( (u32)ptr + i ) != 0x7C0802A6 ) // MFLR
continue;
FuncPattern fp;
MPattern( (u8*)(ptr+i), size, &fp );
for( j=0; j < sizeof(CPatterns)/sizeof(FuncPattern); ++j )
{
if( CPatterns[j].PatchLength == 0 )
continue;
if( CPatterns[j].Found ) // Skip already found patches
continue;
if( CPattern( &fp, &(CPatterns[j]) ) )
{
if( CPatterns[j].Patch == CARDFreeBlocks )
{
if( CardLowestOff == 0 )
{
dbgprintf("CardLowestOff:0x%08X\n", i );
CardLowestOff = i;
}
//Check for CARDGetResultCode which is always (when used) above CARDFreeBlocks
if( read32( (u32)ptr + i - 0x30 ) == 0x2C030000 )
{
dbgprintf("Found [CARDGetResultCode] @ 0x%08X\n", (u32)ptr + i - 0x30 + SectionOffset );
memcpy( ptr + i - 0x30, CARDGetResultCode, sizeof(CARDGetResultCode) );
}
FoundCardFuncStart = 1;
}
if( FoundCardFuncStart == 0 )
continue;
dbgprintf("Found [%s] @ 0x%08X\n", CPatterns[j].Name, (u32)ptr + i + SectionOffset );
CPatterns[j].Found = (u32)ptr + i;
// If this is a patch group set all others of this group as found aswell
if( CPatterns[j].Group )
{
for( k=0; k < sizeof(CPatterns)/sizeof(FuncPattern); ++k )
{
if( CPatterns[k].Group == CPatterns[j].Group )
{
if( !CPatterns[k].Found ) //Don't overwrite the offset!
CPatterns[k].Found = -1; // Usually this holds the offset, to determinate it from a REALLY found pattern we set it -1 which still counts a logical TRUE
//dbgprintf("Setting [%s] to found!\n", CPatterns[k].Name );
}
}
}
//If by now no CARDProbe is found it won't be so set it to found to prevent CARDProbe B false hits
if( CPatterns[j].Patch == CARDRead )
{
for( k=0; k < sizeof(CPatterns)/sizeof(FuncPattern); ++k )
{
if( CPatterns[k].Patch == CARDProbe )
{
if( !CPatterns[k].Found ) //Don't overwrite the offset!
CPatterns[k].Found = -1;
}
}
}
if( strstr( CPatterns[j].Name, "Async" ) != NULL )
{
//dbgprintf("Async!\n");
//Most games only use the normal functions so we patch a branch over to async and clear the CB
//Find function call to our function
offset = (u32)ptr + i;
fail = 0;
while(fail < 3)
{
//dbgprintf("[%08X] %08X %08X(%08X)\n", offset, read32( offset ) & 0xFC000003,read32( offset ) & 0x03FFFFFC ,(read32( offset ) & 0x03FFFFFC ) + offset);
if( (read32( offset ) & 0xFC000003 ) == 0x48000001 )
{
if( (((read32( offset ) & 0x03FFFFFC ) + offset) & 0x03FFFFFC) == (u32)ptr+i )
break;
}
if( read32( offset ) == 0x4E800020 )
fail++;
offset+=4;
}
if( fail < 3 )
{
dbgprintf("Found function call to [%s] @ 0x%08X\n", CPatterns[j].Name, offset + SectionOffset );
//Now find function start
offset -= 4;
while(1)
{
if( read32( offset ) == 0x7C0802A6 )
break;
offset-=4;
}
dbgprintf("Found function start of [%s(Sync)] @ 0x%08X\n", CPatterns[j].Name, offset + SectionOffset );
//This patches a li rX, 0 before the Async function call for the Sync call
//Since this register of the cb is different per function we do this haxx
if( (read32( offset + 0x04 ) & 0x0000F000 ) == 0x00008000 ) // lis
{
write32( offset, read32( offset + 0x0C ) & 0xFBE00000 );
//Forge a branch to the async function
offset += 4;
u32 newval = ((u32)ptr + i) - offset;
newval&= 0x03FFFFFC;
newval|= 0x48000000;
write32( offset, newval );
} else {
dbgprintf("Unhandled Async cb case!\n");
}
} else {
dbgprintf("No sync function found!\n");
}
memcpy( ptr + i, CPatterns[j].Patch, CPatterns[j].PatchLength );
} else {
memcpy( ptr + i, CPatterns[j].Patch, CPatterns[j].PatchLength );
}
}
}
}
for( j=0; j < sizeof(CPatterns)/sizeof(FuncPattern); ++j )
{
if( CPatterns[j].Found == 0 )
dbgprintf("Pattern %s not found!\n", CPatterns[j].Name );
}
return;
}
void DoPatches( char *ptr, u32 size, u32 SectionOffset )
{
u32 i=0,j=0,k=0,value;
u32 PatchCount = 0;
dbgprintf("DoPatches( 0x%p, %d, 0x%X)\n", ptr, size, SectionOffset );
// HACK: PokemonXD and Pokemon Colosseum low memory clear patch
if(( (read32(0)>>8) == 0x475858 ) || ( (read32(0)>>8) == 0x474336 ))
{
// patch out initial memset(0x1800, 0, 0x1800)
if( (read32(0) & 0xFF) == 0x4A ) // JAP
write32( 0x560C, 0x60000000 );
else // EUR/USA
write32( 0x5614, 0x60000000 );
// patch memset to jump to test function
write32(0x00005498, 0x4BFFABF0);
// patch in test < 0x3000 function
write32(0x00000088, 0x3D008000);
write32(0x0000008C, 0x61083000);
write32(0x00000090, 0x7C044000);
write32(0x00000094, 0x4180542C);
write32(0x00000098, 0x90E40004);
write32(0x0000009C, 0x48005400);
// skips __start init of debugger mem
write32(0x00003194, 0x48000028);
}
// Reset Found
for( k=0; k < sizeof(FPatterns)/sizeof(FuncPattern); ++k )
FPatterns[k].Found = 0;
if( ConfigGetConfig(DML_CFG_NMM) )
DoCardPatches( ptr, size, SectionOffset );
//Note: ORing the values prevents an early break out when a single patterns has multiple hits
PatchCount=0;
for( i=0; i < size; i+=4 )
{
if( (PatchCount & 1) == 0 )
{
if( read32( (u32)ptr + i ) == 0x3C00A800 ) // Loader
{
int j=0;
while( read32( (u32)ptr + i - j ) != 0x7C0802A6 ) // Seek to start of function
j+=4;
//Check if there is a lis %rX, 0xCC00 in this function
//At least Sunshine has one false hit on lis r3,0xA800
int k=0;
while( 1 )
{
if( read32( (u32)ptr + i + k - j ) == 0x4E800020 )
break;
if( (read32( (u32)ptr + i + k - j ) & 0xF81FFFFF) == 0x3800CC00 )
break;
k += 4;
}
if( read32( (u32)ptr + i + k - j ) == 0x4E800020 )
{
//dbgprintf("Patch:No 0xCC00 found around:%08X\n", (u32)ptr+i);
continue;
}
k = 0;
while(1)
{
u32 val = read32( (u32)ptr + i + k );
if( (val & 0xFFFF ) == 0xCC00 )
{
write32( (u32)ptr + i + k, (val&0xFFFF0000) | 0xC000 );
//dbgprintf("Patch:lis 0x%08X\n", (u32)ptr + i + k + SectionOffset );
continue;
}
if( (val & 0xFC00FF00) == 0x90006000 )
{
write32( (u32)ptr + i + k, (val&0xFFFF00FF) | 0x2F00 );
//dbgprintf("Patch:stw 0x%08X\n", (u32)ptr + i + k + SectionOffset );
continue;
}
if( read32( (u32)ptr + i + k ) == 0x4E800020 )
break;
k+=4;
}
write32( (u32)ptr + i, 0x3C00A700 );
dbgprintf("Patch:Found [DVDLowRead]: 0x%08X\n", (u32)ptr + i + SectionOffset );
PatchCount |= 1;
} else if( read32( (u32)ptr + i ) == 0x3C60A800 ) // Games
{
int j=0;
while( read32( (u32)ptr + i - j ) != 0x7C0802A6 ) // Seek to start of function
j+=4;
//Check if there is a lis %rX, 0xCC00 in this function
//At least Sunshine has one false hit on lis r3,0xA800
int k=0;
while( 1 )
{
if( read32( (u32)ptr + i + k - j ) == 0x4E800020 )
break;
if( (read32( (u32)ptr + i + k - j ) & 0xF81FFFFF) == 0x3800CC00 )
{
write32( (u32)ptr + i + k - j, (read32((u32)ptr + i + k - j) & 0xFFFF0000) | 0xC000 );
break;
}
k += 4;
}
if( read32( (u32)ptr + i + k - j ) == 0x4E800020 )
{
//dbgprintf("Patch:No 0xCC00 found around:%08X\n", (u32)ptr+i);
continue;
}
//Search addi 0x6000
while( 1 )
{
if( read32( (u32)ptr + i + k - j ) == 0x4E800020 )
break;
if( (read32( (u32)ptr + i + k - j ) & 0xFFFF) == 0x6000 )
{
write32( (u32)ptr + i + k - j, (read32((u32)ptr + i + k - j) & 0xFFFF0000) | 0x2F00 );
break;
}
k += 4;
}
if( read32( (u32)ptr + i + k - j ) == 0x4E800020 )
{
//dbgprintf("Patch:No 0xCC00 found around:%08X\n", (u32)ptr+i);
continue;
}
write32( (u32)ptr + i, 0x3C60A700 );
dbgprintf("Patch:Found [DVDLowRead]: 0x%08X\n", (u32)ptr + i + SectionOffset );
PatchCount |= 1;
}
}
if( (PatchCount & 2) == 0 )
if( (read32( (u32)ptr + i )&0xFC00FFFF) == 0x5400077A &&
(read32( (u32)ptr + i + 4 )&0xFC00FFFF) == 0x28000000 &&
read32( (u32)ptr + i + 8 ) == 0x41820008 &&
(read32( (u32)ptr + i +12 )&0xFC00FFFF) == 0x64002000
)
{
dbgprintf("Patch:Found [__OSDispatchInterrupt]: 0x%08X 0x%08X\n", (u32)ptr + i + 0 + SectionOffset, (u32)ptr + i + 0x1A8 + SectionOffset );
write32( (u32)ptr + i + 0, (read32( (u32)ptr + i + 0 ) & 0xFFFF0000) | 0x0463 );
write32( (u32)ptr + i + 0x1A8, (read32( (u32)ptr + i + 0x1A8 ) & 0xFFFF0000) | 0x0463 );
PatchCount |= 2;
}
if( (PatchCount & 4) == 0 )
if( read32( (u32)ptr + i ) == 0x5480056A &&
read32( (u32)ptr + i + 4 ) == 0x28000000 &&
read32( (u32)ptr + i + 8 ) == 0x40820008 &&
(read32( (u32)ptr + i +12 )&0xFC00FFFF) == 0x60000004
)
{
dbgprintf("Patch:Found [SetInterruptMask]: 0x%08X\n", (u32)ptr + i + 12 + SectionOffset );
write32( (u32)ptr + i + 12, (read32( (u32)ptr + i + 12 ) & 0xFFFF0000) | 0x4000 );
PatchCount |= 4;
}
if( (PatchCount & 8) == 0 )
if( (read32( (u32)ptr + i + 0 ) & 0xFFFF) == 0x6000 &&
(read32( (u32)ptr + i + 4 ) & 0xFFFF) == 0x002A &&
(read32( (u32)ptr + i + 8 ) & 0xFFFF) == 0x0054
)
{
u32 Offset = (u32)ptr + i - 8;
dbgprintf("Patch:Found [__DVDIntrruptHandler]: 0x%08X\n", Offset + SectionOffset );
if( (read32(Offset+4) & 0xFFFF) == 0xCC00 ) // Loader
{
value = *(vu32*)(Offset+4);
value&= 0xFFFF0000;
value|= 0x0000C000;
*(vu32*)(Offset+4) = value;
} else {
value = *(vu32*)Offset;
value&= 0xFFFF0000;
value|= 0x0000C000;
*(vu32*)Offset = value;
}
Offset += 8;
value = *(vu32*)Offset;
value&= 0xFFFF0000;
value|= 0x00002F30;
*(vu32*)Offset = value;
Offset += 20;
dbgprintf("Patch:[__DVDInterruptHandler] 0x%08X\n", Offset + SectionOffset );
*(vu32*)Offset = 0x3D00CD00; Offset += 4;
*(vu32*)Offset = 0x38000034; Offset += 4;
*(vu32*)Offset = 0x90080004; Offset +=16;
dbgprintf("Patch:[__DVDInterruptHandler] 0x%08X\n", Offset + SectionOffset );
*(vu32*)Offset = 0x3D00CD00; Offset += 4;
*(vu32*)Offset = 0x3C004000; Offset += 4;
*(vu32*)Offset = 0x90080030; Offset +=32;
if( (read32(Offset-8) & 0xFFFF) == 0xCC00 ) // Loader
{
Offset -= 8;
}
dbgprintf("Patch:[__DVDInterruptHandler] 0x%08X\n", Offset + SectionOffset );
value = *(vu32*)Offset;
value&= 0xFFFF0000;
value|= 0x0000C000;
*(vu32*)Offset = value;
Offset += 4;
value = *(vu32*)Offset;
value&= 0xFFFF0000;
value|= 0x00002F08;
*(vu32*)Offset = value;
PatchCount |= 8;
}
if( (PatchCount & 32) == 0 )
{
if( (read32( (u32)ptr + i + 0 ) & 0xFFFF) == 0xCC00 && // Game
(read32( (u32)ptr + i + 4 ) & 0xFFFF) == 0x6000 &&
(read32( (u32)ptr + i +12 ) & 0xFFFF) == 0x001C
)
{
u32 Offset = (u32)ptr + i;
dbgprintf("Patch:[cbForStateBusy] 0x%08X\n", Offset + SectionOffset );
write32( Offset, 0x3C80C000 );
write32( Offset+4, 0x38842F30 );
PatchCount |= 32;
} else if( (read32( (u32)ptr + i + 0 ) & 0xFFFF) == 0xCC00 && // Loader
(read32( (u32)ptr + i + 4 ) & 0xFFFF) == 0x6018 &&
(read32( (u32)ptr + i +12 ) & 0xFFFF) == 0x001C
)
{
u32 Offset = (u32)ptr + i;
dbgprintf("Patch:[cbForStateBusy] 0x%08X\n", Offset + SectionOffset );
write32( Offset, 0x3C60C000 );
write32( Offset+4, 0x80832F48 );
PatchCount |= 32;
}
}
if( ConfigGetConfig(DML_CFG_CHEATS) || ConfigGetConfig( DML_CFG_DEBUGGER ) )
{
// OSSleepThread(Pattern 1)
if( (PatchCount & 16) == 0 )
if( read32((u32)ptr + i + 0 ) == 0x3C808000 &&
( read32((u32)ptr + i + 4 ) == 0x38000004 || read32((u32)ptr + i + 4 ) == 0x808400E4 ) &&
( read32((u32)ptr + i + 8 ) == 0x38000004 || read32((u32)ptr + i + 8 ) == 0x808400E4 )
)
{
int j = 12;
while( read32((u32)ptr + i + j ) != 0x4E800020 )
j+=4;
dbgprintf("Patch:[Hook:OSSleepThread] at 0x%08X\n", ((u32)ptr + i + j) | 0x80000000 );
u32 DBGSize;
//if( ConfigGetConfig( DML_CFG_DEBUGGER ) )
//{
memcpy( (void*)0x1800, kenobigcDBG, sizeof(kenobigcDBG) );
DBGSize = sizeof(kenobigcDBG);
//} else {
// memcpy( (void*)0x1800, kenobigc, sizeof(kenobigc) );
// DBGSize = sizeof(kenobigc);
//}
if( ConfigGetConfig(DML_CFG_DEBUGWAIT) )
write32( P2C(read32(0x1808)), 1 );
else
write32( P2C(read32(0x1808)), 0 );
u32 newval = 0x18A8 - ((u32)ptr + i + j);
newval&= 0x03FFFFFC;
newval|= 0x48000000;
write32( (u32)ptr + i + j, newval );
memcpy( (void*)0x1800, (void*)0, 6 );
char *path = (char*)malloc( 128 );
if( ConfigGetConfig(DML_CFG_CHEAT_PATH) )
{
sprintf( path, "%s", ConfigGetCheatPath() );
} else {
sprintf( path, "/games/%.6s/%.6s.gct", (char*)0x1800, (char*)0x1800 );
}
FIL CodeFD;
u32 read;
if( f_open( &CodeFD, path, FA_OPEN_EXISTING|FA_READ ) == FR_OK )
{
if( CodeFD.fsize >= 0x2E80 - (0x1800+DBGSize-8) )
{
dbgprintf("Patch:Cheatfile is too large, it must not be large than %d bytes!\n",
0x2E80 - (0x1800+DBGSize-8));
} else {
if( f_read( &CodeFD, (void*)(0x1800+DBGSize-8), CodeFD.fsize, &read ) == FR_OK )
{
dbgprintf("Patch:Copied cheat file to memory\n");
write32( 0x1804, 1 );
} else
dbgprintf("Patch:Failed to read cheat file:\"%s\"\n", path );
}
f_close( &CodeFD );
} else {
dbgprintf("Patch:Failed to open/find cheat file:\"%s\"\n", path );
}
free(path);
PatchCount |= 16;
}
}
if( ConfigGetConfig(DML_CFG_CHEATS) )
{
if( PatchCount == 63 )
break;
} else {
if( PatchCount == 47 )
break;
}
}
for( i=0; i < size; i+=4 )
{
if( read32( (u32)ptr + i ) != 0x4E800020 )
continue;
i+=4;
FuncPattern fp;
MPattern( (u8*)(ptr+i), size, &fp );
for( j=0; j < sizeof(FPatterns)/sizeof(FuncPattern); ++j )
{
if( FPatterns[j].Found ) //Skip already found patches
continue;
if( CPattern( &fp, &(FPatterns[j]) ) )
{
u32 FOffset = (u32)ptr + i;
dbgprintf("Patch:Found [%s]: 0x%08X\n", FPatterns[j].Name, FOffset + SectionOffset );
switch( FPatterns[j].PatchLength )
{
case 0xdead0004: // Audiostreaming hack
{
switch( read32(0) >> 8 )
{
case 0x474544: // Eternal Darkness
break;
default:
{
write32( FOffset + 0xB4, 0x60000000 );
write32( FOffset + 0xC0, 0x60000000 );
} break;
}
} break;
case 0xdead0001: // Patch for __GXSetVAT, fixes the dungeon map freeze in Wind Waker
{
switch( read32(0) >> 8 )
{
case 0x505A4C: // The Legend of Zelda: Collector's Edition
if( !(DOLSize == 3847012 || DOLSize == 3803812) ) // only patch the main.dol of the Zelda:ww game
break;
case 0x475A4C: // The Legend of Zelda: The Wind Waker
{
write32(FOffset, (read32(FOffset) & 0xff00ffff) | 0x220000);
memcpy((void *)(FOffset + 4), __GXSetVAT_patch, sizeof(__GXSetVAT_patch));
dbgprintf("Patch:Applied __GXSetVAT patch\n");
} break;
default:
break;
}
} break;
case 0xdead000B: // PADRead hook
{
//Find blr
j=0;
while(1)
{
if( read32( FOffset + j ) == 0x4E800020 )
break;
j+=4;
}
dbgprintf("Patch:[PADRead hook] %08X\n", FOffset + j );
memcpy( (void*)0x2EE0, padipc, sizeof(padipc) );
PatchB( 0x2EE0, FOffset + j );
write32( 0x12FC, 0 );
} break;
default:
{
if( ConfigGetConfig( DML_CFG_CHEATS ) )
{
if( FPatterns[j].Patch == patch_fwrite_GC )
break;
}
if( (FPatterns[j].Length >> 16) == 0xdead )
{
dbgprintf("DIP:Unhandled dead case:%08X\n", FPatterns[j].Length );
} else
{
memcpy( (void*)(FOffset), FPatterns[j].Patch, FPatterns[j].PatchLength );
if ((FPatterns[j].Patch == (u8 *)__dvdLowAudioStatusNULL) && ((read32(0) >> 8) == 0x47494B))
{
// Ikaruga resets to the main menu, if the returned status is 0(finished playing the stream), but it works if 1(still playing) is returned
write32(FOffset + 36, 0x38600001);
dbgprintf("Patch:LowAudioStatus patched for Ikaruga\n");
}
}
} break;
}
// If this is a patch group set all others of this group as found aswell
if( FPatterns[j].Group )
{
for( k=0; k < sizeof(FPatterns)/sizeof(FuncPattern); ++k )
{
if( FPatterns[k].Group == FPatterns[j].Group )
{
if( !FPatterns[k].Found ) // Don't overwrite the offset!
FPatterns[k].Found = -1; // Usually this holds the offset, to determinate it from a REALLY found pattern we set it -1 which still counts a logical TRUE
//dbgprintf("Setting [%s] to found!\n", FPatterns[k].Name );
}
}
}
}
}
}
}