88c12646f4
*Reduced HDD read time out to 25 seconds *Added two disc feature (Extracted format is unsupported) Use the latest DMToolBox (0.3 or higher) to install your two disc games This will be the last version for some time, since I'm moving my focus to other things. Always remember; Impossible is nothing! git-svn-id: svn://localhost/Users/andi/Downloads/code/DML@34 be6c1b03-d731-4111-a574-e37d80d43941
1171 lines
37 KiB
C
1171 lines
37 KiB
C
#include "Patches.h"
|
||
|
||
#include "CardPatches.c"
|
||
#include "DVDPatches.c"
|
||
#include "FwritePatches.c"
|
||
#include "CheatCode.c"
|
||
|
||
extern u32 DOLSize;
|
||
u32 FrameBuffer = 0;
|
||
u32 FBOffset = 0;
|
||
u32 FBEnable = 0;
|
||
u32 FBSize = 0;
|
||
|
||
unsigned char VISetFB[] =
|
||
{
|
||
0x38, 0x7F, 0x00, 0xF0, // mr %r3, %r7
|
||
0x38, 0x9F, 0x01, 0x24,
|
||
0x38, 0xBF, 0x01, 0x28,
|
||
0x38, 0xDF, 0x01, 0x3C,
|
||
};
|
||
|
||
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
|
||
};
|
||
|
||
u8 GXMObjects[][0x3C] =
|
||
{
|
||
{ // GXPal528IntDf
|
||
0x00, 0x00, 0x00, 0x04, 0x02, 0x80, 0x02, 0x10, 0x02, 0x10, 0x00, 0x28, 0x00, 0x17, 0x02, 0x80,
|
||
0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||
0x06, 0x06, 0x08, 0x08, 0x0A, 0x0C, 0x0A, 0x08, 0x08, 0x00, 0x00, 0x00,
|
||
},
|
||
|
||
{ // GXEurgb60Hz480IntDf
|
||
0x00, 0x00, 0x00, 0x14, 0x02, 0x80, 0x01, 0xE0, 0x01, 0xE0, 0x00, 0x28, 0x00, 0x00, 0x02, 0x80,
|
||
0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||
0x06, 0x06, 0x08, 0x08, 0x0A, 0x0C, 0x0A, 0x08, 0x08, 0x00, 0x00, 0x00,
|
||
},
|
||
|
||
{ // GXMpal480IntDf
|
||
0x00, 0x00, 0x00, 0x08, 0x02, 0x80, 0x01, 0xE0, 0x01, 0xE0, 0x00, 0x28, 0x00, 0x00, 0x02, 0x80,
|
||
0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||
0x06, 0x06, 0x08, 0x08, 0x0A, 0x0C, 0x0A, 0x08, 0x08, 0x00, 0x00, 0x00,
|
||
},
|
||
|
||
{ // GXNtsc480IntDf
|
||
0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x01, 0xE0, 0x01, 0xE0, 0x00, 0x28, 0x00, 0x00, 0x02, 0x80,
|
||
0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||
0x06, 0x06, 0x08, 0x08, 0x0A, 0x0C, 0x0A, 0x08, 0x08, 0x00, 0x00, 0x00,
|
||
},
|
||
|
||
{ // GXNtsc480Int
|
||
0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x01, 0xE0, 0x01, 0xE0, 0x00, 0x28, 0x00, 0x00, 0x02, 0x80,
|
||
0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||
0x06, 0x06, 0x00, 0x00, 0x15, 0x16, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
},
|
||
};
|
||
|
||
u32 DVDGetDriveStatus[] = {
|
||
0x38600000, // li r3, 0
|
||
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 },
|
||
{ 0xA8, 10, 4, 4, 6, 3, (u8*)DVDGetDriveStatus, sizeof(DVDGetDriveStatus), "DVDGetDriveStatus", 0, 0 },
|
||
{ 0xD4, 13, 8, 11, 2, 7, (u8*)NULL, 0xdead0004, "AIResetStreamSampleCount", 0, 0 },
|
||
|
||
{ 0x10C, 30, 18, 5, 2, 3, (u8*)NULL, 0xdead0002, "DVDLowRead A", 0, 0 },
|
||
{ 0xDC, 23, 18, 3, 2, 4, (u8*)NULL, 0xdead0002, "DVDLowRead B", 0, 0 },
|
||
{ 0x104, 29, 17, 5, 2, 3, (u8*)NULL, 0xdead0002, "DVDLowRead C", 0, 0 },
|
||
|
||
|
||
{ 0xCC, 3, 3, 1, 0, 3, (u8*)NULL, 0xdead000C, "C_MTXPerspective", 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 },
|
||
{ 0x2A8, 66, 4, 20, 17, 14, (u8*)NULL, 0xdead000B, "PADRead E", 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;
|
||
|
||
u32 FB[MAX_FB];
|
||
|
||
void SMenuAddFramebuffer( void )
|
||
{
|
||
u32 i,j,f;
|
||
|
||
if( *(vu32*)FBEnable != 1 )
|
||
return;
|
||
|
||
FrameBuffer = (*(vu32*)FBOffset) & 0x7FFFFFFF;
|
||
|
||
for( i=0; i < MAX_FB; i++)
|
||
{
|
||
if( FB[i] ) //add a new entry
|
||
continue;
|
||
|
||
//check if we already know this address
|
||
f=0;
|
||
for( j=0; j<i; ++j )
|
||
{
|
||
if( FrameBuffer == FB[j] ) // already known!
|
||
{
|
||
f=1;
|
||
return;
|
||
}
|
||
}
|
||
if( !f && FrameBuffer && FrameBuffer < 0x14000000 ) // add new entry
|
||
{
|
||
dbgprintf("ES:Added new FB[%d]:%08X\n", i, FrameBuffer );
|
||
FB[i] = FrameBuffer;
|
||
|
||
switch( *(vu32*)(FBEnable+0x20) )
|
||
{
|
||
case VI_NTSC:
|
||
FBSize = 304*480*4;
|
||
break;
|
||
case VI_PAL:
|
||
FBSize = 320*480*4;
|
||
break;
|
||
case VI_EUR60:
|
||
FBSize = 320*480*4;
|
||
break;
|
||
default:
|
||
dbgprintf("ES:SMenuFindOffsets():Invalid Video mode:%d\n", *(vu32*)(FBEnable+0x20) );
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
void ScreenShot( void )
|
||
{
|
||
if( *(vu32*)FBEnable != 1 )
|
||
return;
|
||
|
||
set32( HW_GPIO_OUT, 1<<5 );
|
||
|
||
char *str = (char*)malloc( 64 );
|
||
|
||
u32 i=0,r,wrote;
|
||
FIL SCRFile;
|
||
|
||
sprintf( str, "/screenshots" );
|
||
f_mkdir( str );
|
||
|
||
do
|
||
{
|
||
sprintf( str, "/screenshots/scrn_%02X.raw", i++ );
|
||
r = f_open( &SCRFile, str, FA_CREATE_NEW|FA_WRITE );
|
||
if( r == FR_OK )
|
||
{
|
||
break;
|
||
} else {
|
||
if( r != FR_EXIST )
|
||
{
|
||
dbgprintf("Failed to create file:%u\n", r );
|
||
clear32( HW_GPIO_OUT, 1<<5 );
|
||
return;
|
||
}
|
||
}
|
||
} while(1);
|
||
|
||
free(str);
|
||
|
||
if( r == FR_OK )
|
||
{
|
||
f_write( &SCRFile, (void*)(FB[0]), FBSize, &wrote );
|
||
f_close( &SCRFile );
|
||
}
|
||
|
||
clear32( HW_GPIO_OUT, 1<<5 );
|
||
}
|
||
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 PatchFunc( char *ptr )
|
||
{
|
||
u32 i = 0;
|
||
u32 reg=-1;
|
||
|
||
while(1)
|
||
{
|
||
u32 op = read32( (u32)ptr + i );
|
||
|
||
if( op == 0x4E800020 ) // blr
|
||
break;
|
||
|
||
if( (op & 0xFC00FFFF) == 0x3C00CC00 ) // lis rX, 0xCC00
|
||
{
|
||
reg = (op & 0x3E00000) >> 21;
|
||
|
||
write32( (u32)ptr + i, (reg<<21) | 0x3C00C000 ); // Patch to: lis rX, 0xC000
|
||
dbgprintf("[%08X] %08X: lis r%u, 0xC000\n", (u32)ptr+i, read32( (u32)ptr+i), reg );
|
||
}
|
||
|
||
if( (op & 0xFC00FFFF) == 0x3C00A800 ) // lis rX, 0xA800
|
||
{
|
||
write32( (u32)ptr + i, (op & 0x3E00000) | 0x3C00A700 ); // Patch to: lis rX, 0xA700
|
||
dbgprintf("[%08X] %08X: lis rX, 0xA700\n", (u32)ptr+i, read32( (u32)ptr+i) );
|
||
}
|
||
|
||
if( (op & 0xFC00FFFF) == 0x38006000 ) // addi rX, rY, 0x6000
|
||
{
|
||
u32 src = (op >> 16) & 0x1F;
|
||
u32 dst = (op >> 21) & 0x1F;
|
||
|
||
if( src == reg )
|
||
{
|
||
write32( (u32)ptr + i, (dst<<21) | (src<<16) | 0x38002F00 ); // Patch to: addi rX, rY, 0x2F00
|
||
dbgprintf("[%08X] %08X: addi r%u, r%u, 0x2F00\n", (u32)ptr+i, read32( (u32)ptr+i), dst, src );
|
||
|
||
}
|
||
}
|
||
|
||
if( (op & 0xFC000000 ) == 0x90000000 )
|
||
{
|
||
u32 src = (op >> 16) & 0x1F;
|
||
u32 dst = (op >> 21) & 0x1F;
|
||
u32 val = op & 0xFFFF;
|
||
|
||
if( src == reg )
|
||
{
|
||
if( (val & 0xFF00) == 0x6000 ) // case with 0x60XY(rZ)
|
||
{
|
||
write32( (u32)ptr + i, (dst<<21) | (src<<16) | 0x2F00 | (val&0xFF) | 0x90000000 ); // Patch to: stw rX, 0x2FXY(rZ)
|
||
dbgprintf("[%08X] %08X: stw r%u, 0x%04X(r%u)\n", (u32)ptr+i, read32( (u32)ptr+i), dst, 0x2F00 | (val&0xFF), src );
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
i += 4;
|
||
}
|
||
}
|
||
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 );
|
||
offset += 4;
|
||
|
||
if( CPatterns[j].Patch == CARDCheckEX )
|
||
{
|
||
write32( offset, 0x38800000 ); // lis r4,0
|
||
offset += 4;
|
||
}
|
||
|
||
//Forge a branch to the async function
|
||
|
||
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 );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
//if( CardLowestOff )
|
||
//{
|
||
// 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 InitPatches( void )
|
||
{
|
||
|
||
}
|
||
void DoPatches( char *ptr, u32 size, u32 SectionOffset )
|
||
{
|
||
u32 i=0,j=0,k=0,value;
|
||
u32 PatchCount = 0;
|
||
u32 r13 = 0;
|
||
|
||
FBOffset = 0;
|
||
FBEnable = 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=1;
|
||
|
||
for( i=0; i < size; i+=4 )
|
||
{
|
||
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 & 16) == 0 )
|
||
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( (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( (PatchCount & 64) == 0 )
|
||
{
|
||
if( read32( (u32)ptr + i + 0 ) == 0x3C608000 )
|
||
{
|
||
if( ((read32( (u32)ptr + i + 4 ) & 0xFC1FFFFF ) == 0x800300CC) && ((read32( (u32)ptr + i + 8 ) >> 24) == 0x54 ) )
|
||
{
|
||
dbgprintf( "Patch:[VIConfgiure] 0x%08X\n", (u32)(ptr+i) );
|
||
write32( *(vu32*)(ptr+i+4), 0x5400F0BE | ((read32( (u32)ptr + i + 4 ) & 0x3E00000) >> 5 ) );
|
||
PatchCount |= 64;
|
||
}
|
||
}
|
||
}
|
||
|
||
if( (PatchCount & 128) == 0 )
|
||
{
|
||
if( ConfigGetConfig(DML_CFG_SCREENSHOT) )
|
||
{
|
||
if( *(u32*)(ptr+i) >> 16 == 0x3DA0 && r13 == 0 )
|
||
{
|
||
r13 = ((*(u32*)(ptr+i)) & 0xFFFF) << 16;
|
||
r13|= (*(u32*)(ptr+i+4)) & 0xFFFF;
|
||
|
||
dbgprintf("Patch:r13:%08X\n", r13 );
|
||
}
|
||
|
||
if( memcmp( ptr+i, VISetFB, sizeof(VISetFB) ) == 0 && FBEnable == 0 )
|
||
{
|
||
dbgprintf("Patch:[VISetFB]%08X\n", (u32)ptr+i );
|
||
|
||
FBEnable = ( *(u32*)(ptr+i-4) );
|
||
|
||
if( FBEnable & 0x8000 )
|
||
{
|
||
FBEnable = ((~FBEnable) & 0xFFFF) + 1;
|
||
FBEnable = (r13 - FBEnable) & 0x7FFFFFF;
|
||
} else {
|
||
FBEnable = FBEnable & 0xFFFF;
|
||
FBEnable = (r13 + FBEnable) & 0x7FFFFFF;
|
||
}
|
||
|
||
FBOffset = FBEnable - 0x08;
|
||
// dbgprintf("FBOffset:%08X\n", FBOffset );
|
||
// dbgprintf("FBEnable:%08X\n", FBEnable );
|
||
|
||
for( j=0; j < MAX_FB; ++j )
|
||
FB[j] = 0;
|
||
|
||
PatchCount |= 128;
|
||
}
|
||
} else {
|
||
PatchCount |= 128;
|
||
|
||
}
|
||
}
|
||
|
||
if( (PatchCount & 256) == 0 ) //DVDLowStopMotor
|
||
{
|
||
if( read32( (u32)ptr + i ) == 0x3C00E300 )
|
||
{
|
||
u32 Offset = (u32)ptr + i;
|
||
|
||
dbgprintf("Patch:[DVDLowStopMotor] 0x%08X\n", Offset + SectionOffset );
|
||
|
||
value = *(vu32*)(Offset-12);
|
||
value&= 0xFFFF0000;
|
||
value|= 0x0000C000;
|
||
*(vu32*)(Offset-12) = value;
|
||
|
||
value = *(vu32*)(Offset-8);
|
||
value&= 0xFFFF0000;
|
||
value|= 0x00002F00;
|
||
*(vu32*)(Offset-8) = value;
|
||
|
||
value = *(vu32*)(Offset+4);
|
||
value&= 0xFFFF0000;
|
||
value|= 0x00002F08;
|
||
*(vu32*)(Offset+4) = value;
|
||
|
||
PatchCount |= 256;
|
||
}
|
||
}
|
||
|
||
if( (PatchCount & 512) == 0 ) //DVDLowReadDiskID
|
||
{
|
||
if( (read32( (u32)ptr + i ) & 0xFFFF ) == 0xA800 && (read32( (u32)ptr + i + 4 ) & 0xFFFF ) == 0x40 )
|
||
{
|
||
u32 Offset = (u32)ptr + i;
|
||
|
||
dbgprintf("Patch:[DVDLowReadDiskID] 0x%08X\n", Offset + SectionOffset );
|
||
|
||
value = *(vu32*)(Offset);
|
||
value&= 0xFFFF0000;
|
||
value|= 0x0000A700;
|
||
*(vu32*)(Offset) = value;
|
||
|
||
value = *(vu32*)(Offset+0x20);
|
||
value&= 0xFFFF0000;
|
||
value|= 0x0000C000;
|
||
*(vu32*)(Offset+0x20) = value;
|
||
|
||
value = *(vu32*)(Offset+0x24);
|
||
value&= 0xFFFF0000;
|
||
value|= 0x00002F00;
|
||
*(vu32*)(Offset+0x24) = value;
|
||
|
||
value = *(vu32*)(Offset+0x2C);
|
||
value&= 0xFFFF0000;
|
||
value|= 0x00002F08;
|
||
*(vu32*)(Offset+0x2C) = value;
|
||
|
||
write32( 0x01576D4, 0x38600000 );
|
||
|
||
PatchCount |= 512;
|
||
}
|
||
}
|
||
|
||
if( ConfigGetConfig(DML_CFG_CHEATS) || ConfigGetConfig( DML_CFG_DEBUGGER ) )
|
||
{
|
||
if( PatchCount == 1023 )
|
||
break;
|
||
} else {
|
||
if( PatchCount == 1007 )
|
||
break;
|
||
}
|
||
}
|
||
|
||
if( ConfigGetVideMode() & DML_VID_FORCE )
|
||
{
|
||
k=0;
|
||
for( i=0; i < size; i+=4 )
|
||
{
|
||
for( j=0; j <= GXNtsc480Int; ++j )
|
||
{
|
||
if( memcmp( ptr+i, GXMObjects[j], 0x3C ) == 0 )
|
||
{
|
||
dbgprintf("Patch:Found GX pattern %u at %08X\n", j, ptr+i );
|
||
switch( ConfigGetVideMode() & 15 )
|
||
{
|
||
case DML_VID_FORCE_PAL50:
|
||
{
|
||
memcpy( ptr+i, GXMObjects[GXPal528IntDf], 0x3C );
|
||
} break;
|
||
case DML_VID_FORCE_PAL60:
|
||
{
|
||
memcpy( ptr+i, GXMObjects[GXEurgb60Hz480IntDf], 0x3C );
|
||
} break;
|
||
case DML_VID_FORCE_NTSC:
|
||
{
|
||
memcpy( ptr+i, GXMObjects[GXNtsc480IntDf], 0x3C );
|
||
} break;
|
||
}
|
||
k++;
|
||
}
|
||
}
|
||
|
||
if( k > 4 )
|
||
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 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 0xdead0002: // DVDLowRead
|
||
{
|
||
PatchFunc( (char*)FOffset );
|
||
} break;
|
||
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 0xdead000B: // PADRead hook
|
||
{
|
||
if( !ConfigGetConfig(DML_CFG_PADHOOK) )
|
||
break;
|
||
|
||
//Find blr
|
||
|
||
j=0;
|
||
while(1)
|
||
{
|
||
if( read32( FOffset + j ) == 0x4E800020 )
|
||
break;
|
||
j+=4;
|
||
}
|
||
|
||
dbgprintf("Patch:[PADRead hook] %08X\n", FOffset + j );
|
||
|
||
memcpy( (void*)0x2ECC, padipc, sizeof(padipc) );
|
||
PatchB( 0x2ECC, FOffset + j );
|
||
write32( 0x12FC, 0 );
|
||
|
||
} break;
|
||
case 0xdead000C: // Widescreen hack by Extrems
|
||
{
|
||
if( !ConfigGetConfig(DML_CFG_FORCE_WIDE) )
|
||
break;
|
||
|
||
dbgprintf("Patch:[MTXPerspectiveSig] 0x%08X \n", (u32)FOffset);
|
||
|
||
*(volatile float *)0x00000050 = 0.5625f;
|
||
memcpy((void*)(FOffset+ 28),(void*)(FOffset+ 36),44);
|
||
memcpy((void*)(FOffset+188),(void*)(FOffset+192),16);
|
||
*(unsigned int*)(FOffset+52) = 0x48000001 | ((*(unsigned int*)(FOffset+52) & 0x3FFFFFC) + 8);
|
||
*(unsigned int*)(FOffset+72) = 0x3C600000 | (0x80000050 >> 16); // lis 3, 0x8180
|
||
*(unsigned int*)(FOffset+76) = 0xC0230000 | (0x80000050 & 0xFFFF); // lfs 1, -0x1C (3)
|
||
*(unsigned int*)(FOffset+80) = 0xEC240072; // fmuls 1, 4, 1
|
||
|
||
} break;
|
||
default:
|
||
{
|
||
if( ConfigGetConfig( DML_CFG_CHEATS ) )
|
||
{
|
||
if( FPatterns[j].Patch == patch_fwrite_GC )
|
||
break;
|
||
}
|
||
|
||
if( FPatterns[j].Patch == (u8*)DVDGetDriveStatus )
|
||
{
|
||
if( (read32(0) >> 8) != 0x474754 && // Chibi-Robo!
|
||
(read32(0) >> 8) != 0x475041 ) // Pok<6F>mon Channel
|
||
break;
|
||
|
||
dbgprintf("Patch:DVDGetDriveStatus\n");
|
||
}
|
||
|
||
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 );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|