From ab3273f4757d2e7729bf8da6d3bc535f1c1d69bb Mon Sep 17 00:00:00 2001 From: wiidev Date: Sun, 1 Jan 2023 17:00:34 +0000 Subject: [PATCH] Automatically pick the cIOS for games To avoid unnecessary IOS reloads the following d2x cIOS setup should be used. - Slot 249 base 56 - Slot 250 base 57 - Slot 251 base 38 (Wii) / base 58 (vWii) Or you could use the following, which should improve game compatibility. - Slot 248 base 38 (Wii) - Slot 249 base 56 - Slot 250 base 57 - Slot 251 base 58 --- Languages/czech.lang | 6 + Languages/danish.lang | 6 + Languages/dutch.lang | 6 + Languages/english.lang | 6 + Languages/finnish.lang | 6 + Languages/french.lang | 6 + Languages/german.lang | 6 + Languages/greek.lang | 6 + Languages/hungarian.lang | 6 + Languages/italian.lang | 6 + Languages/japanese.lang | 6 + Languages/korean.lang | 6 + Languages/norwegian.lang | 6 + Languages/polish.lang | 6 + Languages/portuguese_br.lang | 6 + Languages/portuguese_pt.lang | 6 + Languages/russian.lang | 6 + Languages/schinese.lang | 6 + Languages/spanish.lang | 6 + Languages/swedish.lang | 6 + Languages/tchinese.lang | 6 + Languages/thai.lang | 6 + Languages/turkish.lang | 6 + Makefile | 5 +- source/Channels/channels.cpp | 4 +- source/Channels/channels.h | 2 +- source/StartUpProcess.cpp | 83 +++--- source/StartUpProcess.h | 1 + .../libruntimeiospatch/libruntimeiospatch.a | Bin 29802 -> 0 bytes .../libs/libruntimeiospatch/runtimeiospatch.c | 237 ++++++++++++++++++ source/prompts/GameWindow.cpp | 48 ++-- source/prompts/PromptWindows.cpp | 6 +- source/settings/CGameSettings.cpp | 7 + source/settings/CGameSettings.h | 2 + source/settings/CSettings.cpp | 7 + source/settings/CSettings.h | 2 +- source/settings/SettingsEnums.h | 7 + source/settings/menus/GameLoadSM.cpp | 37 ++- source/settings/menus/LoaderSettings.cpp | 47 +++- source/settings/menus/LoaderSettings.hpp | 1 + source/settings/meta.cpp | 14 +- source/system/IosLoader.cpp | 177 +++++++------ source/system/IosLoader.h | 11 +- source/usbloader/GameBooter.cpp | 106 +++++++- source/usbloader/wdvd.c | 5 +- source/usbloader/wdvd.h | 2 +- svnrev.sh | 7 +- 47 files changed, 783 insertions(+), 173 deletions(-) delete mode 100644 source/libs/libruntimeiospatch/libruntimeiospatch.a create mode 100644 source/libs/libruntimeiospatch/runtimeiospatch.c diff --git a/Languages/czech.lang b/Languages/czech.lang index 547322c7..8f242671 100644 --- a/Languages/czech.lang +++ b/Languages/czech.lang @@ -555,6 +555,12 @@ msgstr "Vlastní adresa" msgid "Custom Banners" msgstr "" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "Vlastní cesty" diff --git a/Languages/danish.lang b/Languages/danish.lang index b01f5521..06006847 100644 --- a/Languages/danish.lang +++ b/Languages/danish.lang @@ -555,6 +555,12 @@ msgstr "Brugerdefineret adresse" msgid "Custom Banners" msgstr "Brugerdefineret bannere" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "Sti-indstillinger" diff --git a/Languages/dutch.lang b/Languages/dutch.lang index 78db7bba..9499c990 100644 --- a/Languages/dutch.lang +++ b/Languages/dutch.lang @@ -555,6 +555,12 @@ msgstr "Aangepaste Adres" msgid "Custom Banners" msgstr "Aangepaste Banners" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "Aangepaste Locaties" diff --git a/Languages/english.lang b/Languages/english.lang index 5f2d00fb..909d3226 100644 --- a/Languages/english.lang +++ b/Languages/english.lang @@ -555,6 +555,12 @@ msgstr "" msgid "Custom Banners" msgstr "" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "" diff --git a/Languages/finnish.lang b/Languages/finnish.lang index 62379195..f9975d39 100644 --- a/Languages/finnish.lang +++ b/Languages/finnish.lang @@ -555,6 +555,12 @@ msgstr "" msgid "Custom Banners" msgstr "" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "Omat polut" diff --git a/Languages/french.lang b/Languages/french.lang index bdf83374..f63bfb52 100644 --- a/Languages/french.lang +++ b/Languages/french.lang @@ -555,6 +555,12 @@ msgstr "" msgid "Custom Banners" msgstr "Bannières persos" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "Personnalisation des dossiers" diff --git a/Languages/german.lang b/Languages/german.lang index 44682741..6ead166c 100644 --- a/Languages/german.lang +++ b/Languages/german.lang @@ -555,6 +555,12 @@ msgstr "" msgid "Custom Banners" msgstr "Community Banner" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "Community Pfade" diff --git a/Languages/greek.lang b/Languages/greek.lang index 16343d0b..1930a488 100644 --- a/Languages/greek.lang +++ b/Languages/greek.lang @@ -555,6 +555,12 @@ msgstr "" msgid "Custom Banners" msgstr "Τροποποιημένες ταμπέλες-εικονίδια" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "Τροποποιημένες διευθύνσεις/μονοπάτια αρχείων" diff --git a/Languages/hungarian.lang b/Languages/hungarian.lang index ee903767..565edfac 100644 --- a/Languages/hungarian.lang +++ b/Languages/hungarian.lang @@ -555,6 +555,12 @@ msgstr "" msgid "Custom Banners" msgstr "" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "Egyéni útvonalak" diff --git a/Languages/italian.lang b/Languages/italian.lang index f18c09af..89c6832e 100644 --- a/Languages/italian.lang +++ b/Languages/italian.lang @@ -555,6 +555,12 @@ msgstr "Indirizzo personalizzati" msgid "Custom Banners" msgstr "Banner personalizzati" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "Percorsi personalizzati" diff --git a/Languages/japanese.lang b/Languages/japanese.lang index 8e84a9be..8e3be54a 100644 --- a/Languages/japanese.lang +++ b/Languages/japanese.lang @@ -555,6 +555,12 @@ msgstr "カスタム アドレス" msgid "Custom Banners" msgstr "カスタムバナー" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "パスを変更" diff --git a/Languages/korean.lang b/Languages/korean.lang index 96df2bf5..a908aa9e 100644 --- a/Languages/korean.lang +++ b/Languages/korean.lang @@ -555,6 +555,12 @@ msgstr "커스텀 주소" msgid "Custom Banners" msgstr "커스텀 배너" +msgid "Custom Game IOS" +msgstr "커스텀 게임 IOS" + +msgid "Custom Games IOS" +msgstr "커스텀 게임 IOS" + msgid "Custom Paths" msgstr "커스텀 경로" diff --git a/Languages/norwegian.lang b/Languages/norwegian.lang index fc10a205..b08ca2bc 100644 --- a/Languages/norwegian.lang +++ b/Languages/norwegian.lang @@ -555,6 +555,12 @@ msgstr "" msgid "Custom Banners" msgstr "" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "Egendefinerte stier" diff --git a/Languages/polish.lang b/Languages/polish.lang index 22cdee91..86eeac94 100644 --- a/Languages/polish.lang +++ b/Languages/polish.lang @@ -555,6 +555,12 @@ msgstr "" msgid "Custom Banners" msgstr "" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "Sciezki" diff --git a/Languages/portuguese_br.lang b/Languages/portuguese_br.lang index edc09914..03262560 100644 --- a/Languages/portuguese_br.lang +++ b/Languages/portuguese_br.lang @@ -555,6 +555,12 @@ msgstr "" msgid "Custom Banners" msgstr "Banners Modificados" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "Caminhos" diff --git a/Languages/portuguese_pt.lang b/Languages/portuguese_pt.lang index 310e2837..e7c828ac 100644 --- a/Languages/portuguese_pt.lang +++ b/Languages/portuguese_pt.lang @@ -555,6 +555,12 @@ msgstr "" msgid "Custom Banners" msgstr "" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "Caminhos Personalizados" diff --git a/Languages/russian.lang b/Languages/russian.lang index 975de12d..acfd1d81 100644 --- a/Languages/russian.lang +++ b/Languages/russian.lang @@ -555,6 +555,12 @@ msgstr "" msgid "Custom Banners" msgstr "" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "Изменение путей" diff --git a/Languages/schinese.lang b/Languages/schinese.lang index 5d2964d4..d75f55eb 100644 --- a/Languages/schinese.lang +++ b/Languages/schinese.lang @@ -555,6 +555,12 @@ msgstr "自定义地址" msgid "Custom Banners" msgstr "自定义频道动画" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "自定义路径" diff --git a/Languages/spanish.lang b/Languages/spanish.lang index 2c6dee3c..116ec77d 100644 --- a/Languages/spanish.lang +++ b/Languages/spanish.lang @@ -555,6 +555,12 @@ msgstr "Dirección custom" msgid "Custom Banners" msgstr "Banners personalizados" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "Rutas personalizadas" diff --git a/Languages/swedish.lang b/Languages/swedish.lang index 59d6d98f..904018ac 100644 --- a/Languages/swedish.lang +++ b/Languages/swedish.lang @@ -555,6 +555,12 @@ msgstr "Anpassad adress" msgid "Custom Banners" msgstr "" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "Anpassade sökvägar" diff --git a/Languages/tchinese.lang b/Languages/tchinese.lang index 3217fe23..77eb1818 100644 --- a/Languages/tchinese.lang +++ b/Languages/tchinese.lang @@ -555,6 +555,12 @@ msgstr "自訂地址" msgid "Custom Banners" msgstr "自製頻道動畫" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "自訂路徑" diff --git a/Languages/thai.lang b/Languages/thai.lang index 09f3540e..990da475 100644 --- a/Languages/thai.lang +++ b/Languages/thai.lang @@ -555,6 +555,12 @@ msgstr "" msgid "Custom Banners" msgstr "" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "กำหนด ที่เก็บ" diff --git a/Languages/turkish.lang b/Languages/turkish.lang index 34b5c7a8..815eab3e 100644 --- a/Languages/turkish.lang +++ b/Languages/turkish.lang @@ -555,6 +555,12 @@ msgstr "" msgid "Custom Banners" msgstr "" +msgid "Custom Game IOS" +msgstr "" + +msgid "Custom Games IOS" +msgstr "" + msgid "Custom Paths" msgstr "Kişisel Yollar" diff --git a/Makefile b/Makefile index 73e3ac6b..6d589a3d 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ SOURCES := source \ source/Controls \ source/system \ source/libs/libwbfs \ + source/libs/libruntimeiospatch \ source/language \ source/mload \ source/mload/modules \ @@ -73,7 +74,7 @@ endif #--------------------------------------------------------------------------------- LIBS := -lwolfssl -lcustomfat -lcustomntfs -lcustomext2fs -lvorbisidec -logg \ -lmad -lfreetype -lgd -ljpeg -lpng -lm -lz -lwiiuse -lwiidrc \ - -lbte -lasnd -logc -lruntimeiospatch + -lbte -lasnd -logc #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing # include and lib @@ -140,7 +141,7 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ #--------------------------------------------------------------------------------- export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) -L$(CURDIR)/source/libs/libdrc/ \ -L$(CURDIR)/source/libs/libext2fs -L$(CURDIR)/source/libs/libfat \ - -L$(CURDIR)/source/libs/libntfs -L$(CURDIR)/source/libs/libruntimeiospatch \ + -L$(CURDIR)/source/libs/libntfs \ -L$(CURDIR)/source/libs/libwolfssl -L$(LIBOGC_LIB) export OUTPUT := $(CURDIR)/$(TARGET) diff --git a/source/Channels/channels.cpp b/source/Channels/channels.cpp index 08ef9203..e1c8d4ee 100755 --- a/source/Channels/channels.cpp +++ b/source/Channels/channels.cpp @@ -264,12 +264,12 @@ u8 *Channels::GetDol(const u64 &title, u8 *tmdBuffer, bool &isForwarder) return outBuf; } -u8 Channels::GetRequestedIOS(const u64 &title) +u8 Channels::GetRequestedIOS(const u64 &title, const char *prefix) { u8 IOS = 0; u32 tmdSize = 0; - u8 *titleTMD = GetTMD(title, &tmdSize, ""); + u8 *titleTMD = GetTMD(title, &tmdSize, prefix); if (!titleTMD) return 0; diff --git a/source/Channels/channels.h b/source/Channels/channels.h index 0ddc538b..67b0ab56 100755 --- a/source/Channels/channels.h +++ b/source/Channels/channels.h @@ -37,7 +37,7 @@ public: static void DestroyInstance(void) { if(instance) delete instance; instance = NULL; } static u32 LoadChannel(const u64 &chantitle); - static u8 GetRequestedIOS(const u64 &title); + static u8 GetRequestedIOS(const u64 &title, const char *prefix); static u8 *GetTMD(const u64 &tid, u32 *size, const char *prefix); static u8 *GetDol(const u64 &title, u8 *tmdBuffer, bool &isForwarder); static u8 *GetOpeningBnr(const u64 &title, u32 *outsize, const char *pathPrefix); diff --git a/source/StartUpProcess.cpp b/source/StartUpProcess.cpp index 88fb4b2b..678abe4b 100644 --- a/source/StartUpProcess.cpp +++ b/source/StartUpProcess.cpp @@ -51,7 +51,7 @@ StartUpProcess::StartUpProcess() versionTxt = new GuiText(" ", 18, (GXColor){255, 255, 255, 255}); versionTxt->SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); - versionTxt->SetPosition(20, screenheight - 20); + versionTxt->SetPosition(23, screenheight - 20); #ifdef FULLCHANNEL versionTxt->SetTextf("v3.0c Rev. %s (%s)", GetRev(), commitID()); @@ -101,15 +101,22 @@ int StartUpProcess::ParseArguments(int argc, char *argv[]) gprintf("Boot argument %i: %s\n", i + 1, argv[i]); - char *ptr = strcasestr(argv[i], "-bootios="); + char *ptr = strcasestr(argv[i], "-ios="); + if(ptr) + { + if(atoi(ptr+strlen("-ios=")) == 58) + Settings.LoaderIOS = 58; + else + Settings.LoaderIOS = LIMIT(atoi(ptr+strlen("-ios=")), 200, 255); + } + + ptr = strcasestr(argv[i], "-bootios="); if (ptr) { if (atoi(ptr + strlen("-bootios=")) == 58) - Settings.LoaderIOS = 58; + Settings.BootIOS = 58; else - Settings.LoaderIOS = LIMIT(atoi(ptr + strlen("-bootios=")), 200, 255); - Settings.UseArgumentIOS = ON; - Settings.BootIOS = Settings.LoaderIOS; + Settings.BootIOS = LIMIT(atoi(ptr + strlen("-bootios=")), 200, 255); } ptr = strcasestr(argv[i], "-usbport="); @@ -245,38 +252,54 @@ int StartUpProcess::Run(int argc, char *argv[]) return ret; } +void StartUpProcess::LoadIOS(u8 ios, bool boot) +{ + SetTextf("Reloading to IOS%d%s\n", ios, boot ? " requested in meta.xml" : ""); + if (IosLoader::LoadAppCios(ios) < 0) + { + SetTextf("Failed to load an IOS. USB Loader GX requires a cIOS or IOS58 with AHB access. Exiting...\n"); + sleep(5); + Sys_BackToLoader(); + } + SetTextf("Reloaded to IOS%d r%d\n", Settings.LoaderIOS, IOS_GetRevision()); +} + int StartUpProcess::Execute(bool quickGameBoot) { Settings.EntryIOS = IOS_GetVersion(); // Disable AHBPROT - IosLoader::PatchAHB(); - gprintf("Current IOS: %d - have AHB access: %s\n", Settings.EntryIOS, AHBPROT_DISABLED ? "yes" : "no"); - // Reload to a cIOS if required (old forwarder?) or requested - if (!AHBPROT_DISABLED || (Settings.EntryIOS != Settings.BootIOS)) - { - SetTextf("Reloading to cIOS %d%s\n", Settings.LoaderIOS, Settings.UseArgumentIOS ? "requested in meta.xml" : ""); - if (IosLoader::LoadAppCios(Settings.LoaderIOS) < 0) - { - SetTextf("Failed to load an IOS. USB Loader GX requires a cIOS or IOS58 with AHB access. Exiting...\n"); - sleep(5); - Sys_BackToLoader(); - } - SetTextf("Reloaded to cIOS %d\n", Settings.LoaderIOS); - gprintf("Current IOS: %d - have AHB access: %s\n", IOS_GetVersion(), AHBPROT_DISABLED ? "yes" : "no"); - } + IosPatch_AHBPROT(false); + // Store dx2 cIOS info + IosLoader::GetD2XInfo(); + + gprintf("Current IOS: %d - have AHB access: %s\n", Settings.EntryIOS, AHBPROT_DISABLED ? "yes" : "no"); + // Reload to a cIOS if we're using both USB ports + if (Settings.USBPort == 2) + LoadIOS(Settings.LoaderIOS, false); + + // Reload to a cIOS if required (old forwarder?) or requested + else if (!AHBPROT_DISABLED || (Settings.EntryIOS != Settings.BootIOS)) + LoadIOS(Settings.BootIOS, true); + + // Setup the pads SetupPads(); + // Mount the SD card SetTextf("Initializing SD card\n"); DeviceHandler::Instance()->MountSD(); // Do not mount USB if not needed. USB is not available with WiiU WiiVC injected channel + bool USBSuccess = false; if (Settings.USBAutoMount == ON && !isWiiVC) { SetTextf("Initializing USB devices\n"); - USBSpinUp(); - DeviceHandler::Instance()->MountAllUSB(false); - gprintf("Completed initialization of USB devices\n"); + if (USBSpinUp()) + { + DeviceHandler::Instance()->MountAllUSB(false); + USBSuccess = true; + gprintf("Completed initialization of USB devices\n"); + } } SetTextf("Loading config files\n"); @@ -311,7 +334,7 @@ int StartUpProcess::Execute(bool quickGameBoot) // Now load the cIOS that was set in the settings menu if (IosLoader::LoadAppCios(Settings.LoaderIOS) > -1) { - SetTextf("Reloaded to %s%d r%d\n", IOS_GetVersion() >= 200 ? "cIOS " : "IOS", Settings.LoaderIOS, IOS_GetRevision()); + SetTextf("Reloaded to IOS%d r%d\n", Settings.LoaderIOS, IOS_GetRevision()); // Re-Mount devices SetTextf("Reinitializing devices\n"); } @@ -321,10 +344,10 @@ int StartUpProcess::Execute(bool quickGameBoot) SetupPads(); DeviceHandler::Instance()->MountSD(); - if (Settings.USBAutoMount == ON) + if (Settings.USBAutoMount == ON && USBSuccess) { - USBSpinUp(); - DeviceHandler::Instance()->MountAllUSB(false); + if (USBSpinUp()) + DeviceHandler::Instance()->MountAllUSB(false); } } @@ -353,9 +376,9 @@ int StartUpProcess::Execute(bool quickGameBoot) // Enable isfs permission if using Hermes v4 without AHB, or WiiU WiiVC (IOS255 fw.img) if (IOS_GetVersion() < 200 || (IosLoader::IsHermesIOS() && IOS_GetRevision() == 4) || isWiiVC) { - SetTextf("Patching %s%d\n", IOS_GetVersion() >= 200 ? "cIOS " : "IOS", IOS_GetVersion()); + SetTextf("Patching IOS%d\n", IOS_GetVersion()); if (IosPatch_RUNTIME(!isWiiVC, false, false, isWiiVC, false) == ERROR_PATCH) - gprintf("Patching %sIOS%d failed!\n", IOS_GetVersion() >= 200 ? "c" : "", IOS_GetVersion()); + gprintf("Patching IOS%d failed!\n", IOS_GetVersion()); else NandTitles.Get(); // get NAND channel's titles diff --git a/source/StartUpProcess.h b/source/StartUpProcess.h index 4ca8a48d..ea962e3f 100644 --- a/source/StartUpProcess.h +++ b/source/StartUpProcess.h @@ -11,6 +11,7 @@ public: private: StartUpProcess(); ~StartUpProcess(); + void LoadIOS(u8 ios, bool boot); int Execute(bool quickGameBoot); bool USBSpinUp(); void TextFade(int direction); diff --git a/source/libs/libruntimeiospatch/libruntimeiospatch.a b/source/libs/libruntimeiospatch/libruntimeiospatch.a deleted file mode 100644 index 10ea9cd1fe2c6ebd5d0d81428e164d95cbb56622..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29802 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 +// Copyright (C) 2012-2013 damysteryman +// Copyright (C) 2012-2015 Christopher Bratusek +// Copyright (C) 2013 DarkMatterCore +// Copyright (C) 2014 megazig +// Copyright (C) 2015-2017 FIX94 + +#include +#include +#include +#include + +#include "../../gecko.h" +#include "runtimeiospatch.h" + +#define MEM_REG_BASE 0xd8b4000 +#define MEM_PROT (MEM_REG_BASE + 0x20a) + + +static inline void disable_memory_protection(void) { + write32(MEM_PROT, read32(MEM_PROT) & 0x0000FFFF); +} + +static const u8 di_readlimit_old[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0A, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x7E, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 +}; +static const u8 di_readlimit_patch[] = { 0x7e, 0xd4 }; + +static const u8 isfs_permissions_old[] = { 0x42, 0x8B, 0xD0, 0x01, 0x25, 0x66 }; +static const u8 isfs_permissions_patch[] = { 0x42, 0x8B, 0xE0, 0x01, 0x25, 0x66 }; +#if 1 +static const u8 setuid_old[] = { 0xD1, 0x2A, 0x1C, 0x39 }; +static const u8 setuid_patch[] = { 0x46, 0xC0 }; +#endif +static const u8 es_identify_old[] = { 0x28, 0x03, 0xD1, 0x23 }; +static const u8 es_identify_patch[] = { 0x00, 0x00 }; +static const u8 hash_old[] = { 0x20, 0x07, 0x23, 0xA2 }; +static const u8 hash_patch[] = { 0x00 }; +static const u8 new_hash_old[] = { 0x20, 0x07, 0x4B, 0x0B }; +#if 0 +static const u8 addticket_vers_check[] = { 0xD2, 0x01, 0x4E, 0x56 }; +static const u8 addticket_patch[] = { 0xE0 }; +#endif +static const u8 es_set_ahbprot_old[] = { 0x68, 0x5B, 0x22, 0xEC, 0x00, 0x52, 0x18, 0x9B, 0x68, 0x1B, 0x46, 0x98, 0x07, 0xDB }; +static const u8 es_set_ahbprot_patch[] = { 0x01 }; + +/* SSL patches made by FIX94 for Nintendont. Ported to libruntimeiospatch by DarkMatterCore */ +static const u8 ssl_patch1_old[] = { 0xFE, 0x0E, 0xE3, 0x50, 0x00, 0x00, 0x05, 0x9F }; +static const u8 ssl_patch1_new[] = { 0xFE, 0x0E, 0xE3, 0x28, 0xF1, 0x02, 0x05, 0x9F }; // Fixes SSL error -9 (wrong host) +static const u8 ssl_patch2_old[] = { 0x00, 0x00, 0x0A, 0x00, 0x00, 0x09, 0xEA, 0x00 }; +static const u8 ssl_patch2_new[] = { 0x00, 0x00, 0xEA, 0x00, 0x00, 0x09, 0xEA, 0x00 }; // Fixes SSL error -10 (part 1) (wrong root cert) +static const u8 ssl_patch3_old[] = { 0x00, 0x00, 0x1A, 0x00, 0x00, 0x08, 0xE3, 0xE0 }; +static const u8 ssl_patch3_new[] = { 0x00, 0x00, 0xEA, 0x00, 0x00, 0x08, 0xE3, 0xE0 }; // Fixes SSL error -10 (part 2) (wrong root cert) +static const u8 ssl_patch4_old[] = { 0x00, 0x00, 0xDA, 0x00, 0x00, 0x16, 0xE7, 0x96 }; +static const u8 ssl_patch4_new[] = { 0x00, 0x00, 0xEA, 0x00, 0x00, 0x16, 0xE7, 0x96 }; // Fixes SSL error -11 (wrong client cert) + +//Following patches added to iospatch.c by damysteryman, taken from sciifii v5 +static const u8 MEM2_prot_old[] = { 0xB5, 0x00, 0x4B, 0x09, 0x22, 0x01, 0x80, 0x1A, 0x22, 0xF0 }; +static const u8 MEM2_prot_patch[] = { 0xB5, 0x00, 0x4B, 0x09, 0x22, 0x00, 0x80, 0x1A, 0x22, 0xF0 }; +static const u8 ES_OpenTitleContent1_old[] = { 0x9D, 0x05, 0x42, 0x9D, 0xD0, 0x03 }; +static const u8 ES_OpenTitleContent1_patch[] = { 0x9D, 0x05, 0x42, 0x9D, 0xE0, 0x03 }; +static const u8 ES_OpenTitleContent2_old[] = { 0xD4, 0x01, 0x4C, 0x36, 0xE0, 0x3B }; +static const u8 ES_OpenTitleContent2_patch[] = { 0xE0, 0x01, 0x4C, 0x36, 0xE0, 0x3B }; +static const u8 ES_ReadContent_old[] = { 0xFC, 0x0F, 0xB5, 0x30, 0x1C, 0x14, 0x1C, 0x1D, 0x4B, + 0x0E, 0x68, 0x9B, 0x2B, 0x00, 0xD0, 0x03, 0x29, 0x00, 0xDB, 0x01, + 0x29, 0x0F, 0xDD, 0x01 }; +static const u8 ES_ReadContent_patch[] = { 0xFC, 0x0F, 0xB5, 0x30, 0x1C, 0x14, 0x1C, 0x1D, 0x4B, + 0x0E, 0x68, 0x9B, 0x2B, 0x00, 0x46, 0xC0, 0x29, 0x00, 0x46, 0xC0, + 0x29, 0x0F, 0xE0, 0x01 }; +static const u8 ES_CloseContent_old[] = { 0xB5, 0x10, 0x4B, 0x10, 0x68, 0x9B, 0x2B, 0x00, 0xD0, + 0x03, 0x29, 0x00, 0xDB, 0x01, 0x29, 0x0F, 0xDD, 0x01 }; +static const u8 ES_CloseContent_patch[] = { 0xB5, 0x10, 0x4B, 0x10, 0x68, 0x9B, 0x2B, 0x00, 0x46, + 0xC0, 0x29, 0x00, 0x46, 0xC0, 0x29, 0x0F, 0xE0, 0x01 }; +static const u8 ES_TitleVersionCheck_old[] = { 0xD2, 0x01, 0x4E, 0x56 }; +static const u8 ES_TitleVersionCheck_patch[] = { 0xE0, 0x01, 0x4E, 0x56 }; +static const u8 ES_TitleDeleteCheck_old[] = { 0xD8, 0x00, 0x4A, 0x04 }; +static const u8 ES_TitleDeleteCheck_patch[] = { 0xE0, 0x00, 0x4A, 0x04 }; + +//Following set of patches made by damysteryman for use with Wii U's vWii +static const u8 Kill_AntiSysTitleInstallv3_pt1_old[] = { 0x68, 0x1A, 0x2A, 0x01, 0xD0, 0x05 }; // Make sure that the pt1 +static const u8 Kill_AntiSysTitleInstallv3_pt1_patch[] = { 0x68, 0x1A, 0x2A, 0x01, 0x46, 0xC0 }; // patch is applied twice. -dmm +static const u8 Kill_AntiSysTitleInstallv3_pt2_old[] = { 0xD0, 0x02, 0x33, 0x06, 0x42, 0x9A, 0xD1, 0x01 }; // Make sure that the pt2 patch +static const u8 Kill_AntiSysTitleInstallv3_pt2_patch[] = { 0x46, 0xC0, 0x33, 0x06, 0x42, 0x9A, 0xE0, 0x01 }; // is also applied twice. -dmm +static const u8 Kill_AntiSysTitleInstallv3_pt3_old[] = { 0x68, 0xFB, 0x2B, 0x00, 0xDB, 0x01 }; +static const u8 Kill_AntiSysTitleInstallv3_pt3_patch[] = { 0x68, 0xFB, 0x2B, 0x00, 0xDB, 0x10 }; + +/* ISFS_SetAttr patches made by megazig */ +#if 0 +static const u8 isfs_setattr_pt1_old[] = { 0x42, 0xAB, 0xD0, 0x02, 0x20, 0x66 }; +static const u8 isfs_setattr_pt1_patch[] = { 0x42, 0xAB, 0xE0, 0x02, 0x20, 0x66 }; +static const u8 isfs_setattr_pt2_old[] = { 0x2D, 0x00, 0xD0, 0x02, 0x20, 0x66 }; +static const u8 isfs_setattr_pt2_patch[] = { 0x2D, 0x00, 0xE0, 0x02, 0x20, 0x66 }; +#endif + +/* ISFS_permission for WiiU WiiVC patches made by fix94 */ +static const u8 isfs_perm_wiivc_old[] = { 0x42, 0x9F, 0xD1, 0x03, 0x20, 0x00, 0xBD, 0xF0, 0x09, 0x8B, 0xE7, 0xF8, 0x20, 0x66 }; +static const u8 isfs_perm_wiivc_patch[] = { 0x42, 0x9F, 0x46, 0xC0, 0x20, 0x00, 0xBD, 0xF0, 0x09, 0x8B, 0xE7, 0xF8, 0x20, 0x66 }; + + +static u8 apply_patch(const char *name, const u8 *old, u32 old_size, const u8 *patch, size_t patch_size, u32 patch_offset, bool verbose) { + u8 *ptr_start = (u8*)*((u32*)0x80003134), *ptr_end = (u8*)0x94000000; + u8 found = 0; + if(verbose) + gprintf(" Patching %-30s", name); + u8 *location = NULL; + while (ptr_start < (ptr_end - patch_size)) { + if (!memcmp(ptr_start, old, old_size)) { + found++; + location = ptr_start + patch_offset; + u8 *start = location; + u32 i; + for (i = 0; i < patch_size; i++) { + *location++ = patch[i]; + } + DCFlushRange((u8 *)(((u32)start) >> 5 << 5), (patch_size >> 5 << 5) + 64); + ICInvalidateRange((u8 *)(((u32)start) >> 5 << 5), (patch_size >> 5 << 5) + 64); + } + ptr_start++; + } + if(verbose){ + if (found) + gprintf(" patched\n"); + else + gprintf(" not patched\n"); + } + return found; +} + +s32 IosPatch_AHBPROT(bool verbose) { + if (AHBPROT_DISABLED) { + disable_memory_protection(); + s32 ret = apply_patch("es_set_ahbprot", es_set_ahbprot_old, sizeof(es_set_ahbprot_old), es_set_ahbprot_patch, sizeof(es_set_ahbprot_patch), 25, verbose); + if (ret) + return ret; + else + return ERROR_PATCH; + } + return ERROR_AHBPROT; +} + +s32 IosPatch_RUNTIME(bool wii, bool sciifii, bool vwii, bool wiivc, bool verbose) { + s32 count = 0; + + if (AHBPROT_DISABLED) { + disable_memory_protection(); + if(wii) + { + if(verbose) gprintf(">> Applying standard Wii patches:\n"); + count += apply_patch("di_readlimit", di_readlimit_old, sizeof(di_readlimit_old), di_readlimit_patch, sizeof(di_readlimit_patch), 12, verbose); + count += apply_patch("isfs_permissions", isfs_permissions_old, sizeof(isfs_permissions_old), isfs_permissions_patch, sizeof(isfs_permissions_patch), 0, verbose); + //count += apply_patch("es_setuid", setuid_old, sizeof(setuid_old), setuid_patch, sizeof(setuid_patch), 0, verbose); + count += apply_patch("es_identify", es_identify_old, sizeof(es_identify_old), es_identify_patch, sizeof(es_identify_patch), 2, verbose); + count += apply_patch("hash_check", hash_old, sizeof(hash_old), hash_patch, sizeof(hash_patch), 1, verbose); + count += apply_patch("new_hash_check", new_hash_old, sizeof(new_hash_old), hash_patch, sizeof(hash_patch), 1, verbose); + //count += apply_patch("isfs_setattr_pt1", isfs_setattr_pt1_old, sizeof(isfs_setattr_pt1_old), isfs_setattr_pt1_patch, sizeof(isfs_setattr_pt1_patch), 0, verbose); + //count += apply_patch("isfs_setattr_pt2", isfs_setattr_pt2_old, sizeof(isfs_setattr_pt2_old), isfs_setattr_pt2_patch, sizeof(isfs_setattr_pt2_patch), 0, verbose); + //count += apply_patch("ssl_patch1", ssl_patch1_old, sizeof(ssl_patch1_old), ssl_patch1_new, sizeof(ssl_patch1_new), 0, verbose); + //count += apply_patch("ssl_patch2", ssl_patch2_old, sizeof(ssl_patch2_old), ssl_patch2_new, sizeof(ssl_patch2_new), 0, verbose); + //count += apply_patch("ssl_patch3", ssl_patch3_old, sizeof(ssl_patch3_old), ssl_patch3_new, sizeof(ssl_patch3_new), 0, verbose); + //count += apply_patch("ssl_patch4", ssl_patch4_old, sizeof(ssl_patch4_old), ssl_patch4_new, sizeof(ssl_patch4_new), 0, verbose); + } + if(sciifii) + { + if(verbose) gprintf(">> Applying Sciifii patches:\n"); + count += apply_patch("MEM2_prot", MEM2_prot_old, sizeof(MEM2_prot_old), MEM2_prot_patch, sizeof(MEM2_prot_patch), 0, verbose); + count += apply_patch("ES_OpenTitleContent1", ES_OpenTitleContent1_old, sizeof(ES_OpenTitleContent1_old), ES_OpenTitleContent1_patch, sizeof(ES_OpenTitleContent1_patch), 0, verbose); + count += apply_patch("ES_OpenTitleContent2", ES_OpenTitleContent2_old, sizeof(ES_OpenTitleContent2_old), ES_OpenTitleContent2_patch, sizeof(ES_OpenTitleContent2_patch), 0, verbose); + count += apply_patch("ES_ReadContent_prot", ES_ReadContent_old, sizeof(ES_ReadContent_old), ES_ReadContent_patch, sizeof(ES_ReadContent_patch), 0, verbose); + count += apply_patch("ES_CloseContent", ES_CloseContent_old, sizeof(ES_CloseContent_old), ES_CloseContent_patch, sizeof(ES_CloseContent_patch), 0, verbose); + count += apply_patch("ES_TitleVersionCheck", ES_TitleVersionCheck_old, sizeof(ES_TitleVersionCheck_old), ES_TitleVersionCheck_patch, sizeof(ES_TitleVersionCheck_patch), 0, verbose); + count += apply_patch("ES_TitleDeleteCheck", ES_TitleDeleteCheck_old, sizeof(ES_TitleDeleteCheck_old), ES_TitleDeleteCheck_patch, sizeof(ES_TitleDeleteCheck_patch), 0, verbose); + } + if(vwii) + { + if(verbose) gprintf(">> Applying vWii patches:\n"); + count += apply_patch("Kill_AntiSysTitleInstallv3_pt1", Kill_AntiSysTitleInstallv3_pt1_old, sizeof(Kill_AntiSysTitleInstallv3_pt1_old), Kill_AntiSysTitleInstallv3_pt1_patch, sizeof(Kill_AntiSysTitleInstallv3_pt1_patch), 0, verbose); + count += apply_patch("Kill_AntiSysTitleInstallv3_pt2", Kill_AntiSysTitleInstallv3_pt2_old, sizeof(Kill_AntiSysTitleInstallv3_pt2_old), Kill_AntiSysTitleInstallv3_pt2_patch, sizeof(Kill_AntiSysTitleInstallv3_pt2_patch), 0, verbose); + count += apply_patch("Kill_AntiSysTitleInstallv3_pt3", Kill_AntiSysTitleInstallv3_pt3_old, sizeof(Kill_AntiSysTitleInstallv3_pt3_old), Kill_AntiSysTitleInstallv3_pt3_patch, sizeof(Kill_AntiSysTitleInstallv3_pt3_patch), 0, verbose); + } + if(wiivc) + { + if(verbose) gprintf(">> Applying WiiVC patches:\n"); + count += apply_patch("isfs_permissions", isfs_perm_wiivc_old, sizeof(isfs_perm_wiivc_old), isfs_perm_wiivc_patch, sizeof(isfs_perm_wiivc_patch), 0, verbose); + count += apply_patch("es_setuid", setuid_old, sizeof(setuid_old), setuid_patch, sizeof(setuid_patch), 0, verbose); + count += apply_patch("es_identify", es_identify_old, sizeof(es_identify_old), es_identify_patch, sizeof(es_identify_patch), 2, verbose); + } + return count; + } + return ERROR_AHBPROT; +} + +s32 IosPatch_FULL(bool wii, bool sciifii, bool vwii, bool wiivc, bool verbose, int IOS) { + s32 ret = 0; + s32 xret = 0; + + if (AHBPROT_DISABLED) + ret = IosPatch_AHBPROT(verbose); + else + return ERROR_AHBPROT; + + if (ret) { + IOS_ReloadIOS(IOS); + xret = IosPatch_RUNTIME(wii, sciifii, vwii, wiivc, verbose); + } else { + xret = ERROR_PATCH; + } + + return xret; + +} + +s32 IosPatch_SSL(bool verbose) { + s32 count = 0; + + if (AHBPROT_DISABLED) { + disable_memory_protection(); + if(verbose) gprintf(">> Applying SSL patches:\n"); + count += apply_patch("ssl_patch1", ssl_patch1_old, sizeof(ssl_patch1_old), ssl_patch1_new, sizeof(ssl_patch1_new), 0, verbose); + count += apply_patch("ssl_patch2", ssl_patch2_old, sizeof(ssl_patch2_old), ssl_patch2_new, sizeof(ssl_patch2_new), 0, verbose); + count += apply_patch("ssl_patch3", ssl_patch3_old, sizeof(ssl_patch3_old), ssl_patch3_new, sizeof(ssl_patch3_new), 0, verbose); + count += apply_patch("ssl_patch4", ssl_patch4_old, sizeof(ssl_patch4_old), ssl_patch4_new, sizeof(ssl_patch4_new), 0, verbose); + return count; + } + return ERROR_AHBPROT; +} diff --git a/source/prompts/GameWindow.cpp b/source/prompts/GameWindow.cpp index fdccb24e..f01b0442 100644 --- a/source/prompts/GameWindow.cpp +++ b/source/prompts/GameWindow.cpp @@ -745,8 +745,9 @@ void GameWindow::BootGame(struct discHdr *header) snprintf(IDfull, sizeof(IDfull), "%s", (char *) header->id); int gameIOS = game_cfg->ios == INHERIT ? Settings.cios : game_cfg->ios; + int autoIOS = game_cfg->autoios == INHERIT ? Settings.AutoIOS : game_cfg->autoios; int gameNandEmuMode = game_cfg->NandEmuMode == INHERIT ? Settings.NandEmuMode : game_cfg->NandEmuMode; - if(header->type == TYPE_GAME_EMUNANDCHAN) + if (header->type == TYPE_GAME_EMUNANDCHAN) gameNandEmuMode = game_cfg->NandEmuMode == INHERIT ? Settings.NandEmuChanMode : game_cfg->NandEmuMode; if (game_cfg->loadalternatedol == 2) @@ -760,14 +761,14 @@ void GameWindow::BootGame(struct discHdr *header) return; } } - else if(game_cfg->loadalternatedol == 3 && WDMMenu::Show(header) == 0) + else if (game_cfg->loadalternatedol == 3 && WDMMenu::Show(header) == 0) { // Canceled return; } - else if(game_cfg->loadalternatedol == 4) + else if (game_cfg->loadalternatedol == 4) { - if(!IosLoader::IsD2X(gameIOS)) + if(autoIOS == GAME_IOS_CUSTOM && !IosLoader::IsD2X(gameIOS)) defaultDolPrompt((char *) header->id); } @@ -778,35 +779,38 @@ void GameWindow::BootGame(struct discHdr *header) if (CheckFile(filepath) == false) { snprintf(filepath + n, sizeof(filepath) - n, " %s", tr( "does not exist! Loading game without cheats." )); - if(!WindowPrompt(tr( "Error" ), filepath, tr( "Continue" ), tr( "Cancel"))) + if (!WindowPrompt(tr( "Error" ), filepath, tr( "Continue" ), tr( "Cancel"))) return; } } - if(header->type == TYPE_GAME_EMUNANDCHAN) + if (autoIOS == GAME_IOS_CUSTOM) { - if(gameNandEmuMode != EMUNAND_NEEK) + if (header->type == TYPE_GAME_EMUNANDCHAN) { - // If NandEmuPath is on root of the first FAT32 partition, allow Waninkoko's rev17-21 cIOS for EmuNAND Channels - bool NandEmu_compatible = false; - const char *NandEmuChanPath = game_cfg->NandEmuPath.size() == 0 ? Settings.NandEmuChanPath : game_cfg->NandEmuPath.c_str(); - NandEmu_compatible = IosLoader::is_NandEmu_compatible(NandEmuChanPath, gameIOS); - - if(!IosLoader::IsD2X(gameIOS) && !NandEmu_compatible) + if (gameNandEmuMode != EMUNAND_NEEK) { - ShowError(tr("Launching emulated NAND channels only works on d2x cIOS! Change game IOS to a d2x cIOS first.")); - return; + // If NandEmuPath is on root of the first FAT32 partition, allow Waninkoko's rev17-21 cIOS for EmuNAND Channels + bool NandEmu_compatible = false; + const char *NandEmuChanPath = game_cfg->NandEmuPath.size() == 0 ? Settings.NandEmuChanPath : game_cfg->NandEmuPath.c_str(); + NandEmu_compatible = IosLoader::is_NandEmu_compatible(NandEmuChanPath, gameIOS); + + if (!IosLoader::IsD2X(gameIOS) && !NandEmu_compatible) + { + ShowError(tr("Launching emulated NAND channels only works on d2x cIOS! Change game IOS to a d2x cIOS first.")); + return; + } } } - } - // Restrict EmuNAND with Wii games only with d2x - if(header->type == TYPE_GAME_WII_IMG || header->type == TYPE_GAME_WII_DISC) - { - if(gameNandEmuMode && !IosLoader::IsD2X(gameIOS)) + // Restrict EmuNAND with Wii games only with d2x + if (header->type == TYPE_GAME_WII_IMG || header->type == TYPE_GAME_WII_DISC) { - ShowError(tr("Launching Wii games with emulated NAND only works on d2x cIOS! Change game IOS to a d2x cIOS first.")); - return; + if (gameNandEmuMode && !IosLoader::IsD2X(gameIOS)) + { + ShowError(tr("Launching Wii games with emulated NAND only works on d2x cIOS! Change game IOS to a d2x cIOS first.")); + return; + } } } diff --git a/source/prompts/PromptWindows.cpp b/source/prompts/PromptWindows.cpp index a08d5244..36c450ac 100644 --- a/source/prompts/PromptWindows.cpp +++ b/source/prompts/PromptWindows.cpp @@ -295,10 +295,12 @@ void WindowCredits() #endif char IosInfo[80] = ""; - iosinfo_t * info = IosLoader::GetIOSInfo(IOS_GetVersion()); + iosinfo_t *info = IosLoader::GetIOSInfo(IOS_GetVersion()); if(info) + { snprintf(IosInfo, sizeof(IosInfo), "(%s v%i%s base%i)", info->name, (int)info->version, info->versionstring, (int)info->baseios); - + free(info); + } // Check if DIOS MIOS (Lite) is available char GCInfo[80] = ""; int currentMIOS = IosLoader::GetMIOSInfo(); diff --git a/source/settings/CGameSettings.cpp b/source/settings/CGameSettings.cpp index 1a0fc6f0..a836dd07 100644 --- a/source/settings/CGameSettings.cpp +++ b/source/settings/CGameSettings.cpp @@ -194,6 +194,7 @@ bool CGameSettings::Save() fprintf(f, "ocarina:%d; ", GameList[i].ocarina); fprintf(f, "vipatch:%d; ", GameList[i].vipatch); fprintf(f, "ios:%d; ", GameList[i].ios); + fprintf(f, "autoios:%d; ", GameList[i].autoios); fprintf(f, "parentalcontrol:%d; ", GameList[i].parentalcontrol); fprintf(f, "iosreloadblock:%d; ", GameList[i].iosreloadblock); fprintf(f, "patchcountrystrings:%d; ", GameList[i].patchcountrystrings); @@ -307,6 +308,11 @@ bool CGameSettings::SetSetting(GameCFG & game, const char *name, const char *val game.ios = atoi(value); return true; } + else if(strcmp(name, "autoios") == 0) + { + game.autoios = atoi(value); + return true; + } else if(strcmp(name, "parentalcontrol") == 0) { game.parentalcontrol = atoi(value); @@ -689,6 +695,7 @@ void CGameSettings::SetDefault(GameCFG &game) game.ocarina = INHERIT; game.vipatch = INHERIT; game.ios = INHERIT; + game.autoios = INHERIT; game.parentalcontrol = PARENTAL_LVL_EVERYONE; game.patchcountrystrings = INHERIT; game.loadalternatedol = ALT_DOL_DEFAULT; diff --git a/source/settings/CGameSettings.h b/source/settings/CGameSettings.h index 464caec5..f1ec67f1 100644 --- a/source/settings/CGameSettings.h +++ b/source/settings/CGameSettings.h @@ -19,6 +19,7 @@ typedef struct _GameCFG short ocarina; short vipatch; short ios; + short autoios; short parentalcontrol; short iosreloadblock; short loadalternatedol; @@ -87,6 +88,7 @@ typedef struct _GameCFG this->ocarina = game.ocarina; this->vipatch = game.vipatch; this->ios = game.ios; + this->autoios = game.autoios; this->parentalcontrol = game.parentalcontrol; this->iosreloadblock = game.iosreloadblock; this->loadalternatedol = game.loadalternatedol; diff --git a/source/settings/CSettings.cpp b/source/settings/CSettings.cpp index 6ddff8bf..24adb124 100644 --- a/source/settings/CSettings.cpp +++ b/source/settings/CSettings.cpp @@ -124,6 +124,7 @@ void CSettings::SetDefault() BootIOS = 58; LoaderIOS = 249; cios = 249; + AutoIOS = GAME_IOS_AUTO; gridRows = 3; partition = 0; discart = DISCARTS_ORIGINALS_CUSTOMS; @@ -345,6 +346,7 @@ bool CSettings::Save() fprintf(file, "GameSort = %d\n", GameSort); fprintf(file, "LoaderIOS = %d\n", LoaderIOS); fprintf(file, "cios = %d\n", cios); + fprintf(file, "autoios = %d\n", AutoIOS); fprintf(file, "keyset = %d\n", keyset); fprintf(file, "xflip = %d\n", xflip); fprintf(file, "gridRows = %d\n", gridRows); @@ -666,6 +668,11 @@ bool CSettings::SetSetting(char *name, char *value) cios = atoi(value); return true; } + else if (strcmp(name, "autoios") == 0) + { + AutoIOS = atoi(value); + return true; + } else if (strcmp(name, "keyset") == 0) { keyset = atoi(value); diff --git a/source/settings/CSettings.h b/source/settings/CSettings.h index de73b33c..52293449 100644 --- a/source/settings/CSettings.h +++ b/source/settings/CSettings.h @@ -124,6 +124,7 @@ class CSettings u8 BootIOS; u8 LoaderIOS; u8 cios; + short AutoIOS; short quickboot; short wsprompt; short keyset; @@ -171,7 +172,6 @@ class CSettings std::vector RequiredCategories; std::vector ForbiddenCategories; u8 EntryIOS; - short UseArgumentIOS; short NandEmuMode; short NandEmuChanMode; short UseSystemFont; diff --git a/source/settings/SettingsEnums.h b/source/settings/SettingsEnums.h index af460ec1..0fb3c135 100644 --- a/source/settings/SettingsEnums.h +++ b/source/settings/SettingsEnums.h @@ -409,4 +409,11 @@ enum TITLETYPE TITLETYPE_MANUAL_OVERRIDE = 7 }; +enum +{ + GAME_IOS_AUTO, + GAME_IOS_CUSTOM, + GAME_IOS_MAX +}; + #endif diff --git a/source/settings/menus/GameLoadSM.cpp b/source/settings/menus/GameLoadSM.cpp index 04f58d6b..04e66c15 100644 --- a/source/settings/menus/GameLoadSM.cpp +++ b/source/settings/menus/GameLoadSM.cpp @@ -42,6 +42,12 @@ static const char * OnOffText[] = trNOOP( "Auto" ) }; +static const char * GamesIOSText[] = +{ + trNOOP( "Auto" ), + trNOOP( "Custom" ) +}; + static const char * VideoModeText[] = { trNOOP( "System Default" ), @@ -226,6 +232,10 @@ void GameLoadSM::SetOptionNames() Options->SetName(Idx++, "%s", tr( "Hooktype" )); Options->SetName(Idx++, "%s", tr( "Wiird Debugger" )); Options->SetName(Idx++, "%s", tr( "Game IOS" )); + if(GameConfig.autoios == GAME_IOS_CUSTOM) + { + Options->SetName(Idx++, "%s", tr( "Custom Game IOS" )); + } Options->SetName(Idx++, "%s", tr( "Return To" )); Options->SetName(Idx++, "%s", tr( "Block IOS Reload" )); @@ -356,10 +366,19 @@ void GameLoadSM::SetOptionValues() Options->SetValue(Idx++, "%s", tr( OnOffText[GameConfig.WiirdDebugger] )); //! Settings: Game IOS - if(GameConfig.ios == INHERIT) + if(GameConfig.autoios == INHERIT) Options->SetValue(Idx++, tr("Use global")); else - Options->SetValue(Idx++, "%i", GameConfig.ios); + Options->SetValue(Idx++, "%s", tr( GamesIOSText[GameConfig.autoios] )); + + //! Settings: Custom Game IOS + if(GameConfig.autoios == GAME_IOS_CUSTOM) + { + if(GameConfig.ios == INHERIT) + Options->SetValue(Idx++, tr("Use global")); + else + Options->SetValue(Idx++, "%i", GameConfig.ios); + } //! Settings: Return To if(Header->type == TYPE_GAME_EMUNANDCHAN && EMUNAND_NEEK == (GameConfig.NandEmuMode == INHERIT ? Settings.NandEmuChanMode : GameConfig.NandEmuMode)) @@ -570,6 +589,15 @@ int GameLoadSM::GetMenuInternal() //! Settings: Game IOS else if (ret == ++Idx) + { + if (++GameConfig.autoios >= GAME_IOS_MAX) GameConfig.autoios = INHERIT; + Options->ClearList(); + SetOptionNames(); + SetOptionValues(); + } + + //! Settings: Custom Game IOS + else if (GameConfig.autoios == GAME_IOS_CUSTOM && ret == ++Idx) { char entered[8]; snprintf(entered, sizeof(entered), "%i", GameConfig.ios); @@ -630,14 +658,15 @@ int GameLoadSM::GetMenuInternal() //! Settings: EmuNAND Save/Channel Path else if (ret == ++Idx) { + int autoIOS = GameConfig.autoios == INHERIT ? Settings.AutoIOS : GameConfig.autoios; // If NandEmuPath is on root of the first FAT32 partition, allow rev17-21 cIOS for EmuNAND Channels bool NandEmu_compatible = false; - if(Header->type == TYPE_GAME_EMUNANDCHAN) + if(!autoIOS && Header->type == TYPE_GAME_EMUNANDCHAN) { NandEmu_compatible = IosLoader::is_NandEmu_compatible(NULL, GameConfig.ios == INHERIT ? Settings.cios : GameConfig.ios); } - if(!IosLoader::IsD2X(GameConfig.ios == INHERIT ? Settings.cios : GameConfig.ios) && !NandEmu_compatible) + if(autoIOS == GAME_IOS_CUSTOM && !IosLoader::IsD2X(GameConfig.ios == INHERIT ? Settings.cios : GameConfig.ios) && !NandEmu_compatible) WindowPrompt(tr("Error:"), tr("NAND emulation is only available on D2X cIOS!"), tr("OK")); else { diff --git a/source/settings/menus/LoaderSettings.cpp b/source/settings/menus/LoaderSettings.cpp index cac578b9..5f3702ab 100644 --- a/source/settings/menus/LoaderSettings.cpp +++ b/source/settings/menus/LoaderSettings.cpp @@ -45,6 +45,12 @@ static const char * OnOffText[] = trNOOP( "Auto" ) }; +static const char * GamesIOSText[] = +{ + trNOOP( "Auto" ), + trNOOP( "Custom" ) +}; + static const char * AspectText[] = { trNOOP( "Force 4:3" ), @@ -219,6 +225,7 @@ LoaderSettings::LoaderSettings() oldLoaderMode = Settings.LoaderMode; oldGameCubeSource = Settings.GameCubeSource; + oldLoaderIOS = Settings.LoaderIOS; } LoaderSettings::~LoaderSettings() @@ -238,6 +245,11 @@ LoaderSettings::~LoaderSettings() { GCGames::Instance()->LoadAllGames(); } + + if(oldLoaderIOS != Settings.LoaderIOS) + { + editMetaArguments(); + } } void LoaderSettings::SetOptionNames() @@ -262,6 +274,10 @@ void LoaderSettings::SetOptionNames() } Options->SetName(Idx++, "%s", tr( "Loaders IOS" )); Options->SetName(Idx++, "%s", tr( "Games IOS" )); + if(Settings.AutoIOS == GAME_IOS_CUSTOM) + { + Options->SetName(Idx++, "%s", tr( "Custom Games IOS" )); + } Options->SetName(Idx++, "%s", tr( "Quick Boot" )); Options->SetName(Idx++, "%s", tr( "Block IOS Reload" )); Options->SetName(Idx++, "%s", tr( "Return To" )); @@ -371,16 +387,25 @@ void LoaderSettings::SetOptionValues() //! Settings: Loaders IOS if (Settings.godmode) - Options->SetValue(Idx++, "IOS %i", Settings.LoaderIOS); + Options->SetValue(Idx++, "%i", Settings.LoaderIOS); else Options->SetValue(Idx++, "********"); //! Settings: Games IOS if (Settings.godmode) - Options->SetValue(Idx++, "IOS %i", Settings.cios); + Options->SetValue(Idx++, "%s", tr( GamesIOSText[Settings.AutoIOS] )); else Options->SetValue(Idx++, "********"); + //! Settings: Custom Games IOS + if(Settings.AutoIOS == GAME_IOS_CUSTOM) + { + if (Settings.godmode) + Options->SetValue(Idx++, "%i", Settings.cios); + else + Options->SetValue(Idx++, "********"); + } + //! Settings: Quick Boot Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.quickboot] )); @@ -693,6 +718,17 @@ int LoaderSettings::GetMenuInternal() //! Settings: Games IOS else if (ret == ++Idx) + { + if(!Settings.godmode) + return MENU_NONE; + if (++Settings.AutoIOS >= GAME_IOS_MAX) Settings.AutoIOS = GAME_IOS_AUTO; + Options->ClearList(); + SetOptionNames(); + SetOptionValues(); + } + + //! Settings: Custom Games IOS + else if (Settings.AutoIOS == GAME_IOS_CUSTOM && ret == ++Idx) { if(!Settings.godmode) return MENU_NONE; @@ -738,8 +774,11 @@ int LoaderSettings::GetMenuInternal() //! Settings: EmuNAND Save Mode else if (ret == ++Idx ) { - if(!IosLoader::IsD2X(Settings.cios)) - WindowPrompt(tr("Error:"), tr("NAND Emulation is only available on D2X cIOS!"), tr("OK")); + if (Settings.AutoIOS == GAME_IOS_CUSTOM && !IosLoader::IsD2X(Settings.cios)) + { + WindowPrompt(tr("Error:"), tr("NAND emulation is only available on D2X cIOS!"), tr("OK")); + Settings.NandEmuMode = EMUNAND_OFF; + } else if (++Settings.NandEmuMode >= EMUNAND_NEEK) Settings.NandEmuMode = EMUNAND_OFF; } diff --git a/source/settings/menus/LoaderSettings.hpp b/source/settings/menus/LoaderSettings.hpp index db194aea..b087ad8c 100644 --- a/source/settings/menus/LoaderSettings.hpp +++ b/source/settings/menus/LoaderSettings.hpp @@ -38,6 +38,7 @@ class LoaderSettings : public SettingsMenu short oldLoaderMode; short oldGameCubeSource; + short oldLoaderIOS; OptionList GuiOptions; }; diff --git a/source/settings/meta.cpp b/source/settings/meta.cpp index 56e96afe..27cac0ee 100644 --- a/source/settings/meta.cpp +++ b/source/settings/meta.cpp @@ -34,6 +34,8 @@ int updateMetaXML() return 0; char line[50]; + snprintf(line, sizeof(line), "--ios=%d", Settings.LoaderIOS); + MetaXML.SetArgument(line); snprintf(line, sizeof(line), "--bootios=%d", Settings.BootIOS); MetaXML.SetArgument(line); snprintf(line, sizeof(line), "--usbport=%d", Settings.USBPort); @@ -85,6 +87,8 @@ int editMetaArguments() // generate argurments if (strstr(line, "") != NULL) { + fputs(line, destination); + snprintf(line, max_line_size, " --ios=%d\n", Settings.LoaderIOS); fputs(line, destination); snprintf(line, max_line_size, " --bootios=%d\n", Settings.BootIOS); fputs(line, destination); @@ -111,11 +115,9 @@ int editMetaArguments() fclose(source); fclose(destination); delete[] line; - - if(CopyFile(metatmppath, metapath) <0) - return 0; - - RemoveFile(metatmppath); - + + if (RemoveFile(metapath)) + RenameFile(metatmppath, metapath); + return 1; } diff --git a/source/system/IosLoader.cpp b/source/system/IosLoader.cpp index d4331e3e..11a2f851 100644 --- a/source/system/IosLoader.cpp +++ b/source/system/IosLoader.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "IosLoader.h" #include "sys.h" @@ -18,27 +19,23 @@ #include "mload/modules/odip_frag.h" #include "utils/tools.h" #include "gecko.h" - -#define MEM2_PROT 0x0D8B420A -#define ES_MODULE_START ((u16 *)0x939F0000) -#define ES_MODULE_END (ES_MODULE_START + 0x4000) -#define ES_HACK_OFFSET 4 +#include "libs/libruntimeiospatch/runtimeiospatch.h" extern u32 hdd_sector_size[2]; /* * Buffer variables for the IOS info to avoid loading it several times */ -static int currentIOS = -1; -static iosinfo_t *currentIOSInfo = NULL; static int currentMIOS = -1; static int currentDMLVersion = -1; +std::vector d2x_list; + /****************************************************************************** * Public Methods: ******************************************************************************/ /* - * Check if the ios passed is a Hermes ios. + * Check if the IOS passed is a Hermes IOS. */ bool IosLoader::IsHermesIOS(s32 ios) { @@ -46,7 +43,7 @@ bool IosLoader::IsHermesIOS(s32 ios) } /* - * Check if the ios passed is a Waninkoko ios. + * Check if the IOS passed is a Waninkoko IOS. */ bool IosLoader::IsWaninkokoIOS(s32 ios) { @@ -57,22 +54,77 @@ bool IosLoader::IsWaninkokoIOS(s32 ios) } /* - * Check if the ios passed is a d2x ios. + * Check if the IOS passed is a d2x IOS. */ bool IosLoader::IsD2X(s32 ios) { - iosinfo_t *info = GetIOSInfo(ios); - if(!info) - return false; - - bool res = (strncasecmp(info->name, "d2x", 3) == 0); - - return res; + for (auto cios = d2x_list.begin(); cios != d2x_list.end(); ++cios) + { + if (cios->slot == ios) + return true; + } + return false; } /* - * Loads CIOS (If possible the one from the settings file). - * @return 0 if a cios has been successfully loaded. Else a value below 0 is returned. + * Check if the IOS is a d2x cIOS and return the base IOS. + */ +bool IosLoader::IsD2XBase(s32 ios, s32 *base) +{ + iosinfo_t *info = GetIOSInfo(ios); + if(!info) + { + *base = 0; + return 0; + } + + *base = (u8)info->baseios; + + bool result = (strncasecmp(info->name, "d2x", 3) == 0); + free(info); + return result; +} + +/* + * Get the cIOS slot from a given base IOS. + */ +s32 IosLoader::GetD2XIOS(s32 base) +{ + for (auto cios = d2x_list.begin(); cios != d2x_list.end(); ++cios) + { + if (cios->base == base) + return cios->slot; + } + return 0; +} + +/* + * Check if slots 255-200 contain a d2x cIOS and store info about them. + */ +void IosLoader::GetD2XInfo() +{ + s32 base = 0; + ISFS_Initialize(); + for (s32 i = 255; i >= 200; i--) // Prefer higher slots e.g. 251, 250 & 249 + { + if (IsD2XBase(i, &base)) + { + struct d2x cios = {}; + cios.slot = i; + cios.base = base; + cios.duplicate = GetD2XIOS(base) ? 1 : 0; + d2x_list.push_back(cios); + gprintf("Found d2x cIOS %d (base %d)\n", i, base); + } + } + ISFS_Deinitialize(); + std::sort(d2x_list.begin(), d2x_list.end(), [](const d2x &a, const d2x &b) + { return a.base < b.base; }); +} + +/* + * Loads cIOS (If possible the one from the settings file). + * @return 0 if a cIOS has been successfully loaded. Else a value below 0 is returned. */ s32 IosLoader::LoadAppCios(u8 ios) { @@ -98,7 +150,7 @@ s32 IosLoader::LoadAppCios(u8 ios) if ((ret = ReloadIosSafe(cios)) > -1) { - // Remember working cios + // Remember working cIOS Settings.LoaderIOS = cios; break; } @@ -108,8 +160,8 @@ s32 IosLoader::LoadAppCios(u8 ios) } /* - * Loads a CIOS before a game start. - * @return 0 if a cios has been successfully loaded. Else a value below 0 is returned. + * Loads a cIOS before a game start. + * @return 0 if a cIOS has been successfully loaded. Else a value below 0 is returned. */ s32 IosLoader::LoadGameCios(s32 ios) { @@ -136,7 +188,7 @@ s32 IosLoader::LoadGameCios(s32 ios) /* * Reloads a certain IOS under the condition, that an appropriate version of the IOS is installed. - * @return a negative value if a safe reload of the ios was not possible. + * @return a negative value if a safe reload of the IOS was not possible. */ s32 IosLoader::ReloadIosSafe(s32 ios) { @@ -176,45 +228,11 @@ s32 IosLoader::ReloadIosSafe(s32 ios) */ s32 IosLoader::ReloadIosKeepingRights(s32 ios) { - PatchAHB(); + IosPatch_AHBPROT(false); // Reload IOS. MEM2 protection is implicitly re-enabled return IOS_ReloadIOS(ios); } -void IosLoader::PatchAHB() -{ - if (CheckAHBPROT()) - { - static const u16 ticket_check[] = { - 0x685B, // ldr r3, [r3, #4] ; Get TMD pointer - 0x22EC, 0x0052, // movs r2, 0x1D8 ; Set offset of access rights field in TMD - 0x189B, // adds r3, r3, r2 ; Add offset to TMD pointer - 0x681B, // ldr r3, [r3] ; Load access rights. We'll hack it with full access rights!!! - 0x4698, // mov r8, r3 ; Store it for the DVD video bitcheck later - 0x07DB // lsls r3, r3, 0x1F ; check AHBPROT bit - }; - // Disable memory protection - write16(MEM2_PROT, 0); - - for (u16 *patchme = ES_MODULE_START; patchme < ES_MODULE_END; patchme++) - { - if (!memcmp(patchme, ticket_check, sizeof(ticket_check))) - { - gprintf("PatchAHB: Found TMD access rights check at %p\n", patchme); - - /* Apply patch */ - patchme[ES_HACK_OFFSET] = 0x23FF; // li r3, 0xFF ; Set full access rights - - /* Flush cache */ - DCFlushRange(patchme+ES_HACK_OFFSET, 2); - break; - } - } - // Enable memory protection - write16(MEM2_PROT, 1); - } -} - /* * Check if MIOS is DIOS MIOS, DIOS MIOS Lite or official MIOS. */ @@ -565,70 +583,51 @@ void IosLoader::LoadIOSModules(s32 ios, s32 ios_rev) mload_close(); } } + if (info) + free(info); ISFS_Deinitialize(); } } /* - * Reads the ios info struct from the .app file. + * Reads the IOS info struct from the .app file. * @return pointer to iosinfo_t on success else NULL. The user is responsible for freeing the buffer. */ iosinfo_t *IosLoader::GetIOSInfo(s32 ios) { - if(currentIOS == ios && currentIOSInfo) - return currentIOSInfo; - - if(currentIOSInfo) - { - free(currentIOSInfo); - currentIOSInfo = NULL; - } - - currentIOS = ios; - char filepath[ISFS_MAXPATH] ATTRIBUTE_ALIGN(0x20); + char filepath[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32); u64 TicketID = ((((u64) 1) << 32) | ios); u32 TMD_Length; - s32 ret = ES_GetStoredTMDSize(TicketID, &TMD_Length); - if (ret < 0) + if (ES_GetStoredTMDSize(TicketID, &TMD_Length) < 0) return NULL; signed_blob *TMD = (signed_blob*) memalign(32, ALIGN32(TMD_Length)); if (!TMD) return NULL; - ret = ES_GetStoredTMD(TicketID, TMD, TMD_Length); - if (ret < 0) + if (ES_GetStoredTMD(TicketID, TMD, TMD_Length) < 0) { free(TMD); return NULL; } - snprintf(filepath, sizeof(filepath), "/title/%08x/%08x/content/%08x.app", 0x00000001, (unsigned int)ios, (unsigned int)(*(u8 *)((u32)TMD+0x1E7))); - + snprintf(filepath, sizeof(filepath), "/title/00000001/%08x/content/%08x.app", (u8)ios, *(u8 *)((u32)TMD+0x1E7)); free(TMD); - u8 *buffer = NULL; u32 filesize = 0; + iosinfo_t *buffer = NULL; - NandTitle::LoadFileFromNand(filepath, &buffer, &filesize); + NandTitle::LoadFileFromNand(filepath, (u8**)&buffer, &filesize); - if(!buffer) + if (!buffer || filesize == 0) return NULL; - iosinfo_t *iosinfo = (iosinfo_t *) buffer; - - if(iosinfo->magicword != 0x1ee7c105 || iosinfo->magicversion != 1) + if (buffer->magicword != 0x1ee7c105 || buffer->magicversion != 1) { free(buffer); return NULL; } - iosinfo = (iosinfo_t *) realloc(buffer, sizeof(iosinfo_t)); - if(!iosinfo) - iosinfo = (iosinfo_t *) buffer; - - currentIOSInfo = iosinfo; - - return iosinfo; + return buffer; } diff --git a/source/system/IosLoader.h b/source/system/IosLoader.h index 6f74f543..4debaa7d 100644 --- a/source/system/IosLoader.h +++ b/source/system/IosLoader.h @@ -81,6 +81,13 @@ typedef struct _iosinfo_t char versionstring[0x10]; // Example: beta2 } __attribute__((packed)) iosinfo_t; +typedef struct d2x +{ + s32 slot; + s32 base; + s32 duplicate; +} d2x; + class IosLoader { public: @@ -88,10 +95,12 @@ class IosLoader static s32 LoadGameCios(s32 ios); static s32 ReloadIosSafe(s32 ios); static s32 ReloadIosKeepingRights(s32 ios); - static void PatchAHB(); static bool IsHermesIOS(s32 ios = IOS_GetVersion()); static bool IsWaninkokoIOS(s32 ios = IOS_GetVersion()); static bool IsD2X(s32 ios = IOS_GetVersion()); + static bool IsD2XBase(s32 ios, s32 *base); + static s32 GetD2XIOS(s32 base); + static void GetD2XInfo(); static iosinfo_t *GetIOSInfo(s32 ios); static u8 GetMIOSInfo(); static u8 GetDMLVersion(char* releaseDate = NULL); diff --git a/source/usbloader/GameBooter.cpp b/source/usbloader/GameBooter.cpp index fbadfec8..f7acb544 100644 --- a/source/usbloader/GameBooter.cpp +++ b/source/usbloader/GameBooter.cpp @@ -15,6 +15,8 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . ****************************************************************************/ +#include + #include "menu/menus.h" #include "menu/WDMMenu.hpp" #include "mload/mload.h" @@ -57,6 +59,7 @@ #include "neek.hpp" #include "lstub.h" #include "xml/GameTDB.hpp" +#include "wad/nandtitle.h" /* GCC 11 false positives */ #if __GNUC__ > 10 @@ -69,6 +72,7 @@ u32 AppEntrypoint = 0; extern bool isWiiVC; // in sys.cpp extern u32 hdd_sector_size[2]; +extern std::vector d2x_list; extern "C" { syssram *__SYS_LockSram(); @@ -143,7 +147,8 @@ u32 GameBooter::BootPartition(char *dolpath, u8 videoselected, u8 alternatedol, return 0; /* Open specified partition */ - ret = WDVD_OpenPartition(offset); + u32 Tmd_Buffer[0x4A00] ATTRIBUTE_ALIGN(32); + ret = WDVD_OpenPartition(offset, Tmd_Buffer); if (ret < 0) return 0; @@ -307,6 +312,7 @@ int GameBooter::BootGame(struct discHdr *gameHdr) u8 deflicker = game_cfg->deflicker == INHERIT ? Settings.deflicker : game_cfg->deflicker; u8 sneekChoice = game_cfg->sneekVideoPatch == INHERIT ? Settings.sneekVideoPatch : game_cfg->sneekVideoPatch; s32 iosChoice = game_cfg->ios == INHERIT ? Settings.cios : game_cfg->ios; + u8 autoIOS = game_cfg->autoios == INHERIT ? Settings.AutoIOS : game_cfg->autoios; u8 countrystrings = game_cfg->patchcountrystrings == INHERIT ? Settings.patchcountrystrings : game_cfg->patchcountrystrings; u8 alternatedol = game_cfg->loadalternatedol; u32 alternatedoloffset = game_cfg->alternatedolstart; @@ -363,6 +369,104 @@ int GameBooter::BootGame(struct discHdr *gameHdr) } } + if (autoIOS == GAME_IOS_AUTO && d2x_list.size()) + { + s32 requestedIOS = 0; + if (gameHeader.type == TYPE_GAME_NANDCHAN) + requestedIOS = Channels::GetRequestedIOS(gameHeader.tid, NULL); + else if (gameHeader.type == TYPE_GAME_EMUNANDCHAN) + requestedIOS = Channels::GetRequestedIOS(gameHeader.tid, NandEmuPath); + else if (gameHeader.type == TYPE_GAME_WII_IMG) + { + wbfs_disc_t *d = WBFS_OpenDisc(gameHeader.id); + if (d) + { + void *titleTMD = NULL; + int tmd_size = wbfs_extract_file(d, (char *)"TMD", &titleTMD); + if (titleTMD != NULL) + { + if (tmd_size > 0x18B) + requestedIOS = *((u8 *)titleTMD + 0x18B); + free(titleTMD); + } + WBFS_CloseDisc(d); + } + } + else if (gameHeader.type == TYPE_GAME_WII_DISC) + { + u64 offset; + if (Disc_FindPartition(&offset) >= 0) + { + u32 Tmd_Buffer[0x4A00] ATTRIBUTE_ALIGN(32); + if (WDVD_OpenPartition(offset, Tmd_Buffer) >= 0) + { + tmd *tmd_dvd = (tmd *)SIGNATURE_PAYLOAD(Tmd_Buffer); + requestedIOS = tmd_dvd->sys_version; + WDVD_ClosePartition(); + } + } + } + + if (requestedIOS) + { + // Remove cIOS duplicates + // This is done here so that IsD2X() always has the complete list + for (auto cios = d2x_list.begin(); cios != d2x_list.end();) + { + if (cios->duplicate) + { + gprintf("Duplicate IOS: %d in slot %d removed\n", cios->base, cios->slot); + cios = d2x_list.erase(cios); + } + else + ++cios; + } + + gprintf("Requested IOS: %d\n", requestedIOS); + // Workaround for SpongeBobs Boating Bash + if (memcmp(gameHeader.id, "SBV", 3) == 0) + { + // Check if we don't have a cIOS with base IOS 53 + if (!IosLoader::GetD2XIOS(requestedIOS)) + { + if (isWiiU()) + requestedIOS = 58; + else + requestedIOS = IosLoader::GetD2XIOS(58) ? 58 : 38; + gprintf("Applied SpongeBob workaround\n"); + } + } + + // Check if there's any cIOS options remaining + if (d2x_list.size()) + { + // Check for a D2X cIOS with the requested base IOS + int slot = IosLoader::GetD2XIOS(requestedIOS); + if (slot) + iosChoice = slot; + else + { + // Nothing found, so try the closest match + // e.g. if we've got 55, 57 & 58 and a game requests 56 we'll use 57 + auto cios = std::lower_bound(d2x_list.begin(), d2x_list.end(), requestedIOS, [](const d2x &x, const int &y) + { return x.base < y; }); + // Check if the requested IOS is greater than what's available + if (cios == d2x_list.end()) + { + requestedIOS = d2x_list.back().base; + iosChoice = d2x_list.back().slot; + } + else + { + requestedIOS = cios->base; + iosChoice = cios->slot; + } + gprintf("Next best IOS: %d\n", requestedIOS); + } + gprintf("Boot with IOS: %d base %d\n", iosChoice, requestedIOS); + } + } + } AppCleanUp(); gprintf("\tSettings.partition: %d\n", Settings.partition); diff --git a/source/usbloader/wdvd.c b/source/usbloader/wdvd.c index 574fd1d8..7b327d0b 100644 --- a/source/usbloader/wdvd.c +++ b/source/usbloader/wdvd.c @@ -193,12 +193,11 @@ s32 WDVD_StopMotor(void) return (ret == 1) ? 0 : -ret; } -s32 WDVD_OpenPartition(u64 offset) +s32 WDVD_OpenPartition(u64 offset, u32 *tmdbuf) { if (_di_fd < 0) return _di_fd; - static u8 Tmd_Buffer[0x4A00] ATTRIBUTE_ALIGN(32); static ioctlv Vectors[5] ATTRIBUTE_ALIGN(32); s32 ret; @@ -214,7 +213,7 @@ s32 WDVD_OpenPartition(u64 offset) Vectors[1].len = 0; Vectors[2].data = 0; Vectors[2].len = 0; - Vectors[3].data = Tmd_Buffer; + Vectors[3].data = tmdbuf; Vectors[3].len = 0x49e4; Vectors[4].data = outbuf; Vectors[4].len = 0x20; diff --git a/source/usbloader/wdvd.h b/source/usbloader/wdvd.h index 295a9975..0bdede22 100644 --- a/source/usbloader/wdvd.h +++ b/source/usbloader/wdvd.h @@ -15,7 +15,7 @@ s32 WDVD_Seek(u64); s32 WDVD_Offset(u64); s32 WDVD_StopLaser(void); s32 WDVD_StopMotor(void); -s32 WDVD_OpenPartition(u64 offset); +s32 WDVD_OpenPartition(u64 offset, u32 *tmdbuf); s32 WDVD_ClosePartition(void); s32 WDVD_UnencryptedRead(void *, u32, u64); s32 WDVD_Read(void *, u32, u64); diff --git a/svnrev.sh b/svnrev.sh index d3d559af..cac2f98b 100644 --- a/svnrev.sh +++ b/svnrev.sh @@ -49,6 +49,7 @@ cat < ./HBC/meta.xml $rev_date