From 07f92c2489ee602161bfe94347e0d2a7771a04ef Mon Sep 17 00:00:00 2001 From: "crediar@rypp.net" Date: Tue, 17 Jul 2012 09:17:46 +0000 Subject: [PATCH] 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 --- Config.h | 6 +- Patches.c | 234 ++++++++++++++++++++++++----------------------------- dip.c | 149 ++++++++++++++++++++-------------- dip.h | 1 + elf.h | 74 +++++++++++++++++ global.h | 2 +- main.c | 1 - vsprintf.c | 31 ------- 8 files changed, 270 insertions(+), 228 deletions(-) create mode 100644 elf.h diff --git a/Config.h b/Config.h index a374642..860407e 100644 --- a/Config.h +++ b/Config.h @@ -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 diff --git a/Patches.c b/Patches.c index d7a7042..92103ef 100644 --- a/Patches.c +++ b/Patches.c @@ -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: { diff --git a/dip.c b/dip.c index b35fa88..bfbfb78 100644 --- a/dip.c +++ b/dip.c @@ -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 ); diff --git a/dip.h b/dip.h index b7e047e..fb8ea88 100644 --- a/dip.h +++ b/dip.h @@ -12,6 +12,7 @@ #include "vsprintf.h" #include "Config.h" #include "DVD.h" +#include "elf.h" enum opcodes { diff --git a/elf.h b/elf.h new file mode 100644 index 0000000..bd9b873 --- /dev/null +++ b/elf.h @@ -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 diff --git a/global.h b/global.h index 574fa4e..2140ed2 100644 --- a/global.h +++ b/global.h @@ -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 diff --git a/main.c b/main.c index fdc5d23..60797fc 100644 --- a/main.c +++ b/main.c @@ -122,7 +122,6 @@ void SysShutdown( void ) } u32 fail; -FIL Log; int main( int argc, char *argv[] ) { diff --git a/vsprintf.c b/vsprintf.c index b489bf9..117aaa0 100644 --- a/vsprintf.c +++ b/vsprintf.c @@ -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; }