diff --git a/out/bins/ext_booter.bin b/out/bins/ext_booter.bin index 7dd68c99..2a78c58f 100644 Binary files a/out/bins/ext_booter.bin and b/out/bins/ext_booter.bin differ diff --git a/out/boot.dol b/out/boot.dol index 120322eb..9e4da36f 100644 Binary files a/out/boot.dol and b/out/boot.dol differ diff --git a/resources/wiiflow_game_booter/source/ChannelHandler.cpp b/resources/wiiflow_game_booter/source/ChannelHandler.cpp index e1c104a3..4dd2dfda 100644 --- a/resources/wiiflow_game_booter/source/ChannelHandler.cpp +++ b/resources/wiiflow_game_booter/source/ChannelHandler.cpp @@ -42,11 +42,13 @@ #include "videopatch.h" #include "video_tinyload.h" #include "apploader.h" +#include "memory.h" void *dolchunkoffset[18]; u32 dolchunksize[18]; u32 dolchunkcount; u32 bootcontent; +bool isForwarder = false; char filepath[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32); @@ -78,29 +80,70 @@ static u8 *GetDol(u32 bootcontent, u64 title) static bool GetAppNameFromTmd(bool dol, u32 *bootcontent, u64 title, u32 *IOS) { - bool ret = false; - + static const u8 dolsign[6] = {0x00, 0x00, 0x01, 0x00, 0x00, 0x00}; + static u8 dolhead[32] ATTRIBUTE_ALIGN(32); + bool found = false; snprintf(filepath, ISFS_MAXPATH, "/title/%08x/%08x/content/title.tmd", TITLE_UPPER(title), TITLE_LOWER(title)); u32 size; u8 *data = ISFS_GetFile(filepath, &size, -1); if(data == NULL || size < 0x208) - return ret; + return found; *IOS = data[0x18B]; _tmd *tmd_file = (_tmd *)SIGNATURE_PAYLOAD((u32 *)data); - for(u16 i = 0; i < tmd_file->num_contents; ++i) + + if(dol) { - if(tmd_file->contents[i].index == (dol ? 0x01 : tmd_file->boot_index)) + // check for dol signature - channels and vc + for(u32 i = 0; i < tmd_file->num_contents; ++i) + { + if(tmd_file->contents[i].index == tmd_file->boot_index) + continue; // Skip app loader + + snprintf(filepath, ISFS_MAXPATH, "/title/%08x/%08x/content/%08x.app", TITLE_UPPER(title), TITLE_LOWER(title), tmd_file->contents[i].cid); + + s32 fd = ISFS_Open(filepath, ISFS_OPEN_READ); + if(fd < 0) + continue; + + s32 ret = ISFS_Read(fd, dolhead, 32); + ISFS_Close(fd); + + if(ret != 32) + continue; + + if(memcmp(dolhead, dolsign, sizeof(dolsign)) == 0) + { + // Normal channels and VC use 1 + if(tmd_file->contents[i].index != 1)// forwarder channel + isForwarder = true; + *bootcontent = tmd_file->contents[i].cid; + found = true; + break; + } + } + } + if(!found) // WiiWare not matching a dol signature or apploader selected + { + for(u32 i = 0; i < tmd_file->num_contents; ++i) { - *bootcontent = tmd_file->contents[i].cid; - ret = true; - break; + if(tmd_file->contents[i].index == (dol ? 0x01 : tmd_file->boot_index)) + { + *bootcontent = tmd_file->contents[i].cid; + found = true; + break; + } } } + //fall back to app loader if main dol wanted but not found + if(!found && dol) + { + *bootcontent = tmd_file->contents[tmd_file->boot_index].cid; + found = true; + } free(data); - - return ret; + return found; } static u32 MoveDol(u8 *buffer) @@ -108,10 +151,10 @@ static u32 MoveDol(u8 *buffer) dolchunkcount = 0; dolheader *dolfile = (dolheader *)buffer; - if(dolfile->bss_start) + if(dolfile->bss_start)// if start is not zero { - if(!(dolfile->bss_start & 0x80000000)) - dolfile->bss_start |= 0x80000000; + if(!(dolfile->bss_start & 0x80000000))// if start isn't >=80000000 + dolfile->bss_start |= 0x80000000;// set it to 80000000 or greater memset((void *)dolfile->bss_start, 0, dolfile->bss_size); DCFlushRange((void *)dolfile->bss_start, dolfile->bss_size); @@ -120,11 +163,11 @@ static u32 MoveDol(u8 *buffer) for(u8 i = 0; i < 18; i++) { - if(!dolfile->section_size[i]) + if(!dolfile->section_size[i])// if section size is zero don't move continue; - if(dolfile->section_pos[i] < sizeof(dolheader)) + if(dolfile->section_pos[i] < sizeof(dolheader)) // if section position is within the header don't move continue; - if(!(dolfile->section_start[i] & 0x80000000)) + if(!(dolfile->section_start[i] & 0x80000000)) // maker sure section start is 80000000 or greater dolfile->section_start[i] |= 0x80000000; dolchunkoffset[dolchunkcount] = (void *)dolfile->section_start[i]; @@ -146,11 +189,24 @@ u32 LoadChannel(u64 title, bool dol, u32 *IOS) entry = MoveDol(data); free(data); + // Preparations + memset((void *)Disc_ID, 0, 6); + *Disc_ID = TITLE_LOWER(title); // Game ID + *Arena_H = 0; // Arena High, the apploader does this too + *BI2 = 0x817FE000; // BI2, the apploader does this too + *Bus_Speed = 0x0E7BE2C0; // bus speed + *CPU_Speed = 0x2B73A840; // cpu speed + *GameID_Address = 0x81000000; // Game id address, while there's all 0s at 0x81000000 when using the apploader... + memcpy((void *)Online_Check, (void *)Disc_ID, 4); // online check + + memset((void *)0x817FE000, 0, 0x2000); // Clearing BI2 + DCFlushRange((void *)0x817FE000, 0x2000); + return entry; } void PatchChannel(u8 vidMode, GXRModeObj *vmode, bool vipatch, bool countryString, u8 patchVidModes, int aspectRatio, - u8 private_server, const char *server_addr, bool patchFix480p, u8 deflicker, u8 bootType) + u32 returnTo, u8 private_server, const char *server_addr, bool patchFix480p, u8 deflicker, u8 bootType) { u8 vfilter_off[7] = {0, 0, 21, 22, 21, 0, 0}; u8 vfilter_low[7] = {4, 4, 16, 16, 16, 4, 4}; @@ -169,6 +225,8 @@ void PatchChannel(u8 vidMode, GXRModeObj *vmode, bool vipatch, bool countryStrin PatchCountryStrings(dolchunkoffset[i], dolchunksize[i]); if(aspectRatio != -1) PatchAspectRatio(dolchunkoffset[i], dolchunksize[i], aspectRatio); + if(returnTo) + PatchReturnTo(dolchunkoffset[i], dolchunksize[i], returnTo); if(private_server) PrivateServerPatcher(dolchunkoffset[i], dolchunksize[i], private_server, server_addr); if(hooktype != 0 && hookpatched == false) @@ -207,4 +265,7 @@ void PatchChannel(u8 vidMode, GXRModeObj *vmode, bool vipatch, bool countryStrin if(patchFix480p) PatchFix480p(); + + if(private_server == PRIVSERV_WIIMMFI) + do_new_wiimmfi_nonMKWii(); } diff --git a/resources/wiiflow_game_booter/source/ChannelHandler.hpp b/resources/wiiflow_game_booter/source/ChannelHandler.hpp index d78dca50..f3b00e62 100644 --- a/resources/wiiflow_game_booter/source/ChannelHandler.hpp +++ b/resources/wiiflow_game_booter/source/ChannelHandler.hpp @@ -13,8 +13,10 @@ typedef struct _dolheader u32 padding[7]; } ATTRIBUTE_PACKED dolheader; -void PatchChannel(u8 vidMode, GXRModeObj *vmode, bool vipatch, bool countryString, - u8 patchVidModes, int aspectRatio, u8 private_server, const char *server_addr, bool patchFix480p, u8 deflicker, u8 bootType); +void PatchChannel(u8 vidMode, GXRModeObj *vmode, bool vipatch, bool countryString, u8 patchVidModes, int aspectRatio, + u32 returnTo, u8 private_server, const char *server_addr, bool patchFix480p, u8 deflicker, u8 bootType); u32 LoadChannel(u64 title, bool dol, u32 *IOS); +extern bool isForwarder; + #endif /* __CHANHANDLE_HPP_ */ diff --git a/resources/wiiflow_game_booter/source/apploader.c b/resources/wiiflow_game_booter/source/apploader.c index e33ce8bb..d3f6aa47 100644 --- a/resources/wiiflow_game_booter/source/apploader.c +++ b/resources/wiiflow_game_booter/source/apploader.c @@ -52,12 +52,14 @@ u32 Apploader_Run(u8 vidMode, GXRModeObj *vmode, bool vipatch, bool countryStrin bool patchregion , u8 private_server, const char *server_addr, bool patchFix480p, u8 deflicker, u8 bootType) { //! Disable private server for games that still have official servers. - if (memcmp(GameID, "SC7", 3) == 0 || memcmp(GameID, "RJA", 3) == 0 || + if(memcmp(GameID, "SC7", 3) == 0 || memcmp(GameID, "RJA", 3) == 0 || memcmp(GameID, "SM8", 3) == 0 || memcmp(GameID, "SZB", 3) == 0 || memcmp(GameID, "R9J", 3) == 0) { private_server = PRIVSERV_OFF; // Private server patching causes error 20100 } + // if either of these 2 games - adds internal wip codes before do_wip_code() is called in maindolpatches() + // note: using external .wip codes for these games will prevent their internal codes. PrinceOfPersiaPatch(); NewSuperMarioBrosPatch(); @@ -118,21 +120,35 @@ u32 Apploader_Run(u8 vidMode, GXRModeObj *vmode, bool vipatch, bool countryStrin if(hooktype != 0 && hookpatched) ocarina_do_code(); - if(patchFix480p) + //! Apply the 480p fix. + //! This needs to be done after the call to maindolpatches(), after loading any code handler. + //! Can (and should) be done before Wiimmfi patching, can't be done in maindolpatches() itself. + //! Exclude Prince of Persia: The Forgotten Sands and a few games that use MetaFortress + bool excludeGame = false; + if(memcmp(GameID, "RPW", 3) == 0 || memcmp(GameID, "SPX", 3) == 0 || + memcmp(GameID, "R3D", 3) == 0 || memcmp(GameID, "SDV", 3) == 0 || + memcmp(GameID, "SUK", 3) == 0 || memcmp(GameID, "STN", 3) == 0 || + memcmp(GameID, "S7S", 3) == 0 || memcmp(GameID, "SDUP41", 6) == 0 || + memcmp(GameID, "SDUE41", 6) == 0 || memcmp(GameID, "SDUX41", 6) == 0) + { + excludeGame = true; + } + + if(patchFix480p && !excludeGame) PatchFix480p(); - //! If we're NOT on Wiimmfi, patch the known RCE vulnerability in MKWii. + //! If we're NOT on Wiimmfi, patch the known Remote Code Execution (RCE) vulnerability in MKWii. //! Wiimmfi will handle that on its own through the update payload. //! This will also patch error 23400 for a couple games that still have official servers. if(private_server != PRIVSERV_WIIMMFI) Patch_23400_and_MKWii_vulnerability(); - else //wiimmfi patch + else //PRIVSERV_WIIMMFI { if(memcmp("RMC", GameID, 3) != 0)// This isn't MKWii, perform the patch for other games. - do_new_wiimmfi_nonMKWii(); + do_new_wiimmfi_nonMKWii();// does not patch the server address - done in maindolpatches() else // This is MKWii, perform the known patch from 2018. - do_new_wiimmfi(); + do_new_wiimmfi();// includes patching the server address } /* Set entry point from apploader */ @@ -174,7 +190,7 @@ void maindolpatches(void *dst, int len, u8 vidMode, GXRModeObj *vmode, bool vipa if(patchregion) PatchRegion(dst, len); if(private_server) - PrivateServerPatcher(dst, len, private_server, serverAddr); + PrivateServerPatcher(dst, len, private_server, serverAddr); if(deflicker == DEFLICKER_ON_LOW) { diff --git a/resources/wiiflow_game_booter/source/disc.c b/resources/wiiflow_game_booter/source/disc.c index a40f0b33..12ebf283 100644 --- a/resources/wiiflow_game_booter/source/disc.c +++ b/resources/wiiflow_game_booter/source/disc.c @@ -18,7 +18,7 @@ s32 Disc_Open(u8 type) { - if(type > 0) + if(type > 0)// if not a wii disc (wbfs ext or wbfs drive) { /* Reset drive */ s32 ret = WDVD_Reset(); if(ret < 0) @@ -29,23 +29,7 @@ s32 Disc_Open(u8 type) return WDVD_ReadDiskId((u8*)Disc_ID); } -void Disc_SetLowMemPre() -{ - /* Setup low memory before Apploader */ - *BI2 = 0x817E5480; // BI2 - *(vu32*)0xCD00643C = 0x00000000; // 32Mhz on Bus - - /* Clear Disc ID */ - memset((u8*)Disc_ID, 0, 32); - - /* For WiiRD */ - memset((void*)0x80001800, 0, 0x1800); - - /* Flush everything */ - DCFlushRange((void*)0x80000000, 0x3f00); -} - -void Disc_SetLowMem(u32 IOS) +void Disc_SetLowMem(void) { /* Setup low memory */ *Sys_Magic = 0x0D15EA5E; // Standard Boot Code @@ -58,35 +42,10 @@ void Disc_SetLowMem(u32 IOS) *Dev_Debugger = 0x81800000; // Dev Debugger Monitor Address *Simulated_Mem = 0x01800000; // Simulated Memory Size *GameID_Address = 0x80000000; // Fix for Sam & Max (WiiPower) + *(vu32 *) 0xCD00643C = 0x00000000; // 32Mhz on Bus /* Copy Disc ID */ memcpy((void*)Online_Check, (void*)Disc_ID, 4); - - /* For WiiRD */ - memcpy((void*)0x80001800, (void*)Disc_ID, 8); - - /* Error 002 Fix (thanks WiiPower and uLoader) */ - *Current_IOS = (IOS << 16) | 0xffff; - *Apploader_IOS = (IOS << 16) | 0xffff; - - /* Flush everything */ - DCFlushRange((void*)0x80000000, 0x3f00); -} - -/* Thanks to triiforce for that code */ -void Disc_SetLowMemChan() -{ - /* Setup low mem */ - *Arena_H = 0x00000000; // Arena High, the appldr does this too - *BI2 = 0x817FE000; // BI2, the appldr does this too - *GameID_Address = 0x81000000; // Game id address, 0s at 0x81000000 with appldr - - /* Flush low mem */ - DCFlushRange((void*)0x80000000, 0x3f00); - - /* Clear BI2 */ - memset((void *)0x817FE000, 0, 0x2000); - DCFlushRange((void*)0x817FE000, 0x2000); } /* Thanks Tinyload */ diff --git a/resources/wiiflow_game_booter/source/disc.h b/resources/wiiflow_game_booter/source/disc.h index 3e58d2fe..6be916e8 100644 --- a/resources/wiiflow_game_booter/source/disc.h +++ b/resources/wiiflow_game_booter/source/disc.h @@ -9,9 +9,7 @@ extern "C" { s32 Disc_Open(u8 type); s32 Disc_FindPartition(u32 *outbuf); s32 Disc_SetUSB(const u8 *id, bool frag); -void Disc_SetLowMemPre(); -void Disc_SetLowMem(u32 IOS); -void Disc_SetLowMemChan(); +void Disc_SetLowMem(); GXRModeObj *Disc_SelectVMode(u8 videoselected, u32 *rmode_reg); void Disc_SetVMode(GXRModeObj *rmode, u32 rmode_reg); diff --git a/resources/wiiflow_game_booter/source/fst.c b/resources/wiiflow_game_booter/source/fst.c index 42f3c794..9e4e7dc1 100644 --- a/resources/wiiflow_game_booter/source/fst.c +++ b/resources/wiiflow_game_booter/source/fst.c @@ -144,6 +144,7 @@ void app_pokevalues() void load_handler() { + memset((void*)0x80001800, 0, 0x1800); if(debuggerselect == 0x01) { gprintf("Ocarina: Debugger selected.\n"); diff --git a/resources/wiiflow_game_booter/source/main.cpp b/resources/wiiflow_game_booter/source/main.cpp index 432780d0..6ada3b13 100644 --- a/resources/wiiflow_game_booter/source/main.cpp +++ b/resources/wiiflow_game_booter/source/main.cpp @@ -56,12 +56,12 @@ int main() InitGecko(); gprintf("WiiFlow External Booter by FIX94\n"); memcpy(&normalCFG, ((void*)*EXT_ADDR_CFG), sizeof(the_CFG)); - VIDEO_Init(); - video_init(); + VIDEO_Init();// libogc + video_init();// tinyload progress bar prog10(); - configbytes[0] = normalCFG.configbytes[0]; - configbytes[1] = normalCFG.configbytes[1]; + configbytes[0] = normalCFG.configbytes[0];// game language 0 - 9 or 0xCD = not patched + configbytes[1] = normalCFG.configbytes[1];// not used hooktype = normalCFG.hooktype; debuggerselect = normalCFG.debugger; CurrentIOS = normalCFG.IOS; @@ -73,9 +73,6 @@ int main() wbfs_part_idx = normalCFG.wbfsPart; prog10(); - /* Setup Low Memory */ - Disc_SetLowMemPre(); - if(normalCFG.BootType == TYPE_WII_GAME) { WDVD_Init(); @@ -103,6 +100,7 @@ int main() u32 offset = 0; Disc_FindPartition(&offset); WDVD_OpenPartition(offset, &GameIOS); + Disc_SetLowMem(); if(normalCFG.vidMode == 5) normalCFG.patchVidMode = 1; //progressive mode requires this vmode = Disc_SelectVMode(normalCFG.vidMode, &vmode_reg); @@ -112,22 +110,24 @@ int main() } else if(normalCFG.BootType == TYPE_CHANNEL) { - ISFS_Initialize(); - *Disc_ID = TITLE_LOWER(normalCFG.title); vmode = Disc_SelectVMode(normalCFG.vidMode, &vmode_reg); + ISFS_Initialize(); AppEntrypoint = LoadChannel(normalCFG.title, normalCFG.use_dol, &GameIOS); - PatchChannel(normalCFG.vidMode, vmode, normalCFG.vipatch, normalCFG.countryString, normalCFG.patchVidMode, normalCFG.aspectRatio, - normalCFG.private_server, normalCFG.server_addr, normalCFG.patchFix480p, normalCFG.deflicker, normalCFG.BootType); ISFS_Deinitialize(); + PatchChannel(normalCFG.vidMode, vmode, normalCFG.vipatch, normalCFG.countryString, normalCFG.patchVidMode, normalCFG.aspectRatio, + normalCFG.returnTo, normalCFG.private_server, normalCFG.server_addr, normalCFG.patchFix480p, normalCFG.deflicker, normalCFG.BootType); } gprintf("Entrypoint: %08x, Requested Game IOS: %i\n", AppEntrypoint, GameIOS); setprog(320); - /* Setup Low Memory */ - Disc_SetLowMem(GameIOS); - if(normalCFG.BootType == TYPE_CHANNEL && AppEntrypoint != 0x3400) - Disc_SetLowMemChan(); /* Real DOL without appldr */ - + /* Error 002 Fix (thanks WiiPower and uLoader) */ + *Current_IOS = (GameIOS << 16) | 0xffff; + if(!isForwarder) + *Apploader_IOS = (GameIOS << 16) | 0xffff; + + /* Flush everything */ + DCFlushRange((void*)0x80000000, 0x3f00); + /* Enable front LED if requested */ if(normalCFG.use_led) *HW_GPIOB_OUT |= 0x20; diff --git a/resources/wiiflow_game_booter/source/patchcode.c b/resources/wiiflow_game_booter/source/patchcode.c index c5117da2..b00ec66c 100644 --- a/resources/wiiflow_game_booter/source/patchcode.c +++ b/resources/wiiflow_game_booter/source/patchcode.c @@ -357,140 +357,148 @@ void PatchVideoSneek(void *addr, u32 len) } } -//giantpune's magic super patch to return to channels +// giantpune's magic super patch to return to channels -static u32 ad[ 4 ] = { 0, 0, 0, 0 };//these variables are global on the off chance the different parts needed -static u8 found = 0; //to find in the dol are found in different sections of the dol +static u32 ad[4] = {0, 0, 0, 0}; // these variables are global on the off chance the different parts needed +static u8 found = 0; // to find in the dol are found in different sections of the dol static u8 returnToPatched = 0; -bool PatchReturnTo( void *Address, int Size, u32 id ) +bool PatchReturnTo(void *Address, int Size, u32 id) { - if( !id || returnToPatched ) - return 0; - //gprintf("PatchReturnTo( %p, %08x, %08x )\n", Address, Size, id ); + if(!id || returnToPatched) + return 0; + //gprintf("PatchReturnTo( %p, %08x, %08x )\n", Address, Size, id ); - //new __OSLoadMenu() (SM2.0 and higher) - u8 SearchPattern[ 12 ] = { 0x38, 0x80, 0x00, 0x02, 0x38, 0x60, 0x00, 0x01, 0x38, 0xa0, 0x00, 0x00 }; //li r4,2 - //li r3,1 - //li r5,0 - //old _OSLoadMenu() (used in launch games) - u8 SearchPatternB[ 12 ] = { 0x38, 0xC0, 0x00, 0x02, 0x38, 0xA0, 0x00, 0x01, 0x38, 0xE0, 0x00, 0x00 }; //li r6,2 - //li r5,1 - //li r7,0 - //identifier for the safe place - u8 SearchPattern2[ 12 ] = { 0x4D, 0x65, 0x74, 0x72, 0x6F, 0x77, 0x65, 0x72, 0x6B, 0x73, 0x20, 0x54 }; //"Metrowerks T" + // new __OSLoadMenu() (SM2.0 and higher) + u8 SearchPattern[12] = {0x38, 0x80, 0x00, 0x02, 0x38, 0x60, 0x00, 0x01, 0x38, 0xa0, 0x00, 0x00}; // li r4,2 + // li r3,1 + // li r5,0 + // old _OSLoadMenu() (used in launch games) + u8 SearchPatternB[12] = {0x38, 0xC0, 0x00, 0x02, 0x38, 0xA0, 0x00, 0x01, 0x38, 0xE0, 0x00, 0x00}; // li r6,2 + // li r5,1 + // li r7,0 + // identifier for the safe place + u8 SearchPattern2[12] = {0x4D, 0x65, 0x74, 0x72, 0x6F, 0x77, 0x65, 0x72, 0x6B, 0x73, 0x20, 0x54}; // "Metrowerks T" - u8 oldSDK = 0; - found = 0; + u8 oldSDK = 0; + found = 0; - void *Addr = Address; - void *Addr_end = Address+Size; + void *Addr = Address; + void *Addr_end = Address + Size; - while (Addr <= Addr_end - 12 ) - { - //find a safe place or the patch to hang out - if ( ! ad[ 3 ] && memcmp( Addr, SearchPattern2, 12 ) == 0 ) - { - ad[ 3 ] = (u32)Addr + 0x30; - } - //find __OSLaunchMenu() and remember some addresses in it - else if ( memcmp( Addr, SearchPattern, 12 )==0 ) - { - ad[ found++ ] = (u32)Addr; - } - else if ( ad[ 0 ] && memcmp( Addr, SearchPattern, 8 )==0 ) //after the first match is found, only search the first 8 bytes for the other 2 - { - if( !ad[ 1 ] ) ad[ found++ ] = (u32)Addr; - else if( !ad[ 2 ] ) ad[ found++ ] = (u32)Addr; - if( found >= 3 )break; - } - Addr += 4; - } - //check for the older-ass version of the SDK - if( found < 3 && ad[ 3 ] ) - { - Addr = Address; - ad[ 0 ] = 0; - ad[ 1 ] = 0; - ad[ 2 ] = 0; - found = 0; - oldSDK = 1; + while(Addr <= Addr_end - 12) + { + // find a safe place for the patch to hang out + if(!ad[3] && memcmp(Addr, SearchPattern2, 12) == 0) + { + ad[3] = (u32)Addr + 0x30; + } + // find __OSLaunchMenu() and remember some addresses in it + else if(memcmp(Addr, SearchPattern, 12) == 0) + { + ad[found++] = (u32)Addr; + } + else if(ad[0] && memcmp(Addr, SearchPattern, 8) == 0) // after the first match is found, only search the first 8 bytes for the other 2 + { + if(!ad[1]) + ad[found++] = (u32)Addr; + else if(!ad[2]) + ad[found++] = (u32)Addr; + if(found >= 3) + break; + } + Addr += 4; + } + // check for the older-ass version of the SDK + if(found < 3 && ad[3]) + { + Addr = Address; + ad[0] = 0; + ad[1] = 0; + ad[2] = 0; + found = 0; + oldSDK = 1; - while (Addr <= Addr_end - 12 ) - { - //find __OSLaunchMenu() and remember some addresses in it - if ( memcmp( Addr, SearchPatternB, 12 )==0 ) - { - ad[ found++ ] = (u32)Addr; - } - else if ( ad[ 0 ] && memcmp( Addr, SearchPatternB, 8 ) == 0 ) //after the first match is found, only search the first 8 bytes for the other 2 - { - if( !ad[ 1 ] ) ad[ found++ ] = (u32)Addr; - else if( !ad[ 2 ] ) ad[ found++ ] = (u32)Addr; - if( found >= 3 )break; - } - Addr += 4; - } - } + while(Addr <= Addr_end - 12) + { + // find __OSLaunchMenu() and remember some addresses in it + if(memcmp(Addr, SearchPatternB, 12) == 0) + { + ad[found++] = (u32)Addr; + } + else if(ad[0] && memcmp(Addr, SearchPatternB, 8) == 0) // after the first match is found, only search the first 8 bytes for the other 2 + { + if(!ad[1]) + ad[found++] = (u32)Addr; + else if(!ad[2]) + ad[found++] = (u32)Addr; + if(found >= 3) + break; + } + Addr += 4; + } + } - //if the function is found - if( found == 3 && ad[ 3 ] ) - { - gprintf("patch __OSLaunchMenu( 0x00010001, 0x%08x )\n", id); - u32 nop = 0x60000000; + // if the function is found + if(found == 3 && ad[3]) + { + //gprintf("patch __OSLaunchMenu( 0x00010001, 0x%08x )\n", id); + u32 nop = 0x60000000; - //the magic that writes the TID to the registers - u8 jump[ 20 ] = { 0x3C, 0x60, 0x00, 0x01, //lis r3,1 - 0x60, 0x63, 0x00, 0x01, //ori r3,r3,1 - 0x3C, 0x80, (u8)( id >> 24 ), (u8)( id >> 16 ), //lis r4,(u16)(tid >> 16) - 0x60, 0x84, (u8)( id >> 8 ), (u8)id, //ori r4,r4,(u16)(tid) - 0x4E, 0x80, 0x00, 0x20 - }; //blr + // the magic that writes the TID to the registers + u8 jump[20] = { + 0x3C, 0x60, 0x00, 0x01, // lis r3,1 + 0x60, 0x63, 0x00, 0x01, // ori r3,r3,1 + 0x3C, 0x80, (u8)(id >> 24), (u8)(id >> 16), // lis r4,(u16)(tid >> 16) + 0x60, 0x84, (u8)(id >> 8), (u8)id, // ori r4,r4,(u16)(tid) + 0x4E, 0x80, 0x00, 0x20}; // blr - if( oldSDK ) - { - jump[ 1 ] = 0xA0; //3CA00001 //lis r5,1 - jump[ 5 ] = 0xA5; //60A50001 //ori r5,r5,1 - jump[ 9 ] = 0xC0; //3CC0AF1B //lis r6,(u16)(tid >> 16) - jump[ 13 ] = 0xC6;//60C6F516 //ori r6,r6,(u16)(tid) - } + if(oldSDK) + { + jump[1] = 0xA0; // 3CA00001 // lis r5,1 + jump[5] = 0xA5; // 60A50001 // ori r5,r5,1 + jump[9] = 0xC0; // 3CC0AF1B // lis r6,(u16)(tid >> 16) + jump[13] = 0xC6; // 60C6F516 // ori r6,r6,(u16)(tid) + } - void* addr = (u32*)ad[ 3 ]; + void *addr = (u32 *)ad[3]; - //write new stuff to in a unused part of the main.dol - memcpy( addr, jump, sizeof( jump ) ); + // write new stuff to in a unused part of the main.dol + memcpy(addr, jump, sizeof(jump)); - //ES_GetTicketViews() - u32 newval = ( ad[ 3 ] - ad[ 0 ] ); - newval &= 0x03FFFFFC; - newval |= 0x48000001; - addr = (u32*)ad[ 0 ]; - memcpy( addr, &newval, sizeof( u32 ) ); //bl ad[ 3 ] - memcpy( addr + 4, &nop, sizeof( u32 ) ); //nop - //gprintf("\t%08x -> %08x\n", addr, newval ); + // ES_GetTicketViews() + u32 newval = (ad[3] - ad[0]); + newval &= 0x03FFFFFC; + newval |= 0x48000001; + addr = (u32 *)ad[0]; + memcpy(addr, &newval, sizeof(u32)); // bl ad[ 3 ] + memcpy(addr + 4, &nop, sizeof(u32)); // nop + //gprintf("\t%08x -> %08x\n", addr, newval ); - //ES_GetTicketViews() again - newval = ( ad[ 3 ] - ad[ 1 ] ); - newval &= 0x03FFFFFC; - newval |= 0x48000001; - addr = (u32*)ad[ 1 ]; - memcpy( addr, &newval, sizeof( u32 ) ); //bl ad[ 3 ] - memcpy( addr + 4, &nop, sizeof( u32 ) ); //nop - //gprintf("\t%08x -> %08x\n", addr, newval ); + // ES_GetTicketViews() again + newval = (ad[3] - ad[1]); + newval &= 0x03FFFFFC; + newval |= 0x48000001; + addr = (u32 *)ad[1]; + memcpy(addr, &newval, sizeof(u32)); // bl ad[ 3 ] + memcpy(addr + 4, &nop, sizeof(u32)); // nop + //gprintf("\t%08x -> %08x\n", addr, newval ); - //ES_LaunchTitle() - newval = ( ad[ 3 ] - ad[ 2 ] ); - newval &= 0x03FFFFFC; - newval |= 0x48000001; - addr = (u32*)ad[ 2 ]; - memcpy( addr, &newval, sizeof( u32 ) ); //bl ad[ 3 ] - memcpy( addr + 4, &nop, sizeof( u32 ) ); //nop - //gprintf("\t%08x -> %08x\n", addr, newval ); + // ES_LaunchTitle() + newval = (ad[3] - ad[2]); + newval &= 0x03FFFFFC; + newval |= 0x48000001; + addr = (u32 *)ad[2]; + memcpy(addr, &newval, sizeof(u32)); // bl ad[ 3 ] + memcpy(addr + 4, &nop, sizeof(u32)); // nop + //gprintf("\t%08x -> %08x\n", addr, newval ); - returnToPatched = 1; - } + returnToPatched = 1; + } + if(returnToPatched) + gprintf("Return to %08X patched with old method.\n", (u32)id); - return returnToPatched; + return returnToPatched; } void PatchAspectRatio(void *addr, u32 len, u8 aspect) @@ -513,7 +521,7 @@ void PatchAspectRatio(void *addr, u32 len, u8 aspect) while(addr_start < addr_end) { - if( (memcmp(addr_start, aspect_searchpattern1, sizeof(aspect_searchpattern1)) == 0) + if((memcmp(addr_start, aspect_searchpattern1, sizeof(aspect_searchpattern1)) == 0) && (memcmp(addr_start + 4 + sizeof(aspect_searchpattern1), aspect_searchpattern2, sizeof(aspect_searchpattern2)) == 0)) { *((u32 *)(addr_start+0x44)) = (0x38600000 | aspect); diff --git a/source/channel/channels.cpp b/source/channel/channels.cpp index fae248e3..a4089bcc 100644 --- a/source/channel/channels.cpp +++ b/source/channel/channels.cpp @@ -108,7 +108,7 @@ u64 *Channels::GetChannelList(u32 *count) return titles; } -bool Channels::GetAppNameFromTmd(u64 title, char *app, u32 *bootcontent) +bool Channels::GetAppNameFromTmd(u64 title, char *app, u32 *bootcontent)// get banner .app name { bool ret = false; u32 size = 0; @@ -128,10 +128,9 @@ bool Channels::GetAppNameFromTmd(u64 title, char *app, u32 *bootcontent) return ret; } _tmd *tmd_file = (_tmd *)SIGNATURE_PAYLOAD((u32 *)data); - u16 i; - for(i = 0; i < tmd_file->num_contents; ++i) + for(u32 i = 0; i < tmd_file->num_contents; ++i) { - if(tmd_file->contents[i].index == 0) + if(tmd_file->contents[i].index == 0)// banner app { *bootcontent = tmd_file->contents[i].cid; snprintf(app, ISFS_MAXPATH, "/title/%08x/%08x/content/%08x.app", TITLE_UPPER(title), TITLE_LOWER(title), *bootcontent); diff --git a/source/defines.h b/source/defines.h index 0b1f34c7..9bd75920 100644 --- a/source/defines.h +++ b/source/defines.h @@ -1,6 +1,6 @@ #define APP_NAME "WiiFlow WFL" -#define APP_VERSION "5.5.0 beta 11" +#define APP_VERSION "5.5.0 beta 12" #define APP_DATA_DIR "wiiflow" #define APPS_DIR "apps/wiiflow" diff --git a/source/menu/menu_game_boot.cpp b/source/menu/menu_game_boot.cpp index 2184f9d8..62ecfc82 100644 --- a/source/menu/menu_game_boot.cpp +++ b/source/menu/menu_game_boot.cpp @@ -705,7 +705,7 @@ int CMenu::_loadGameIOS(u8 gameIOS, int userIOS, string id, bool RealNAND_Channe if(RealNAND_Channels && IOS_GetType(mainIOS) == IOS_TYPE_STUB) { /* doesn't use cIOS so we don't check userIOS */ - bool ret = loadIOS(gameIOS, false);//load game requested IOS and patch nothing + bool ret = loadIOS(gameIOS, false);//load game requested IOS and do not remount sd and USB if(has_enabled_providers() || m_use_wifi_gecko) _initAsyncNetwork();// needed after IOS change if(ret == false) @@ -740,7 +740,7 @@ int CMenu::_loadGameIOS(u8 gameIOS, int userIOS, string id, bool RealNAND_Channe if(gameIOS != CurrentIOS.Version) { gprintf("Reloading IOS into %d\n", gameIOS); - bool ret = loadIOS(gameIOS, true);// cIOS patch everything + bool ret = loadIOS(gameIOS, true);//load cIOS requested and then remount sd and USB devices if(has_enabled_providers() || m_use_wifi_gecko) _initAsyncNetwork();// always seem to do netinit after changing IOS if(ret == false) @@ -755,39 +755,52 @@ int CMenu::_loadGameIOS(u8 gameIOS, int userIOS, string id, bool RealNAND_Channe void CMenu::_launchChannel(dir_discHdr *hdr) { - NANDemuView = hdr->type == TYPE_EMUCHANNEL; - /* clear coverflow, start wiiflow wait animation, set exit handler */ _launchShutdown(); - string id = string(hdr->id); - /* WII_Launch is used for launching real nand channels */ + NANDemuView = hdr->type == TYPE_EMUCHANNEL; + string id = string(hdr->id); + u64 gameTitle = TITLE_ID(hdr->settings[0],hdr->settings[1]); + m_gcfg1.setInt("PLAYCOUNT", id, m_gcfg1.getInt("PLAYCOUNT", id, 0) + 1); + m_gcfg1.setUInt("LASTPLAYED", id, time(NULL)); + + bool hbc = false; + if(gameTitle == HBC_OHBC || gameTitle == HBC_LULZ || gameTitle == HBC_108 || gameTitle == HBC_JODI || gameTitle == HBC_HAXX) + hbc = true; + + /* WII_Launch is used only for launching real nand channels */ + /* note: no patches, cheats, or cIOS settings allowed */ bool WII_Launch = (m_gcfg2.getBool(id, "custom", false) && !NANDemuView); + if(WII_Launch || (hbc && !NANDemuView)) + { + /* configs no longer needed */ + m_gcfg1.save(true); + m_gcfg2.save(true); + m_cat.save(true); + m_cfg.save(true); + cleanup();//no more error messages we can now cleanup + ShutdownBeforeExit(); + WII_Initialize(); + WII_LaunchTitle(gameTitle); + } + /* use_dol = true to use the channels dol or false to use the old apploader method to boot channel */ bool use_dol = !m_gcfg2.getBool(id, "apploader", false); - - bool vipatch = m_gcfg2.getBool(id, "vipatch", false); - bool cheat = m_gcfg2.getBool(id, "cheat", false); - bool countryPatch = m_gcfg2.getBool(id, "country_patch", false); - - u8 videoMode = min(m_gcfg2.getUInt(id, "video_mode", 0), ARRAY_SIZE(CMenu::_VideoModes) - 1u); - videoMode = (videoMode == 0) ? min(m_cfg.getUInt("GENERAL", "video_mode", 0), ARRAY_SIZE(CMenu::_GlobalVideoModes) - 1u) : videoMode - 1; + bool use_led = m_gcfg2.getBool(id, "led", false); int language = min(m_gcfg2.getUInt(id, "language", 0), ARRAY_SIZE(CMenu::_languages) - 1u); language = (language == 0) ? min(m_cfg.getUInt("GENERAL", "game_language", 0), ARRAY_SIZE(CMenu::_languages) - 1u) : language; + bool vipatch = m_gcfg2.getBool(id, "vipatch", false); + bool countryPatch = m_gcfg2.getBool(id, "country_patch", false); + + u8 videoMode = min(m_gcfg2.getUInt(id, "video_mode", 0), ARRAY_SIZE(CMenu::_VideoModes) - 1u); + videoMode = (videoMode == 0) ? min(m_cfg.getUInt("GENERAL", "video_mode", 0), ARRAY_SIZE(CMenu::_GlobalVideoModes) - 1u) : videoMode - 1; + u8 patchVidMode = min(m_gcfg2.getUInt(id, "patch_video_modes", 0), ARRAY_SIZE(CMenu::_vidModePatch) - 1u); s8 aspectRatio = min(m_gcfg2.getUInt(id, "aspect_ratio", 0), ARRAY_SIZE(CMenu::_AspectRatio) - 1) - 1;// -1,0,1 - u8 private_server = m_gcfg2.getUInt(id, "private_server", 0); - string server_addr = ""; - if(private_server > 2) - { - vector custom_servers = stringToVector(m_cfg.getString("custom_servers", "servers"), '|'); - server_addr = m_cfg.getString("custom_servers", fmt("%s_url", custom_servers[private_server - 3]), ""); - } - int fix480pVal = m_gcfg2.getOptBool(id, "fix480p", 2); bool fix480p = fix480pVal == 0 ? false : (fix480pVal == 1 ? true : m_cfg.getBool(WII_DOMAIN, "fix480p", false)); @@ -796,6 +809,14 @@ void CMenu::_launchChannel(dir_discHdr *hdr) u8 deflicker = min(m_gcfg2.getUInt(id, "deflicker_wii", 0), ARRAY_SIZE(CMenu::_DeflickerOptions) - 1u); deflicker = (deflicker == 0) ? min(m_cfg.getUInt("GENERAL", "deflicker_wii", 0), ARRAY_SIZE(CMenu::_GlobalDeflickerOptions) - 1u) : deflicker - 1; + u8 private_server = m_gcfg2.getUInt(id, "private_server", 0); + string server_addr = ""; + if(private_server > 2) + { + vector custom_servers = stringToVector(m_cfg.getString("custom_servers", "servers"), '|'); + server_addr = m_cfg.getString("custom_servers", fmt("%s_url", custom_servers[private_server - 3]), ""); + } + u32 returnTo = 0; const char *rtrn = m_cfg.getString("GENERAL", "returnto").c_str(); if(strlen(rtrn) == 4) @@ -803,31 +824,26 @@ void CMenu::_launchChannel(dir_discHdr *hdr) u8 *cheatFile = NULL; u32 cheatSize = 0; - if(!WII_Launch) - { - hooktype = (u32) m_gcfg2.getInt(id, "hooktype", 0); - debuggerselect = m_gcfg2.getInt(id, "debugger", 0); - if((cheat || debuggerselect == 1) && hooktype == 0) - hooktype = 1; - else if(!cheat && debuggerselect != 1) - hooktype = 0; + bool cheat = m_gcfg2.getBool(id, "cheat", false); + hooktype = (u32) m_gcfg2.getInt(id, "hooktype", 0); + debuggerselect = m_gcfg2.getInt(id, "debugger", 0); + if((cheat || debuggerselect == 1) && hooktype == 0) + hooktype = 1; + else if(!cheat && debuggerselect != 1) + hooktype = 0; + if(cheat) + _loadFile(cheatFile, cheatSize, m_cheatDir.c_str(), fmt("%s.gct", id.c_str())); - if(cheat) - _loadFile(cheatFile, cheatSize, m_cheatDir.c_str(), fmt("%s.gct", id.c_str())); - if(has_enabled_providers() && _initNetwork() == 0) - add_game_to_card(id.c_str()); - } - m_gcfg1.setInt("PLAYCOUNT", id, m_gcfg1.getInt("PLAYCOUNT", id, 0) + 1); - m_gcfg1.setUInt("LASTPLAYED", id, time(NULL)); + if(has_enabled_providers() && _initNetwork() == 0) + add_game_to_card(id.c_str()); + int userIOS = m_gcfg2.getInt(id, "ios", 0); + u32 gameIOS = ChannelHandle.GetRequestedIOS(gameTitle); + //interesting - there is only a global option for nand emulation - no per game choice int emulate_mode = min(max(0, m_cfg.getInt(CHANNEL_DOMAIN, "emulation", 1)), (int)ARRAY_SIZE(CMenu::_NandEmu) - 1); - int userIOS = m_gcfg2.getInt(id, "ios", 0); - u64 gameTitle = TITLE_ID(hdr->settings[0],hdr->settings[1]); bool useNK2o = m_gcfg2.getBool(id, "useneek", false);//if not in neek2o and use neek is set - bool use_led = m_gcfg2.getBool(id, "led", false); - u32 gameIOS = ChannelHandle.GetRequestedIOS(gameTitle); if(NANDemuView) { @@ -871,11 +887,13 @@ void CMenu::_launchChannel(dir_discHdr *hdr) } } } - if(WII_Launch == false && ExternalBooter_LoadBins(m_binsDir.c_str()) == false) + + if(ExternalBooter_LoadBins(m_binsDir.c_str()) == false) { error(_t("errgame15", L"Missing ext_loader.bin or ext_booter.bin!")); _exitWiiflow(); } + if(_loadGameIOS(gameIOS, userIOS, id, !NANDemuView) == LOAD_IOS_FAILED) { /* error message already shown */ @@ -885,8 +903,9 @@ void CMenu::_launchChannel(dir_discHdr *hdr) if(CurrentIOS.Type == IOS_TYPE_D2X && returnTo != 0) { if(D2X_PatchReturnTo(returnTo) >= 0) - memset(&returnTo, 0, sizeof(u32));// not needed - always set to 0 in external booter below + memset(&returnTo, 0, sizeof(u32));//Already patched - no need for giantpune patch in external booter } + if(NANDemuView) { /* Enable our Emu NAND */ @@ -912,26 +931,18 @@ void CMenu::_launchChannel(dir_discHdr *hdr) mask32(0xd8006a8, 0, 2); } - if(WII_Launch) - { - ShutdownBeforeExit(); - WII_Initialize(); - WII_LaunchTitle(gameTitle); - } - else - { - setLanguage(language); - ocarina_load_code(cheatFile, cheatSize); - if(cheatFile != NULL) - MEM2_free(cheatFile); - NandHandle.Patch_AHB(); /* Identify maybe uses it so keep AHBPROT disabled */ - PatchIOS(true, isWiiVC); /* Patch for everything */ - Identify(gameTitle); + setLanguage(language);// set configbyte[0] for external booter + ocarina_load_code(cheatFile, cheatSize);// copy to address used by external booter + if(cheatFile != NULL) + MEM2_free(cheatFile); + NandHandle.Patch_AHB(); /* Identify maybe uses it so keep AHBPROT disabled */ + PatchIOS(true, isWiiVC); /* Patch cIOS for everything */ + Identify(gameTitle);// identify title with E-Ticket Service (ES) module + + ExternalBooter_ChannelSetup(gameTitle, use_dol); + WiiFlow_ExternalBooter(videoMode, vipatch, countryPatch, patchVidMode, aspectRatio, private_server, server_addr.c_str(), + fix480p, deflicker, 0, TYPE_CHANNEL, use_led); - ExternalBooter_ChannelSetup(gameTitle, use_dol); - WiiFlow_ExternalBooter(videoMode, vipatch, countryPatch, patchVidMode, aspectRatio, private_server, server_addr.c_str(), - fix480p, deflicker, 0, TYPE_CHANNEL, use_led); - } Sys_Exit(); } @@ -1101,7 +1112,7 @@ void CMenu::_launchWii(dir_discHdr *hdr, bool dvd, bool disc_cfg) bool use_led = m_gcfg2.getBool(id, "led", false); bool cheat = m_gcfg2.getBool(id, "cheat", false); debuggerselect = m_gcfg2.getInt(id, "debugger", 0); // debuggerselect is defined in fst.h - if((id == "RPWE41" || id == "RPWZ41" || id == "SPXP41") && debuggerselect == 1) // Prince of Persia, Rival Swords + if((id == "RPWE41" || id == "RPWZ41" || id == "SPXP41") && debuggerselect == 1) // Prince of Persia: Rival Swords debuggerselect = 0; hooktype = (u32)m_gcfg2.getInt(id, "hooktype", 0); // hooktype is defined in patchcode.h if((cheat || debuggerselect == 1) && hooktype == 0) @@ -1160,7 +1171,7 @@ void CMenu::_launchWii(dir_discHdr *hdr, bool dvd, bool disc_cfg) if(CurrentIOS.Type == IOS_TYPE_D2X) { if(returnTo != 0 && !m_directLaunch && D2X_PatchReturnTo(returnTo) >= 0) - memset(&returnTo, 0, sizeof(u32));//set to null to keep external booter from setting it again if using d2x + memset(&returnTo, 0, sizeof(u32));//Already patched - no need for giantpune patch in external booter if(emulate_mode) { /* Enable our Emu NAND */ @@ -1186,9 +1197,11 @@ void CMenu::_launchWii(dir_discHdr *hdr, bool dvd, bool disc_cfg) if(!dvd) { DeviceHandle.OpenWBFS(currentPartition); - wbfs_partition = (DeviceHandle.GetFSType(currentPartition) == PART_FS_WBFS); + wbfs_partition = (DeviceHandle.GetFSType(currentPartition) == PART_FS_WBFS);// if USB device formatted to WBFS + /* if not WBFS formatted get fragmented list. */ + /* if SD card (currentPartition == 0) set sector size to 512 (0x200) */ if(!wbfs_partition && get_frag_list((u8 *)id.c_str(), (char*)path.c_str(), currentPartition == 0 ? 0x200 : USBStorage2_GetSectorSize()) < 0) - Sys_Exit(); + Sys_Exit();// failed to get frag list WBFS_Close(); } if(cheatFile != NULL)