Skip to content

Commit

Permalink
- beta 12 (external booter changes).
Browse files Browse the repository at this point in the history
- fixed launching of real nand channels.
- fixed launching of forwarder channels, but some apps (ie. wiimcc and savegame manager gx) don't connect with USB devices. if they are on real nand use the 'custom' option in game settings for these forwarders.
- fixed launching HBC on real nand. don't know if its even possible on a emu nand.
- 480p pixel patch for nand wiiware/vc games no longer requires apploader setting ON.
- Exclude Prince of Persia: The Forgotten Sands and a few games that use MetaFortress from using 480p pixel patch
- added giantpunes returnto patch for channels just in case not using d2x cios. some reason it was missing.
  • Loading branch information
Fledge68 committed Nov 29, 2021
1 parent a45cc4c commit 9f7da43
Show file tree
Hide file tree
Showing 13 changed files with 343 additions and 286 deletions.
Binary file modified out/bins/ext_booter.bin
Binary file not shown.
Binary file modified out/boot.dol
Binary file not shown.
95 changes: 78 additions & 17 deletions resources/wiiflow_game_booter/source/ChannelHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -78,40 +80,81 @@ 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)
{
// 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
{
if(tmd_file->contents[i].index == (dol ? 0x01 : tmd_file->boot_index))
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)
{
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);
Expand All @@ -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];
Expand All @@ -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};
Expand All @@ -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)
Expand Down Expand Up @@ -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();
}
6 changes: 4 additions & 2 deletions resources/wiiflow_game_booter/source/ChannelHandler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_ */
30 changes: 23 additions & 7 deletions resources/wiiflow_game_booter/source/apploader.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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)
{
Expand Down
47 changes: 3 additions & 44 deletions resources/wiiflow_game_booter/source/disc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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 */
Expand Down
4 changes: 1 addition & 3 deletions resources/wiiflow_game_booter/source/disc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions resources/wiiflow_game_booter/source/fst.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ void app_pokevalues()

void load_handler()
{
memset((void*)0x80001800, 0, 0x1800);
if(debuggerselect == 0x01)
{
gprintf("Ocarina: Debugger selected.\n");
Expand Down
Loading

3 comments on commit 9f7da43

@iamerror80
Copy link

@iamerror80 iamerror80 commented on 9f7da43 Dec 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,

I think there's a problem in wiiflow_game_booter/source/main.cpp

Disc_SelectVMode() needs Disc_ID to be already set in order to work.
Now that Disc_ID is set within LoadChannel(), Disc_SelectVMode() should be called after this and not before.

@iamerror80
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And in menu_game_boot.cpp:

WiiFlow_ExternalBooter() should have returnTo as argument (not 0), now that giantpunes return to patch has been added in external booter for channels.

@Fledge68
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey thanks too bad i didn't see your replies till a month later.

you are right about the Disc_ID for channels.

but when using d2x cios you don't need the giantpune old patch method. giantpunes old patch is just there if you are using a non d2x cios.

Please sign in to comment.