We are still looking for competent contributors (JPN and 480p results especially) for our

compatibility list ( http://crediar.no-ip.com/gc )

Please come to #DM on efnet if you want to help!

IMPORTANT: The config version has been updated to 2!

updated DM to version 2.1

*Improved patch code and made it more versatile
*Improved .elf patching code (fixes Nightfire)
*Improved No Disc patching
*Added a hack for PSO I&II EUR/USA
*Added the wide screen hack by Extrems
*The NODISC config setting has been removed since it's been unused since 1.0
*Removed USBGecko debug output


git-svn-id: svn://localhost/Users/andi/Downloads/code/trunk@18 be6c1b03-d731-4111-a574-e37d80d43941
This commit is contained in:
crediar@rypp.net 2012-07-17 09:17:46 +00:00
parent 0dabbeeb80
commit 07f92c2489
8 changed files with 270 additions and 228 deletions

View File

@ -44,7 +44,7 @@ typedef struct GC_SRAM
typedef struct DML_CFG
{
u32 Magicbytes; // 0xD1050CF6
u32 Version; // 0x00000001
u32 Version; // 0x00000002
u32 VideoMode;
u32 Config;
char GamePath[255];
@ -62,9 +62,9 @@ enum dmlconfig
DML_CFG_CHEAT_PATH = (1<<6),
DML_CFG_ACTIVITY_LED= (1<<7),
DML_CFG_PADHOOK = (1<<8),
DML_CFG_NODISC = (1<<9),
DML_CFG_FORCE_WIDE = (1<<9),
DML_CFG_BOOT_DISC = (1<<10),
DML_CFG_BOOT_DOL = (1<<11),
DML_CFG_BOOT_DISC2 = (1<<11),
};
enum dmlvideomode

234
Patches.c
View File

@ -114,12 +114,23 @@ u8 GXMObjects[][0x3C] =
},
};
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 },
{ 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 },
@ -199,6 +210,65 @@ void PatchBL( u32 dst, u32 src )
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;
@ -453,126 +523,10 @@ void DoPatches( char *ptr, u32 size, u32 SectionOffset )
DoCardPatches( ptr, size, SectionOffset );
//Note: ORing the values prevents an early break out when a single patterns has multiple hits
PatchCount=0;
PatchCount=1;
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 &&
@ -847,19 +801,6 @@ void DoPatches( char *ptr, u32 size, u32 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 )
@ -879,6 +820,23 @@ void DoPatches( char *ptr, u32 size, u32 SectionOffset )
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
{
//Find blr
@ -897,6 +855,22 @@ void DoPatches( char *ptr, u32 size, u32 SectionOffset )
PatchB( 0x2EE0, 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:
{

149
dip.c
View File

@ -16,6 +16,8 @@ u32 DOLOffset = 0;
s32 ELFNumberOfSections = 0;
u32 FSTMode = 0;
extern DML_CFG *DMLCfg;
FIL GameFile;
u32 read;
u32 DiscRead=0;
@ -46,8 +48,9 @@ void DIInit( void )
u32 DIUpdateRegisters( void )
{
u32 read,i,j;
static u32 PatchState = 0;
static u32 DOLReadSize= 0;
static u32 PatchState = 0;
static u32 DOLReadSize = 0;
static u32 PSOHack = 0;
if( read32(DI_CONTROL) != 0xdeadbeef )
{
@ -145,9 +148,30 @@ u32 DIUpdateRegisters( void )
DoPatches( (char*)(0x01300000), Length, 0x80000000 );
}
// PSO 1&2
if( (read32(0) >> 8) == 0x47504F )
{
switch( Offset )
{
case 0x56B8E7E0: // AppSwitcher [EUR]
case 0x56C49600: // [USA]
{
DMLCfg->Config &= ~(DML_CFG_CHEATS|DML_CFG_PADHOOK|DML_CFG_DEBUGGER|DML_CFG_DEBUGWAIT);
DoPatches( (char*)Buffer, Length, 0x80000000 );
} break;
case 0x5668FE20: // psov3.dol [EUR]
case 0x56750660: // [USA]
{
PSOHack = 1;
} break;
}
}
if( PatchState == 0 )
{
if( Length == 0x100 )
if( Length == 0x100 || PSOHack )
{
if( read32( (u32)Buffer ) == 0x100 )
{
@ -160,7 +184,7 @@ u32 DIUpdateRegisters( void )
for( i=0; i < 11; ++i )
DOLSize += dol->sizeData[i];
DOLReadSize = sizeof(dolhdr);
DOLReadSize = Length;
DOLMinOff=0x81800000;
DOLMaxOff=0;
@ -190,82 +214,83 @@ u32 DIUpdateRegisters( void )
}
DOLMinOff -= 0x80000000;
DOLMaxOff -= 0x80000000;
DOLMaxOff -= 0x80000000;
if( PSOHack )
{
DOLMinOff = Buffer;
DOLMaxOff = Buffer + DOLSize;
}
dbgprintf("DIP:DOLSize:%d DOLMinOff:0x%08X DOLMaxOff:0x%08X\n", DOLSize, DOLMinOff, DOLMaxOff );
PatchState = 1;
}
PSOHack = 0;
} else if( read32(Buffer) == 0x7F454C46 )
{
if (getfilenamebyoffset(Offset) != NULL)
{
dbgprintf("DIP:The Game is loading %s\n", getfilenamebyoffset(Offset));
} else
{
dbgprintf("DIP:The Game is loading some .elf that is not in the fst...\n");
}
for (i = ((*(u32 *)0x00000038) & ~0x80000000) + 16; i < 0x01800000; i+=12) // Search the fst for the dvd offset of the .elf file
{
if (*(u32 *)i == Offset)
{
DOLSize = *(u32 *)(i+4);
DOLReadSize = Length;
dbgprintf("DIP:Game is loading an ELF 0x%08x\n", Offset );
if( DOLReadSize == DOLSize ) // The .elf is read completely already
{
dbgprintf("DIP:The .elf is read completely, file size: %u bytes\n", DOLSize);
DoPatches( (char*)(Buffer), Length, 0x80000000 );
} else // a part of the .elf is read
{
PatchState = 2;
DOLMinOff=Buffer;
DOLMaxOff=Buffer+Length;
if (Length <= 4096) // The .elf header is read
{
ELFNumberOfSections = read16(Buffer+0x2c) -2; // Assume that 2 sections are .bss and .sbss which are not read
dbgprintf("DIP:The .elf header is read(%u bytes), .elf file size: %u bytes, number of sections to load: %u\n", Length, DOLSize, ELFNumberOfSections);
} else // The .elf is read into a buffer
{
ELFNumberOfSections = -1; // Make sure that ELFNumberOfSections == 0 does not become true
dbgprintf("DIP:The .elf is read into a buffer, read progress: %u/%u bytes\n", Length, DOLSize);
}
}
break;
DOLOffset = Offset;
DOLSize = 0;
if( Length > 0x1000 )
{
DOLReadSize = Length;
DoPatches( (char*)(Buffer), Length, 0x80000000 );
} else
DOLReadSize = 0;
Elf32_Ehdr *ehdr = (Elf32_Ehdr*)Buffer;
dbgprintf("DIP:ELF Programheader Entries:%u\n", ehdr->e_phnum );
for( i=0; i < ehdr->e_phnum; ++i )
{
Elf32_Phdr phdr;
if( FSTMode )
{
FSTRead( (char*)&phdr, sizeof(Elf32_Phdr), DOLOffset + ehdr->e_phoff + i * sizeof(Elf32_Phdr) );
} else {
f_lseek( &GameFile, DOLOffset + ehdr->e_phoff + i * sizeof(Elf32_Phdr) );
f_read( &GameFile, &phdr, sizeof(Elf32_Phdr), &read );
}
DOLSize += (phdr.p_filesz+31) & (~31); // align by 32byte
}
dbgprintf("DIP:ELF size:%u\n", DOLSize );
PatchState = 2;
}
} else if ( PatchState != 0 )
} else if ( PatchState == 1 )
{
DOLReadSize += Length;
if (PatchState == 2)
{
ELFNumberOfSections--;
// DOLMinOff and DOLMaxOff are optimised when loading .dol files
if (DOLMinOff > Buffer)
DOLMinOff = Buffer;
if (DOLMaxOff < Buffer+Length)
DOLMaxOff = Buffer+Length;
if (ELFNumberOfSections < 0)
{
dbgprintf("DIP:.elf read progress: %u/%u bytes\n", DOLReadSize, DOLSize);
} else
{
dbgprintf("DIP:.elf read progress: %u/%u bytes, sections left: %u\n", DOLReadSize, DOLSize, ELFNumberOfSections);
}
}
//dbgprintf("DIP:DOLSize:%d DOLReadSize:%d\n", DOLSize, DOLReadSize );
if( DOLReadSize >= DOLSize || (PatchState == 2 && ELFNumberOfSections == 0))
//dbgprintf("DIP:DOL ize:%d DOL read:%d\n", DOLSize, DOLReadSize );
if( DOLReadSize >= DOLSize )
{
DoPatches( (char*)(DOLMinOff), DOLMaxOff-DOLMinOff, 0x80000000 );
PatchState = 0;
}
} else if ( PatchState == 2 )
{
DoPatches( (char*)(Buffer), Length, 0x80000000 );
if( Buffer > DOLMaxOff )
DOLMaxOff = Buffer;
DOLReadSize += Length;
//dbgprintf("DIP:ELF size:%d ELF read:%d\n", DOLSize, DOLReadSize );
if( DOLReadSize >= DOLSize )
{
PatchState = 0;
}
}
write32( DI_SDMA_LEN, 0 );

1
dip.h
View File

@ -12,6 +12,7 @@
#include "vsprintf.h"
#include "Config.h"
#include "DVD.h"
#include "elf.h"
enum opcodes
{

74
elf.h Normal file
View File

@ -0,0 +1,74 @@
/*
preloader 0.30 - A tool which allows to change the default boot up sequence on the Wii console
Copyright (C) 2008-2009 crediar
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 version 2.
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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define EI_NIDENT 16
typedef struct {
unsigned char e_ident[EI_NIDENT];
unsigned short e_type;
unsigned short e_machine;
unsigned int e_version;
unsigned int e_entry;
unsigned int e_phoff;
unsigned int e_shoff;
unsigned int e_flags;
unsigned short e_ehsize;
unsigned short e_phentsize;
unsigned short e_phnum;
unsigned short e_shentsize;
unsigned short e_shnum;
unsigned short e_shstrndx;
} __attribute__((packed)) Elf32_Ehdr;
typedef struct {
unsigned int sh_name;
unsigned int sh_type;
unsigned int sh_flags;
unsigned int sh_addr;
unsigned int sh_offset;
unsigned int sh_size;
unsigned int sh_link;
unsigned int sh_info;
unsigned int sh_addralign;
unsigned int sh_entsize;
} __attribute__((packed)) Elf32_Shdr;
typedef struct {
unsigned int p_type;
unsigned int p_offset;
unsigned int p_vaddr;
unsigned int p_paddr;
unsigned int p_filesz;
unsigned int p_memsz;
unsigned int p_flags;
unsigned int p_align;
} __attribute__((packed)) Elf32_Phdr;
#define EI_MAG0 0
#define EI_MAG1 1
#define EI_MAG2 2
#define EI_MAG3 3
#define EI_CLASS 4
#define EI_DATA 5
#define EI_VERSION 6
#define EI_PAD 7
#define EI_NIDENT 16 //size of ident

View File

@ -15,7 +15,7 @@
#define PADHOOK 1
#define CONFIG_VERSION 0x00000001
#define DM_VERSION 0x00020000
#define DM_VERSION 0x00020001
#define DI_SUCCESS 1
#define DI_ERROR 2

1
main.c
View File

@ -122,7 +122,6 @@ void SysShutdown( void )
}
u32 fail;
FIL Log;
int main( int argc, char *argv[] )
{

View File

@ -362,39 +362,8 @@ void GeckoSendBuffer( char *buffer )
return;
}
extern FIL Log;
static char buffer[128] ALIGNED(32);
int dbgprintf( const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vsprintf(buffer, fmt, args);
va_end(args);
//u32 cokie = read32( 0x0D800070 );
//set32(0x0D800070,1);
if( read32( 0x0D800070 ) & 1 )
{
GeckoSendBuffer( buffer );
}/* else {
u32 read;
u32 fres = f_open( &Log, "/dm.log", FA_READ|FA_WRITE|FA_OPEN_ALWAYS );
if( fres != FR_OK )
{
write32( 0x0D800070, 1 );
dbgprintf("f_open():%d\n", fres );
}
f_lseek( &Log, Log.fsize );
f_write( &Log, buffer, strlen(buffer), &read );
f_close( &Log );
}*/
//write32( 0x0D800070, cokie );
return 1;
}