From 0bdeb63894b1bc345b4f6e79cc8c0880dd436816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 1 Oct 2017 12:38:35 +0200 Subject: [PATCH 01/18] WiiUtils: Skip WAD import if it's already installed The check is fairly quick, and this allows saving a lot of time and resources for larger WADs. --- Source/Core/Core/WiiUtils.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Source/Core/Core/WiiUtils.cpp b/Source/Core/Core/WiiUtils.cpp index 4235c9ba96..6667bf80e7 100644 --- a/Source/Core/Core/WiiUtils.cpp +++ b/Source/Core/Core/WiiUtils.cpp @@ -113,6 +113,15 @@ bool InstallWAD(const std::string& wad_path) { IOS::HLE::Kernel ios; const DiscIO::WiiWAD wad{wad_path}; + + if (!wad.GetTMD().IsValid()) + return false; + + // Skip the install if the WAD is already installed. + const auto installed_contents = ios.GetES()->GetStoredContentsFromTMD(wad.GetTMD()); + if (wad.GetTMD().GetContents() == installed_contents) + return true; + const bool result = InstallWAD(ios, wad); DiscIO::NANDContentManager::Access().ClearCache(); From 6a03a248227bf762d64148bd8e68b0a9663fecce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 1 Oct 2017 12:46:38 +0200 Subject: [PATCH 02/18] WiiUtils: Warn before overwriting during WAD import --- Source/Core/Core/WiiUtils.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Source/Core/Core/WiiUtils.cpp b/Source/Core/Core/WiiUtils.cpp index 6667bf80e7..5bca8ae1cc 100644 --- a/Source/Core/Core/WiiUtils.cpp +++ b/Source/Core/Core/WiiUtils.cpp @@ -122,6 +122,15 @@ bool InstallWAD(const std::string& wad_path) if (wad.GetTMD().GetContents() == installed_contents) return true; + // If a different version is currently installed, warn the user to make sure + // they don't overwrite the current version by mistake. + if (ios.GetES()->FindInstalledTMD(wad.GetTMD().GetTitleId()).IsValid() && + !AskYesNoT("A different version of this title is already installed on the NAND. " + "Installing this WAD will replace it irreversibly. Continue?")) + { + return false; + } + const bool result = InstallWAD(ios, wad); DiscIO::NANDContentManager::Access().ClearCache(); From dd5c468c6307af02ce34affcb12f829a9cafa7a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 1 Oct 2017 15:07:59 +0200 Subject: [PATCH 03/18] WiiUtils: Allow reusing existing IOS/WAD instance --- Source/Core/Core/WiiUtils.cpp | 17 ++++++++++------- Source/Core/Core/WiiUtils.h | 6 ++++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Source/Core/Core/WiiUtils.cpp b/Source/Core/Core/WiiUtils.cpp index 5bca8ae1cc..2c766015bb 100644 --- a/Source/Core/Core/WiiUtils.cpp +++ b/Source/Core/Core/WiiUtils.cpp @@ -46,7 +46,7 @@ namespace WiiUtils { -static bool InstallWAD(IOS::HLE::Kernel& ios, const DiscIO::WiiWAD& wad) +static bool ImportWAD(IOS::HLE::Kernel& ios, const DiscIO::WiiWAD& wad) { if (!wad.IsValid()) { @@ -109,11 +109,8 @@ static bool InstallWAD(IOS::HLE::Kernel& ios, const DiscIO::WiiWAD& wad) return true; } -bool InstallWAD(const std::string& wad_path) +bool InstallWAD(IOS::HLE::Kernel& ios, const DiscIO::WiiWAD& wad) { - IOS::HLE::Kernel ios; - const DiscIO::WiiWAD wad{wad_path}; - if (!wad.GetTMD().IsValid()) return false; @@ -131,12 +128,18 @@ bool InstallWAD(const std::string& wad_path) return false; } - const bool result = InstallWAD(ios, wad); + const bool result = ImportWAD(ios, wad); DiscIO::NANDContentManager::Access().ClearCache(); return result; } +bool InstallWAD(const std::string& wad_path) +{ + IOS::HLE::Kernel ios; + return InstallWAD(ios, DiscIO::WiiWAD{wad_path}); +} + // Common functionality for system updaters. class SystemUpdater { @@ -685,7 +688,7 @@ UpdateResult DiscSystemUpdater::ProcessEntry(u32 type, std::bitset<32> attrs, return UpdateResult::DiscReadFailed; } const DiscIO::WiiWAD wad{std::move(blob)}; - return InstallWAD(m_ios, wad) ? UpdateResult::Succeeded : UpdateResult::ImportFailed; + return ImportWAD(m_ios, wad) ? UpdateResult::Succeeded : UpdateResult::ImportFailed; } UpdateResult DoOnlineUpdate(UpdateCallback update_callback, const std::string& region) diff --git a/Source/Core/Core/WiiUtils.h b/Source/Core/Core/WiiUtils.h index 0047e2c63d..eb7d669672 100644 --- a/Source/Core/Core/WiiUtils.h +++ b/Source/Core/Core/WiiUtils.h @@ -13,6 +13,10 @@ // Small utility functions for common Wii related tasks. +namespace DiscIO +{ +class WiiWAD; +} namespace IOS { namespace HLE @@ -23,6 +27,8 @@ class Kernel; namespace WiiUtils { +bool InstallWAD(IOS::HLE::Kernel& ios, const DiscIO::WiiWAD& wad); +// Same as the above, but constructs a temporary IOS and WiiWAD instance for importing. bool InstallWAD(const std::string& wad_path); enum class UpdateResult From 62be010ac6c38582e6254f21b510264876301ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 1 Oct 2017 19:33:59 +0200 Subject: [PATCH 04/18] WiiUtils: Improve the error message on import failure Now shows the import return code and also skips showing the message altogether if the user cancelled the import for an unsigned WAD. --- Source/Core/Core/WiiUtils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/WiiUtils.cpp b/Source/Core/Core/WiiUtils.cpp index 2c766015bb..63f50a1ea2 100644 --- a/Source/Core/Core/WiiUtils.cpp +++ b/Source/Core/Core/WiiUtils.cpp @@ -76,8 +76,9 @@ static bool ImportWAD(IOS::HLE::Kernel& ios, const DiscIO::WiiWAD& wad) continue; } + if (ret != IOS::HLE::IOSC_FAIL_CHECKVALUE) + PanicAlertT("WAD installation failed: Could not initialise title import (error %d).", ret); SConfig::GetInstance().m_enable_signature_checks = checks_enabled; - PanicAlertT("WAD installation failed: Could not initialise title import."); return false; } SConfig::GetInstance().m_enable_signature_checks = checks_enabled; From 60ba3827992ab5cfaea345a10b0f4d162aa2b75e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 1 Oct 2017 15:41:54 +0200 Subject: [PATCH 05/18] Boot: Add support for booting NAND titles with just the ID --- Source/Core/Core/Boot/Boot.cpp | 9 ++++++++- Source/Core/Core/Boot/Boot.h | 10 ++++++++-- Source/Core/Core/Boot/Boot_BS2Emu.cpp | 7 ++----- Source/Core/Core/Boot/Boot_WiiWAD.cpp | 14 ++++++++++++++ Source/Core/Core/ConfigManager.cpp | 15 +++++++++++++++ Source/Core/DolphinQt2/MainWindow.cpp | 3 +-- Source/Core/DolphinWX/FrameTools.cpp | 2 +- 7 files changed, 49 insertions(+), 11 deletions(-) diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index a93ba7b577..94bd4ef2b8 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -339,7 +339,8 @@ bool CBoot::BootUp(std::unique_ptr boot) HID4.SBE = 1; // Because there is no TMD to get the requested system (IOS) version from, // we default to IOS58, which is the version used by the Homebrew Channel. - SetupWiiMemory(0x000000010000003a); + SetupWiiMemory(); + IOS::HLE::GetIOS()->BootIOS(0x000000010000003a); } else { @@ -363,6 +364,12 @@ bool CBoot::BootUp(std::unique_ptr boot) return Boot_WiiWAD(nand.content_path); } + bool operator()(const BootParameters::NANDTitle& nand_title) const + { + SetDefaultDisc(); + return BootNANDTitle(nand_title.id); + } + bool operator()(const BootParameters::IPL& ipl) const { NOTICE_LOG(BOOT, "Booting GC IPL: %s", ipl.path.c_str()); diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h index 96dd2002e4..b3bc5fab36 100644 --- a/Source/Core/Core/Boot/Boot.h +++ b/Source/Core/Core/Boot/Boot.h @@ -50,6 +50,11 @@ struct BootParameters std::string content_path; }; + struct NANDTitle + { + u64 id; + }; + struct IPL { explicit IPL(DiscIO::Region region_); @@ -67,7 +72,7 @@ struct BootParameters static std::unique_ptr GenerateFromFile(const std::string& path); - using Parameters = std::variant; + using Parameters = std::variant; BootParameters(Parameters&& parameters_); Parameters parameters; @@ -99,6 +104,7 @@ private: static void UpdateDebugger_MapLoaded(); static bool Boot_WiiWAD(const std::string& filename); + static bool BootNANDTitle(u64 title_id); static void SetupMSR(); static void SetupBAT(bool is_wii); @@ -109,7 +115,7 @@ private: static bool Load_BS2(const std::string& boot_rom_filename); static void SetupGCMemory(); - static bool SetupWiiMemory(u64 ios_title_id); + static bool SetupWiiMemory(); }; class BootExecutableReader diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index 794e979aa1..ac7d691fce 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -213,7 +213,7 @@ bool CBoot::EmulatedBS2_GC(const DiscIO::Volume& volume) return RunApploader(/*is_wii*/ false, volume); } -bool CBoot::SetupWiiMemory(u64 ios_title_id) +bool CBoot::SetupWiiMemory() { static const std::map region_settings = { {DiscIO::Region::NTSC_J, {"JPN", "NTSC", "JP", "LJ"}}, @@ -308,9 +308,6 @@ bool CBoot::SetupWiiMemory(u64 ios_title_id) // It is fine to always use the latest value as apploaders work with all versions. Memory::Write_U16(0x0113, 0x0000315e); - if (!IOS::HLE::GetIOS()->BootIOS(ios_title_id)) - return false; - Memory::Write_U8(0x80, 0x0000315c); // OSInit Memory::Write_U16(0x0000, 0x000030e0); // PADInit Memory::Write_U32(0x80000000, 0x00003184); // GameID Address @@ -367,7 +364,7 @@ bool CBoot::EmulatedBS2_Wii(const DiscIO::Volume& volume) Memory::Write_U32(0, 0x3194); Memory::Write_U32(static_cast(data_partition.offset >> 2), 0x3198); - if (!SetupWiiMemory(tmd.GetIOSId())) + if (!SetupWiiMemory() || !IOS::HLE::GetIOS()->BootIOS(tmd.GetIOSId())) return false; DVDRead(volume, 0x00000000, 0x00000000, 0x20, DiscIO::PARTITION_NONE); // Game Code diff --git a/Source/Core/Core/Boot/Boot_WiiWAD.cpp b/Source/Core/Core/Boot/Boot_WiiWAD.cpp index 44d2b64262..de4275c14a 100644 --- a/Source/Core/Core/Boot/Boot_WiiWAD.cpp +++ b/Source/Core/Core/Boot/Boot_WiiWAD.cpp @@ -21,6 +21,20 @@ #include "DiscIO/NANDContentLoader.h" +bool CBoot::BootNANDTitle(const u64 title_id) +{ + UpdateStateFlags([](StateFlags* state) { + state->type = 0x03; // TYPE_RETURN + }); + + if (title_id == Titles::SYSTEM_MENU) + IOS::HLE::CreateVirtualFATFilesystem(); + + SetupWiiMemory(); + auto* ios = IOS::HLE::GetIOS(); + return ios->GetES()->LaunchTitle(title_id); +} + bool CBoot::Boot_WiiWAD(const std::string& _pFilename) { UpdateStateFlags([](StateFlags* state) { diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 2341fdfba3..c5d39b5530 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -902,6 +902,21 @@ struct SetGameMetadata return true; } + bool operator()(const BootParameters::NANDTitle& nand_title) const + { + IOS::HLE::Kernel ios; + const IOS::ES::TMDReader tmd = ios.GetES()->FindInstalledTMD(nand_title.id); + if (!tmd.IsValid() || !IOS::ES::IsChannel(nand_title.id)) + { + PanicAlertT("This title cannot be booted."); + return false; + } + config->SetRunningGameMetadata(tmd); + config->bWii = true; + *region = tmd.GetRegion(); + return true; + } + bool operator()(const BootParameters::IPL& ipl) const { config->bWii = false; diff --git a/Source/Core/DolphinQt2/MainWindow.cpp b/Source/Core/DolphinQt2/MainWindow.cpp index fbb508f195..7ebc6e9546 100644 --- a/Source/Core/DolphinQt2/MainWindow.cpp +++ b/Source/Core/DolphinQt2/MainWindow.cpp @@ -652,8 +652,7 @@ void MainWindow::PerformOnlineUpdate(const std::string& region) void MainWindow::BootWiiSystemMenu() { - StartGame(QString::fromStdString( - Common::GetTitleContentPath(Titles::SYSTEM_MENU, Common::FROM_CONFIGURED_ROOT))); + StartGame(std::make_unique(BootParameters::NANDTitle{Titles::SYSTEM_MENU})); } void MainWindow::NetPlayInit() diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index 592f338cd2..7ec4cb0da1 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -1225,7 +1225,7 @@ void CFrame::OnShowCheatsWindow(wxCommandEvent& WXUNUSED(event)) void CFrame::OnLoadWiiMenu(wxCommandEvent& WXUNUSED(event)) { - BootGame(Common::GetTitleContentPath(Titles::SYSTEM_MENU, Common::FROM_CONFIGURED_ROOT)); + StartGame(std::make_unique(BootParameters::NANDTitle{Titles::SYSTEM_MENU})); } void CFrame::OnInstallWAD(wxCommandEvent& event) From 9000a042e4bbc340f6b4787c3fff70b7304d4cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 1 Oct 2017 15:14:53 +0200 Subject: [PATCH 06/18] Drop the direct WAD launch hack This removes the hack that enables directly booting from WADs without installing them first for the following reasons: 1. It makes the NAND content handling much more complicated than what it should be and makes future changes like permissions or booting NAND titles without a WAD more annoying to implement. Because of this hack, we needed an extra level of abstraction (NANDContent*) which has to read tons of things from the NAND, even most of the time it's useless. This in turn forces us to have caching, which is known to break titles and requires manual cache invalidations. Annoying and error prone. 2. It prevents the WAD boot code from being easily accurate. With this change, we can simply reuse the existing launch code, and ask IOS to launch the title from the NAND. 3. The hack did not work that well since it did not cover a lot of ES commands. And it works even less since the ES accuracy fixes. This results in Dolphin returning inconsistent results: a lot of the ES "DI" commands will just fail because the active title is not installed on the NAND. uid.sys is not changed, etc. And I'm not even talking about FS stuff -- where this would still totally fail, unless we add even more unnecessary hacks. This is not just theoretical -- the system menu and the Wii Shop are known to behave strangely because the hack damages the NAND structure, and we've already had several users report issues. This commit makes it so WADs are always installed prior to launching. A future commit will remove any code that was there only for the hack. --- Source/Core/Core/Boot/Boot.cpp | 9 +++--- Source/Core/Core/Boot/Boot.h | 11 +++---- Source/Core/Core/Boot/Boot_WiiWAD.cpp | 44 ++++----------------------- Source/Core/Core/ConfigManager.cpp | 17 ++++++++--- Source/Core/DiscIO/WiiWad.h | 2 ++ 5 files changed, 28 insertions(+), 55 deletions(-) diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 94bd4ef2b8..9d12c2188d 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -100,8 +100,8 @@ std::unique_ptr BootParameters::GenerateFromFile(const std::stri if (extension == ".dff") return std::make_unique(DFF{path}); - if (DiscIO::NANDContentManager::Access().GetNANDLoader(path).IsValid()) - return std::make_unique(NAND{path}); + if (extension == ".wad") + return std::make_unique(DiscIO::WiiWAD{path}); PanicAlertT("Could not recognize file %s", path.c_str()); return {}; @@ -357,11 +357,10 @@ bool CBoot::BootUp(std::unique_ptr boot) return true; } - bool operator()(const BootParameters::NAND& nand) const + bool operator()(const DiscIO::WiiWAD& wad) const { - NOTICE_LOG(BOOT, "Booting from NAND: %s", nand.content_path.c_str()); SetDefaultDisc(); - return Boot_WiiWAD(nand.content_path); + return Boot_WiiWAD(wad); } bool operator()(const BootParameters::NANDTitle& nand_title) const diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h index b3bc5fab36..9295244bcb 100644 --- a/Source/Core/Core/Boot/Boot.h +++ b/Source/Core/Core/Boot/Boot.h @@ -13,8 +13,10 @@ #include #include "Common/CommonTypes.h" +#include "DiscIO/Blob.h" #include "DiscIO/Enums.h" #include "DiscIO/Volume.h" +#include "DiscIO/WiiWad.h" namespace File { @@ -45,11 +47,6 @@ struct BootParameters std::unique_ptr reader; }; - struct NAND - { - std::string content_path; - }; - struct NANDTitle { u64 id; @@ -72,7 +69,7 @@ struct BootParameters static std::unique_ptr GenerateFromFile(const std::string& path); - using Parameters = std::variant; + using Parameters = std::variant; BootParameters(Parameters&& parameters_); Parameters parameters; @@ -103,7 +100,7 @@ private: static void UpdateDebugger_MapLoaded(); - static bool Boot_WiiWAD(const std::string& filename); + static bool Boot_WiiWAD(const DiscIO::WiiWAD& wad); static bool BootNANDTitle(u64 title_id); static void SetupMSR(); diff --git a/Source/Core/Core/Boot/Boot_WiiWAD.cpp b/Source/Core/Core/Boot/Boot_WiiWAD.cpp index de4275c14a..1aa8193fff 100644 --- a/Source/Core/Core/Boot/Boot_WiiWAD.cpp +++ b/Source/Core/Core/Boot/Boot_WiiWAD.cpp @@ -18,8 +18,10 @@ #include "Core/IOS/ES/Formats.h" #include "Core/IOS/FS/FileIO.h" #include "Core/IOS/IOS.h" +#include "Core/WiiUtils.h" #include "DiscIO/NANDContentLoader.h" +#include "DiscIO/WiiWad.h" bool CBoot::BootNANDTitle(const u64 title_id) { @@ -35,46 +37,12 @@ bool CBoot::BootNANDTitle(const u64 title_id) return ios->GetES()->LaunchTitle(title_id); } -bool CBoot::Boot_WiiWAD(const std::string& _pFilename) +bool CBoot::Boot_WiiWAD(const DiscIO::WiiWAD& wad) { - UpdateStateFlags([](StateFlags* state) { - state->type = 0x03; // TYPE_RETURN - }); - - const DiscIO::NANDContentLoader& ContentLoader = - DiscIO::NANDContentManager::Access().GetNANDLoader(_pFilename); - if (!ContentLoader.IsValid()) - return false; - - u64 titleID = ContentLoader.GetTMD().GetTitleId(); - - if (!IOS::ES::IsChannel(titleID)) + if (!WiiUtils::InstallWAD(*IOS::HLE::GetIOS(), wad)) { - PanicAlertT("This WAD is not bootable."); + PanicAlertT("Cannot boot this WAD because it could not be installed to the NAND."); return false; } - - // create data directory - File::CreateFullPath(Common::GetTitleDataPath(titleID, Common::FROM_SESSION_ROOT)); - - if (titleID == Titles::SYSTEM_MENU) - IOS::HLE::CreateVirtualFATFilesystem(); - // setup Wii memory - - if (!SetupWiiMemory(ContentLoader.GetTMD().GetIOSId())) - return false; - - IOS::HLE::Device::ES::LoadWAD(_pFilename); - - // TODO: kill these manual calls and just use ES_Launch here, as soon as the direct WAD - // launch hack is dropped. - auto* ios = IOS::HLE::GetIOS(); - IOS::ES::UIDSys uid_map{Common::FROM_SESSION_ROOT}; - ios->SetUidForPPC(uid_map.GetOrInsertUIDForTitle(titleID)); - ios->SetGidForPPC(ContentLoader.GetTMD().GetGroupId()); - - if (!ios->BootstrapPPC(ContentLoader)) - return false; - - return true; + return BootNANDTitle(wad.GetTMD().GetTitleId()); } diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index c5d39b5530..5c074768d0 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -45,6 +45,7 @@ #include "DiscIO/Enums.h" #include "DiscIO/NANDContentLoader.h" #include "DiscIO/Volume.h" +#include "DiscIO/WiiWad.h" SConfig* SConfig::m_Instance; @@ -888,14 +889,20 @@ struct SetGameMetadata return true; } - bool operator()(const BootParameters::NAND& nand) const + bool operator()(const DiscIO::WiiWAD& wad) const { - const auto& loader = DiscIO::NANDContentManager::Access().GetNANDLoader(nand.content_path); - if (!loader.IsValid()) + if (!wad.IsValid() || !wad.GetTMD().IsValid()) + { + PanicAlertT("This WAD is not valid."); return false; + } + if (!IOS::ES::IsChannel(wad.GetTMD().GetTitleId())) + { + PanicAlertT("This WAD is not bootable."); + return false; + } - const IOS::ES::TMDReader& tmd = loader.GetTMD(); - + const IOS::ES::TMDReader& tmd = wad.GetTMD(); config->SetRunningGameMetadata(tmd); config->bWii = true; *region = tmd.GetRegion(); diff --git a/Source/Core/DiscIO/WiiWad.h b/Source/Core/DiscIO/WiiWad.h index 6f3f4a97bc..1bdd40f698 100644 --- a/Source/Core/DiscIO/WiiWad.h +++ b/Source/Core/DiscIO/WiiWad.h @@ -20,6 +20,8 @@ class WiiWAD public: explicit WiiWAD(const std::string& name); explicit WiiWAD(std::unique_ptr blob_reader); + WiiWAD(WiiWAD&&) = default; + WiiWAD& operator=(WiiWAD&&) = default; ~WiiWAD(); bool IsValid() const { return m_valid; } From 0476c0e60e791878217b546ca7f6fef36c9b35d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 1 Oct 2017 16:28:46 +0200 Subject: [PATCH 07/18] [Cleanup] Remove static state in ES --- Source/Core/Core/Boot/Boot_BS2Emu.cpp | 2 +- Source/Core/Core/IOS/DI/DI.cpp | 2 +- Source/Core/Core/IOS/ES/ES.cpp | 66 ++++----------------- Source/Core/Core/IOS/ES/ES.h | 9 ++- Source/Core/Core/IOS/ES/Identity.cpp | 4 +- Source/Core/Core/IOS/ES/TitleContents.cpp | 6 +- Source/Core/Core/IOS/ES/TitleManagement.cpp | 8 +-- Source/Core/Core/IOS/ES/Views.cpp | 28 ++++----- Source/Core/Core/State.cpp | 2 +- 9 files changed, 43 insertions(+), 84 deletions(-) diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index ac7d691fce..7bc1799878 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -389,7 +389,7 @@ bool CBoot::EmulatedBS2_Wii(const DiscIO::Volume& volume) // Warning: This call will set incorrect running game metadata if our volume parameter // doesn't point to the same disc as the one that's inserted in the emulated disc drive! - IOS::HLE::Device::ES::DIVerify(tmd, volume.GetTicket(partition)); + IOS::HLE::GetIOS()->GetES()->DIVerify(tmd, volume.GetTicket(partition)); return true; } diff --git a/Source/Core/Core/IOS/DI/DI.cpp b/Source/Core/Core/IOS/DI/DI.cpp index 39311960fd..af8b5343bd 100644 --- a/Source/Core/Core/IOS/DI/DI.cpp +++ b/Source/Core/Core/IOS/DI/DI.cpp @@ -113,7 +113,7 @@ IPCCommandResult DI::IOCtlV(const IOCtlVRequest& request) const IOS::ES::TMDReader tmd = DVDThread::GetTMD(partition); const std::vector& raw_tmd = tmd.GetBytes(); Memory::CopyToEmu(request.io_vectors[0].address, raw_tmd.data(), raw_tmd.size()); - ES::DIVerify(tmd, DVDThread::GetTicket(partition)); + m_ios.GetES()->DIVerify(tmd, DVDThread::GetTicket(partition)); return_value = 1; break; diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index e398d0bb5c..64fa54930e 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -35,10 +35,6 @@ namespace HLE { namespace Device { -// TODO: drop this and convert the title context into a member once the WAD launch hack is gone. -static std::string s_content_file; -static TitleContext s_title_context; - // Title to launch after IOS has been reset and reloaded (similar to /sys/launch.sys). static u64 s_title_to_launch; @@ -84,9 +80,6 @@ ES::ES(Kernel& ios, const std::string& device_name) : Device(ios, device_name) FinishAllStaleImports(); - s_content_file = ""; - s_title_context = TitleContext{}; - if (s_title_to_launch != 0) { NOTICE_LOG(IOS, "Re-launching title after IOS reload."); @@ -95,11 +88,6 @@ ES::ES(Kernel& ios, const std::string& device_name) : Device(ios, device_name) } } -TitleContext& ES::GetTitleContext() -{ - return s_title_context; -} - void TitleContext::Clear() { ticket.SetBytes({}); @@ -114,13 +102,6 @@ void TitleContext::DoState(PointerWrap& p) p.Do(active); } -void TitleContext::Update(const DiscIO::NANDContentLoader& content_loader) -{ - if (!content_loader.IsValid()) - return; - Update(content_loader.GetTMD(), content_loader.GetTicket()); -} - void TitleContext::Update(const IOS::ES::TMDReader& tmd_, const IOS::ES::TicketReader& ticket_) { if (!tmd_.IsValid() || !ticket_.IsValid()) @@ -141,16 +122,6 @@ void TitleContext::Update(const IOS::ES::TMDReader& tmd_, const IOS::ES::TicketR } } -void ES::LoadWAD(const std::string& _rContentFile) -{ - s_content_file = _rContentFile; - // XXX: Ideally, this should be done during a launch, but because we support launching WADs - // without installing them (which is a bit of a hack), we have to do this manually here. - const auto& content_loader = DiscIO::NANDContentManager::Access().GetNANDLoader(s_content_file); - s_title_context.Update(content_loader); - INFO_LOG(IOS_ES, "LoadWAD: Title context changed: %016" PRIx64, s_title_context.tmd.GetTitleId()); -} - IPCCommandResult ES::GetTitleDirectory(const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(1, 1)) @@ -167,9 +138,9 @@ IPCCommandResult ES::GetTitleDirectory(const IOCtlVRequest& request) ReturnCode ES::GetTitleId(u64* title_id) const { - if (!s_title_context.active) + if (!m_title_context.active) return ES_EINVAL; - *title_id = s_title_context.tmd.GetTitleId(); + *title_id = m_title_context.tmd.GetTitleId(); return IPC_SUCCESS; } @@ -242,7 +213,7 @@ IPCCommandResult ES::SetUID(u32 uid, const IOCtlVRequest& request) bool ES::LaunchTitle(u64 title_id, bool skip_reload) { - s_title_context.Clear(); + m_title_context.Clear(); INFO_LOG(IOS_ES, "ES_Launch: Title context changed: (none)"); NOTICE_LOG(IOS_ES, "Launching title %016" PRIx64 "...", title_id); @@ -310,15 +281,15 @@ bool ES::LaunchPPCTitle(u64 title_id, bool skip_reload) return LaunchTitle(required_ios); } - s_title_context.Update(content_loader); + m_title_context.Update(content_loader.GetTMD(), content_loader.GetTicket()); INFO_LOG(IOS_ES, "LaunchPPCTitle: Title context changed: %016" PRIx64, - s_title_context.tmd.GetTitleId()); + m_title_context.tmd.GetTitleId()); // Note: the UID/GID is also updated for IOS titles, but since we have no guarantee IOS titles // are installed, we can only do this for PPC titles. - if (!UpdateUIDAndGID(m_ios, s_title_context.tmd)) + if (!UpdateUIDAndGID(m_ios, m_title_context.tmd)) { - s_title_context.Clear(); + m_title_context.Clear(); INFO_LOG(IOS_ES, "LaunchPPCTitle: Title context changed: (none)"); return false; } @@ -339,9 +310,8 @@ void ES::Context::DoState(PointerWrap& p) void ES::DoState(PointerWrap& p) { Device::DoState(p); - p.Do(s_content_file); p.Do(m_content_table); - s_title_context.DoState(p); + m_title_context.DoState(p); for (auto& context : m_contexts) context.DoState(p); @@ -605,16 +575,6 @@ IPCCommandResult ES::LaunchBC(const IOCtlVRequest& request) const DiscIO::NANDContentLoader& ES::AccessContentDevice(u64 title_id) { - // for WADs, the passed title id and the stored title id match; along with s_content_file - // being set to the actual WAD file name. We cannot simply get a NAND Loader for the title id - // in those cases, since the WAD need not be installed in the NAND, but it could be opened - // directly from a WAD file anywhere on disk. - if (s_title_context.active && s_title_context.tmd.GetTitleId() == title_id && - !s_content_file.empty()) - { - return DiscIO::NANDContentManager::Access().GetNANDLoader(s_content_file); - } - return DiscIO::NANDContentManager::Access().GetNANDLoader(title_id, Common::FROM_SESSION_ROOT); } @@ -628,7 +588,7 @@ IPCCommandResult ES::DIVerify(const IOCtlVRequest& request) s32 ES::DIVerify(const IOS::ES::TMDReader& tmd, const IOS::ES::TicketReader& ticket) { - s_title_context.Clear(); + m_title_context.Clear(); INFO_LOG(IOS_ES, "ES_DIVerify: Title context changed: (none)"); if (!tmd.IsValid() || !ticket.IsValid()) @@ -637,7 +597,7 @@ s32 ES::DIVerify(const IOS::ES::TMDReader& tmd, const IOS::ES::TicketReader& tic if (tmd.GetTitleId() != ticket.GetTitleId()) return ES_EINVAL; - s_title_context.Update(tmd, ticket); + m_title_context.Update(tmd, ticket); INFO_LOG(IOS_ES, "ES_DIVerify: Title context changed: %016" PRIx64, tmd.GetTitleId()); std::string tmd_path = Common::GetTMDFileName(tmd.GetTitleId(), Common::FROM_SESSION_ROOT); @@ -659,7 +619,7 @@ s32 ES::DIVerify(const IOS::ES::TMDReader& tmd, const IOS::ES::TicketReader& tic // clear the cache to avoid content access mismatches. DiscIO::NANDContentManager::Access().ClearCache(); - if (!UpdateUIDAndGID(*GetIOS(), s_title_context.tmd)) + if (!UpdateUIDAndGID(*GetIOS(), m_title_context.tmd)) { return ES_SHORT_READ; } @@ -803,10 +763,10 @@ IPCCommandResult ES::DeleteStreamKey(const IOCtlVRequest& request) bool ES::IsActiveTitlePermittedByTicket(const u8* ticket_view) const { - if (!GetTitleContext().active) + if (!m_title_context.active) return false; - const u32 title_identifier = static_cast(GetTitleContext().tmd.GetTitleId()); + const u32 title_identifier = static_cast(m_title_context.tmd.GetTitleId()); const u32 permitted_title_mask = Common::swap32(ticket_view + offsetof(IOS::ES::TicketView, permitted_title_mask)); const u32 permitted_title_id = diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index d7122ddb1f..41b3dbd559 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -32,7 +32,6 @@ struct TitleContext { void Clear(); void DoState(PointerWrap& p); - void Update(const DiscIO::NANDContentLoader& content_loader); void Update(const IOS::ES::TMDReader& tmd_, const IOS::ES::TicketReader& ticket_); IOS::ES::TicketReader ticket; @@ -46,8 +45,7 @@ class ES final : public Device public: ES(Kernel& ios, const std::string& device_name); - static s32 DIVerify(const IOS::ES::TMDReader& tmd, const IOS::ES::TicketReader& ticket); - static void LoadWAD(const std::string& _rContentFile); + s32 DIVerify(const IOS::ES::TMDReader& tmd, const IOS::ES::TicketReader& ticket); bool LaunchTitle(u64 title_id, bool skip_reload = false); void DoState(PointerWrap& p) override; @@ -306,7 +304,6 @@ private: bool LaunchIOS(u64 ios_title_id); bool LaunchPPCTitle(u64 title_id, bool skip_reload); - static TitleContext& GetTitleContext(); bool IsActiveTitlePermittedByTicket(const u8* ticket_view) const; ReturnCode CheckStreamKeyPermissions(u32 uid, const u8* ticket_view, @@ -341,7 +338,8 @@ private: void FinishStaleImport(u64 title_id); void FinishAllStaleImports(); - static const DiscIO::NANDContentLoader& AccessContentDevice(u64 title_id); + // TODO: remove these + const DiscIO::NANDContentLoader& AccessContentDevice(u64 title_id); // TODO: reuse the FS code. struct OpenedContent @@ -357,6 +355,7 @@ private: ContentTable m_content_table; ContextArray m_contexts; + TitleContext m_title_context{}; }; } // namespace Device } // namespace HLE diff --git a/Source/Core/Core/IOS/ES/Identity.cpp b/Source/Core/Core/IOS/ES/Identity.cpp index 9e24a78959..dd6c342a48 100644 --- a/Source/Core/Core/IOS/ES/Identity.cpp +++ b/Source/Core/Core/IOS/ES/Identity.cpp @@ -110,11 +110,11 @@ IPCCommandResult ES::Sign(const IOCtlVRequest& request) u32 data_size = request.in_vectors[0].size; u8* sig_out = Memory::GetPointer(request.io_vectors[0].address); - if (!GetTitleContext().active) + if (!m_title_context.active) return GetDefaultReply(ES_EINVAL); const EcWii& ec = EcWii::GetInstance(); - MakeAPSigAndCert(sig_out, ap_cert_out, GetTitleContext().tmd.GetTitleId(), data, data_size, + MakeAPSigAndCert(sig_out, ap_cert_out, m_title_context.tmd.GetTitleId(), data, data_size, ec.GetNGPriv(), ec.GetNGID()); return GetDefaultReply(IPC_SUCCESS); diff --git a/Source/Core/Core/IOS/ES/TitleContents.cpp b/Source/Core/Core/IOS/ES/TitleContents.cpp index d6cba3fb9f..46b6477c0e 100644 --- a/Source/Core/Core/IOS/ES/TitleContents.cpp +++ b/Source/Core/Core/IOS/ES/TitleContents.cpp @@ -77,15 +77,15 @@ IPCCommandResult ES::OpenActiveTitleContent(u32 caller_uid, const IOCtlVRequest& const u32 content_index = Memory::Read_U32(request.in_vectors[0].address); - if (!GetTitleContext().active) + if (!m_title_context.active) return GetDefaultReply(ES_EINVAL); IOS::ES::UIDSys uid_map{Common::FROM_SESSION_ROOT}; - const u32 uid = uid_map.GetOrInsertUIDForTitle(GetTitleContext().tmd.GetTitleId()); + const u32 uid = uid_map.GetOrInsertUIDForTitle(m_title_context.tmd.GetTitleId()); if (caller_uid != 0 && caller_uid != uid) return GetDefaultReply(ES_EACCES); - return GetDefaultReply(OpenContent(GetTitleContext().tmd, content_index, caller_uid)); + return GetDefaultReply(OpenContent(m_title_context.tmd, content_index, caller_uid)); } s32 ES::ReadContent(u32 cfd, u8* buffer, u32 size, u32 uid) diff --git a/Source/Core/Core/IOS/ES/TitleManagement.cpp b/Source/Core/Core/IOS/ES/TitleManagement.cpp index 4a9e82aeb8..d571465094 100644 --- a/Source/Core/Core/IOS/ES/TitleManagement.cpp +++ b/Source/Core/Core/IOS/ES/TitleManagement.cpp @@ -160,8 +160,8 @@ ReturnCode ES::ImportTmd(Context& context, const std::vector& tmd_bytes) if (!InitImport(context.title_import_export.tmd.GetTitleId())) return ES_EIO; - ret = InitBackupKey(GetTitleContext().tmd, m_ios.GetIOSC(), - &context.title_import_export.key_handle); + ret = + InitBackupKey(m_title_context.tmd, m_ios.GetIOSC(), &context.title_import_export.key_handle); if (ret != IPC_SUCCESS) return ret; @@ -639,8 +639,8 @@ ReturnCode ES::ExportTitleInit(Context& context, u64 title_id, u8* tmd_bytes, u3 ResetTitleImportContext(&context, m_ios.GetIOSC()); context.title_import_export.tmd = tmd; - const ReturnCode ret = InitBackupKey(GetTitleContext().tmd, m_ios.GetIOSC(), - &context.title_import_export.key_handle); + const ReturnCode ret = + InitBackupKey(m_title_context.tmd, m_ios.GetIOSC(), &context.title_import_export.key_handle); if (ret != IPC_SUCCESS) return ret; diff --git a/Source/Core/Core/IOS/ES/Views.cpp b/Source/Core/Core/IOS/ES/Views.cpp index a687419408..08e0e1ed3b 100644 --- a/Source/Core/Core/IOS/ES/Views.cpp +++ b/Source/Core/Core/IOS/ES/Views.cpp @@ -52,7 +52,7 @@ IPCCommandResult ES::GetTicketViewCount(const IOCtlVRequest& request) const IOS::ES::TicketReader ticket = DiscIO::FindSignedTicket(TitleID); u32 view_count = ticket.IsValid() ? static_cast(ticket.GetNumberOfTickets()) : 0; - if (ShouldReturnFakeViewsForIOSes(TitleID, GetTitleContext())) + if (ShouldReturnFakeViewsForIOSes(TitleID, m_title_context)) { view_count = 1; WARN_LOG(IOS_ES, "GetViewCount: Faking IOS title %016" PRIx64 " being present", TitleID); @@ -85,7 +85,7 @@ IPCCommandResult ES::GetTicketViews(const IOCtlVRequest& request) ticket_view.data(), ticket_view.size()); } } - else if (ShouldReturnFakeViewsForIOSes(TitleID, GetTitleContext())) + else if (ShouldReturnFakeViewsForIOSes(TitleID, m_title_context)) { Memory::Memset(request.io_vectors[0].address, 0, sizeof(IOS::ES::TicketView)); WARN_LOG(IOS_ES, "GetViews: Faking IOS title %016" PRIx64 " being present", TitleID); @@ -112,11 +112,11 @@ ReturnCode ES::GetV0TicketFromView(const u8* ticket_view, u8* ticket) const if (ticket_bytes.empty()) return ES_NO_TICKET; - if (!GetTitleContext().active) + if (!m_title_context.active) return ES_EINVAL; // Check for permission to export the ticket. - const u32 title_identifier = static_cast(GetTitleContext().tmd.GetTitleId()); + const u32 title_identifier = static_cast(m_title_context.tmd.GetTitleId()); const u32 permitted_title_mask = Common::swap32(ticket_bytes.data() + offsetof(IOS::ES::Ticket, permitted_title_mask)); const u32 permitted_title_id = @@ -276,10 +276,10 @@ IPCCommandResult ES::DIGetTMDViewSize(const IOCtlVRequest& request) else { // If no TMD was passed in and no title is active, IOS returns -1017. - if (!GetTitleContext().active) + if (!m_title_context.active) return GetDefaultReply(ES_EINVAL); - tmd_view_size = GetTitleContext().tmd.GetRawView().size(); + tmd_view_size = m_title_context.tmd.GetRawView().size(); } Memory::Write_U32(static_cast(tmd_view_size), request.io_vectors[0].address); @@ -319,10 +319,10 @@ IPCCommandResult ES::DIGetTMDView(const IOCtlVRequest& request) else { // If no TMD was passed in and no title is active, IOS returns -1017. - if (!GetTitleContext().active) + if (!m_title_context.active) return GetDefaultReply(ES_EINVAL); - tmd_view = GetTitleContext().tmd.GetRawView(); + tmd_view = m_title_context.tmd.GetRawView(); } if (tmd_view.size() > request.io_vectors[0].size) @@ -352,10 +352,10 @@ IPCCommandResult ES::DIGetTicketView(const IOCtlVRequest& request) // Of course, this returns -1017 if no title is active and no ticket is passed. if (!has_ticket_vector) { - if (!GetTitleContext().active) + if (!m_title_context.active) return GetDefaultReply(ES_EINVAL); - view = GetTitleContext().ticket.GetRawTicketView(0); + view = m_title_context.ticket.GetRawTicketView(0); } else { @@ -375,10 +375,10 @@ IPCCommandResult ES::DIGetTMDSize(const IOCtlVRequest& request) if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != sizeof(u32)) return GetDefaultReply(ES_EINVAL); - if (!GetTitleContext().active) + if (!m_title_context.active) return GetDefaultReply(ES_EINVAL); - Memory::Write_U32(static_cast(GetTitleContext().tmd.GetBytes().size()), + Memory::Write_U32(static_cast(m_title_context.tmd.GetBytes().size()), request.io_vectors[0].address); return GetDefaultReply(IPC_SUCCESS); } @@ -392,10 +392,10 @@ IPCCommandResult ES::DIGetTMD(const IOCtlVRequest& request) if (tmd_size != request.io_vectors[0].size) return GetDefaultReply(ES_EINVAL); - if (!GetTitleContext().active) + if (!m_title_context.active) return GetDefaultReply(ES_EINVAL); - const std::vector& tmd_bytes = GetTitleContext().tmd.GetBytes(); + const std::vector& tmd_bytes = m_title_context.tmd.GetBytes(); if (static_cast(tmd_bytes.size()) > tmd_size) return GetDefaultReply(ES_EINVAL); diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index b17daba6ca..afd6105e7c 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -74,7 +74,7 @@ static Common::Event g_compressAndDumpStateSyncEvent; static std::thread g_save_thread; // Don't forget to increase this after doing changes on the savestate system -static const u32 STATE_VERSION = 90; // Last changed in PR 6077 +static const u32 STATE_VERSION = 91; // Last changed in PR 6094 // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list, From 689ed2a0ce95b743f73ae57cfb044cb4c100549f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 1 Oct 2017 16:45:18 +0200 Subject: [PATCH 08/18] [Cleanup] Move FindSignedTicket to IOS/ES For consistency and because NANDContentManager is going to be removed. --- Source/Core/Core/IOS/ES/ES.cpp | 2 +- Source/Core/Core/IOS/ES/ES.h | 1 + Source/Core/Core/IOS/ES/NandUtils.cpp | 14 ++++++++++++++ Source/Core/Core/IOS/ES/TitleManagement.cpp | 4 ++-- Source/Core/Core/IOS/ES/Views.cpp | 6 +++--- Source/Core/Core/IOS/WFS/WFSI.cpp | 2 +- Source/Core/Core/WiiUtils.cpp | 6 +++--- 7 files changed, 25 insertions(+), 10 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index 64fa54930e..eaefd60fef 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -684,7 +684,7 @@ ReturnCode ES::SetUpStreamKey(const u32 uid, const u8* ticket_view, const IOS::E // Find a signed ticket from the view. const u64 ticket_id = Common::swap64(&ticket_view[offsetof(IOS::ES::TicketView, ticket_id)]); const u64 title_id = Common::swap64(&ticket_view[offsetof(IOS::ES::TicketView, title_id)]); - const IOS::ES::TicketReader installed_ticket = DiscIO::FindSignedTicket(title_id); + const IOS::ES::TicketReader installed_ticket = FindSignedTicket(title_id); // Unlike the other "get ticket from view" function, this returns a FS error, not ES_NO_TICKET. if (!installed_ticket.IsValid()) return FS_ENOENT; diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index 41b3dbd559..e6287e6826 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -85,6 +85,7 @@ public: IOS::ES::TMDReader FindImportTMD(u64 title_id) const; IOS::ES::TMDReader FindInstalledTMD(u64 title_id) const; + IOS::ES::TicketReader FindSignedTicket(u64 title_id) const; // Get installed titles (in /title) without checking for TMDs at all. std::vector GetInstalledTitles() const; diff --git a/Source/Core/Core/IOS/ES/NandUtils.cpp b/Source/Core/Core/IOS/ES/NandUtils.cpp index b82d5daae4..a5afa0d571 100644 --- a/Source/Core/Core/IOS/ES/NandUtils.cpp +++ b/Source/Core/Core/IOS/ES/NandUtils.cpp @@ -50,6 +50,20 @@ IOS::ES::TMDReader ES::FindInstalledTMD(u64 title_id) const return FindTMD(title_id, Common::GetTMDFileName(title_id, Common::FROM_SESSION_ROOT)); } +IOS::ES::TicketReader ES::FindSignedTicket(u64 title_id) const +{ + const std::string path = Common::GetTicketFileName(title_id, Common::FROM_SESSION_ROOT); + File::IOFile ticket_file(path, "rb"); + if (!ticket_file) + return {}; + + std::vector signed_ticket(ticket_file.GetSize()); + if (!ticket_file.ReadBytes(signed_ticket.data(), signed_ticket.size())) + return {}; + + return IOS::ES::TicketReader{std::move(signed_ticket)}; +} + static bool IsValidPartOfTitleID(const std::string& string) { if (string.length() != 8) diff --git a/Source/Core/Core/IOS/ES/TitleManagement.cpp b/Source/Core/Core/IOS/ES/TitleManagement.cpp index d571465094..de2fad3bc8 100644 --- a/Source/Core/Core/IOS/ES/TitleManagement.cpp +++ b/Source/Core/Core/IOS/ES/TitleManagement.cpp @@ -220,7 +220,7 @@ ReturnCode ES::ImportTitleInit(Context& context, const std::vector& tmd_byte if (ret != IPC_SUCCESS) return ret; - const auto ticket = DiscIO::FindSignedTicket(context.title_import_export.tmd.GetTitleId()); + const auto ticket = FindSignedTicket(context.title_import_export.tmd.GetTitleId()); if (!ticket.IsValid()) return ES_NO_TICKET; @@ -528,7 +528,7 @@ ReturnCode ES::DeleteTicket(const u8* ticket_view) if (!CanDeleteTitle(title_id)) return ES_EINVAL; - auto ticket = DiscIO::FindSignedTicket(title_id); + auto ticket = FindSignedTicket(title_id); if (!ticket.IsValid()) return FS_ENOENT; diff --git a/Source/Core/Core/IOS/ES/Views.cpp b/Source/Core/Core/IOS/ES/Views.cpp index 08e0e1ed3b..8eb32ee326 100644 --- a/Source/Core/Core/IOS/ES/Views.cpp +++ b/Source/Core/Core/IOS/ES/Views.cpp @@ -49,7 +49,7 @@ IPCCommandResult ES::GetTicketViewCount(const IOCtlVRequest& request) u64 TitleID = Memory::Read_U64(request.in_vectors[0].address); - const IOS::ES::TicketReader ticket = DiscIO::FindSignedTicket(TitleID); + const IOS::ES::TicketReader ticket = FindSignedTicket(TitleID); u32 view_count = ticket.IsValid() ? static_cast(ticket.GetNumberOfTickets()) : 0; if (ShouldReturnFakeViewsForIOSes(TitleID, m_title_context)) @@ -73,7 +73,7 @@ IPCCommandResult ES::GetTicketViews(const IOCtlVRequest& request) u64 TitleID = Memory::Read_U64(request.in_vectors[0].address); u32 maxViews = Memory::Read_U32(request.in_vectors[1].address); - const IOS::ES::TicketReader ticket = DiscIO::FindSignedTicket(TitleID); + const IOS::ES::TicketReader ticket = FindSignedTicket(TitleID); if (ticket.IsValid()) { @@ -102,7 +102,7 @@ ReturnCode ES::GetV0TicketFromView(const u8* ticket_view, u8* ticket) const const u64 title_id = Common::swap64(&ticket_view[offsetof(IOS::ES::TicketView, title_id)]); const u64 ticket_id = Common::swap64(&ticket_view[offsetof(IOS::ES::TicketView, ticket_id)]); - const auto installed_ticket = DiscIO::FindSignedTicket(title_id); + const auto installed_ticket = FindSignedTicket(title_id); // TODO: when we get std::optional, check for presence instead of validity. // This is close enough, though. if (!installed_ticket.IsValid()) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index a0d8610bde..d296045c7a 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -157,7 +157,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) Memory::CopyFromEmu(tmd_bytes.data(), tmd_addr, tmd_size); m_tmd.SetBytes(std::move(tmd_bytes)); - IOS::ES::TicketReader ticket = DiscIO::FindSignedTicket(m_tmd.GetTitleId()); + IOS::ES::TicketReader ticket = m_ios.GetES()->FindSignedTicket(m_tmd.GetTitleId()); if (!ticket.IsValid()) { return_error_code = -11028; diff --git a/Source/Core/Core/WiiUtils.cpp b/Source/Core/Core/WiiUtils.cpp index 63f50a1ea2..f59164472f 100644 --- a/Source/Core/Core/WiiUtils.cpp +++ b/Source/Core/Core/WiiUtils.cpp @@ -670,7 +670,7 @@ UpdateResult DiscSystemUpdater::ProcessEntry(u32 type, std::bitset<32> attrs, return UpdateResult::AlreadyUpToDate; const IOS::ES::TMDReader tmd = m_ios.GetES()->FindInstalledTMD(title.id); - const IOS::ES::TicketReader ticket = DiscIO::FindSignedTicket(title.id); + const IOS::ES::TicketReader ticket = m_ios.GetES()->FindSignedTicket(title.id); // Optional titles can be skipped if the ticket is present, even when the title isn't installed. if (attrs.test(16) && ticket.IsValid()) @@ -735,7 +735,7 @@ NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios) } // Check for incomplete title installs (missing ticket, TMD or contents). - const auto ticket = DiscIO::FindSignedTicket(title_id); + const auto ticket = es->FindSignedTicket(title_id); if (!IOS::ES::IsDiscTitle(title_id) && !ticket.IsValid()) { ERROR_LOG(CORE, "CheckNAND: Missing ticket for title %016" PRIx64, title_id); @@ -801,7 +801,7 @@ bool RepairNAND(IOS::HLE::Kernel& ios) const auto content_files = File::ScanDirectoryTree(content_dir, false).children; const bool has_no_tmd_but_contents = !es->FindInstalledTMD(title_id).IsValid() && !content_files.empty(); - if (has_no_tmd_but_contents || !DiscIO::FindSignedTicket(title_id).IsValid()) + if (has_no_tmd_but_contents || !es->FindSignedTicket(title_id).IsValid()) { const std::string title_dir = Common::GetTitlePath(title_id, Common::FROM_CONFIGURED_ROOT); File::DeleteDirRecursively(title_dir); From 44fc6d878a6340ce58c280f4d6cfb738c1c3f1de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 1 Oct 2017 19:47:12 +0200 Subject: [PATCH 09/18] IOS/ES: Fix a missing check in ReadCertStore Without this, some operations can fail when trying to read an existing cert store, as it may not exist when signature checks are disabled. --- Source/Core/Core/IOS/ES/ES.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index eaefd60fef..2cb7ec62b4 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -791,6 +791,9 @@ bool ES::IsIssuerCorrect(VerifyContainerType type, const IOS::ES::CertReader& is ReturnCode ES::ReadCertStore(std::vector* buffer) const { + if (!SConfig::GetInstance().m_enable_signature_checks) + return IPC_SUCCESS; + const std::string store_path = Common::RootUserPath(Common::FROM_SESSION_ROOT) + "/sys/cert.sys"; File::IOFile store_file{store_path, "rb"}; if (!store_file) From a7e21bca13ccd5df7260c251a63c8124e435bcd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 1 Oct 2017 17:02:01 +0200 Subject: [PATCH 10/18] IOS/ES: Add a helper function to get a content path --- Source/Core/Core/IOS/ES/ES.h | 4 ++++ Source/Core/Core/IOS/ES/NandUtils.cpp | 24 ++++++++++++++---------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index e6287e6826..9695fd43c8 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -339,6 +339,10 @@ private: void FinishStaleImport(u64 title_id); void FinishAllStaleImports(); + std::string GetContentPath(u64 title_id, const IOS::ES::Content& content, + const IOS::ES::SharedContentMap& map = IOS::ES::SharedContentMap{ + Common::FROM_SESSION_ROOT}) const; + // TODO: remove these const DiscIO::NANDContentLoader& AccessContentDevice(u64 title_id); diff --git a/Source/Core/Core/IOS/ES/NandUtils.cpp b/Source/Core/Core/IOS/ES/NandUtils.cpp index a5afa0d571..06c6efdf29 100644 --- a/Source/Core/Core/IOS/ES/NandUtils.cpp +++ b/Source/Core/Core/IOS/ES/NandUtils.cpp @@ -168,21 +168,15 @@ std::vector ES::GetStoredContentsFromTMD(const IOS::ES::TMDRea if (!tmd.IsValid()) return {}; - const IOS::ES::SharedContentMap shared{Common::FROM_SESSION_ROOT}; + const IOS::ES::SharedContentMap map{Common::FROM_SESSION_ROOT}; const std::vector contents = tmd.GetContents(); std::vector stored_contents; std::copy_if(contents.begin(), contents.end(), std::back_inserter(stored_contents), - [&tmd, &shared](const auto& content) { - if (content.IsShared()) - { - const auto path = shared.GetFilenameFromSHA1(content.sha1); - return path && File::Exists(*path); - } - return File::Exists( - Common::GetTitleContentPath(tmd.GetTitleId(), Common::FROM_SESSION_ROOT) + - StringFromFormat("%08x.app", content.id)); + [this, &tmd, &map](const IOS::ES::Content& content) { + const std::string path = GetContentPath(tmd.GetTitleId(), content, map); + return !path.empty() && File::Exists(path); }); return stored_contents; @@ -303,6 +297,16 @@ void ES::FinishAllStaleImports() File::DeleteDirRecursively(import_dir); File::CreateDir(import_dir); } + +std::string ES::GetContentPath(const u64 title_id, const IOS::ES::Content& content, + const IOS::ES::SharedContentMap& content_map) const +{ + if (content.IsShared()) + return content_map.GetFilenameFromSHA1(content.sha1).value_or(""); + + return Common::GetTitleContentPath(title_id, Common::FROM_SESSION_ROOT) + + StringFromFormat("%08x.app", content.id); +} } // namespace Device } // namespace HLE } // namespace IOS From 63a52fa707211bcc8809ba450c3f98b63333fdff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 1 Oct 2017 17:06:16 +0200 Subject: [PATCH 11/18] [Cleanup] IOS/ES: Remove usages of NANDContentManager --- Source/Core/Core/IOS/ES/ES.cpp | 42 ++++++++++++++--------- Source/Core/Core/IOS/ES/ES.h | 5 ++- Source/Core/Core/IOS/ES/TitleContents.cpp | 42 +++++++---------------- Source/Core/Core/IOS/IOS.cpp | 15 +++----- Source/Core/Core/IOS/IOS.h | 7 +--- 5 files changed, 46 insertions(+), 65 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index 2cb7ec62b4..d12114c14c 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -251,8 +251,10 @@ bool ES::LaunchIOS(u64 ios_title_id) bool ES::LaunchPPCTitle(u64 title_id, bool skip_reload) { - const DiscIO::NANDContentLoader& content_loader = AccessContentDevice(title_id); - if (!content_loader.IsValid()) + const IOS::ES::TMDReader tmd = FindInstalledTMD(title_id); + const IOS::ES::TicketReader ticket = FindSignedTicket(title_id); + + if (!tmd.IsValid() || !ticket.IsValid()) { if (title_id == Titles::SYSTEM_MENU) { @@ -268,22 +270,18 @@ bool ES::LaunchPPCTitle(u64 title_id, bool skip_reload) return false; } - if (!content_loader.GetTMD().IsValid() || !content_loader.GetTicket().IsValid()) - return false; - // Before launching a title, IOS first reads the TMD and reloads into the specified IOS version, // even when that version is already running. After it has reloaded, ES_Launch will be called // again with the reload skipped, and the PPC will be bootstrapped then. if (!skip_reload) { s_title_to_launch = title_id; - const u64 required_ios = content_loader.GetTMD().GetIOSId(); + const u64 required_ios = tmd.GetIOSId(); return LaunchTitle(required_ios); } - m_title_context.Update(content_loader.GetTMD(), content_loader.GetTicket()); - INFO_LOG(IOS_ES, "LaunchPPCTitle: Title context changed: %016" PRIx64, - m_title_context.tmd.GetTitleId()); + m_title_context.Update(tmd, ticket); + INFO_LOG(IOS_ES, "LaunchPPCTitle: Title context changed: %016" PRIx64, tmd.GetTitleId()); // Note: the UID/GID is also updated for IOS titles, but since we have no guarantee IOS titles // are installed, we can only do this for PPC titles. @@ -294,7 +292,11 @@ bool ES::LaunchPPCTitle(u64 title_id, bool skip_reload) return false; } - return m_ios.BootstrapPPC(content_loader); + IOS::ES::Content content; + if (!tmd.GetContent(tmd.GetBootIndex(), &content)) + return false; + + return m_ios.BootstrapPPC(GetContentPath(tmd.GetTitleId(), content)); } void ES::Context::DoState(PointerWrap& p) @@ -310,7 +312,20 @@ void ES::Context::DoState(PointerWrap& p) void ES::DoState(PointerWrap& p) { Device::DoState(p); - p.Do(m_content_table); + + for (auto& entry : m_content_table) + { + p.Do(entry.m_opened); + p.Do(entry.m_title_id); + p.Do(entry.m_content); + p.Do(entry.m_position); + p.Do(entry.m_uid); + if (entry.m_opened) + entry.m_opened = entry.m_file.Open(GetContentPath(entry.m_title_id, entry.m_content), "rb"); + else + entry.m_file.Close(); + } + m_title_context.DoState(p); for (auto& context : m_contexts) @@ -573,11 +588,6 @@ IPCCommandResult ES::LaunchBC(const IOCtlVRequest& request) return GetNoReply(); } -const DiscIO::NANDContentLoader& ES::AccessContentDevice(u64 title_id) -{ - return DiscIO::NANDContentManager::Access().GetNANDLoader(title_id, Common::FROM_SESSION_ROOT); -} - // This is technically an ioctlv in IOS's ES, but it is an internal API which cannot be // used from the PowerPC (for unpatched and up-to-date IOSes anyway). // So we block access to it from the IPC interface. diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index 9695fd43c8..433a9bad0f 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -10,6 +10,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/File.h" #include "Core/IOS/Device.h" #include "Core/IOS/ES/Formats.h" #include "Core/IOS/IOS.h" @@ -343,13 +344,11 @@ private: const IOS::ES::SharedContentMap& map = IOS::ES::SharedContentMap{ Common::FROM_SESSION_ROOT}) const; - // TODO: remove these - const DiscIO::NANDContentLoader& AccessContentDevice(u64 title_id); - // TODO: reuse the FS code. struct OpenedContent { bool m_opened = false; + File::IOFile m_file; u64 m_title_id = 0; IOS::ES::Content m_content; u32 m_position = 0; diff --git a/Source/Core/Core/IOS/ES/TitleContents.cpp b/Source/Core/Core/IOS/ES/TitleContents.cpp index 46b6477c0e..28c93b0215 100644 --- a/Source/Core/Core/IOS/ES/TitleContents.cpp +++ b/Source/Core/Core/IOS/ES/TitleContents.cpp @@ -23,14 +23,10 @@ namespace Device s32 ES::OpenContent(const IOS::ES::TMDReader& tmd, u16 content_index, u32 uid) { const u64 title_id = tmd.GetTitleId(); - const DiscIO::NANDContentLoader& loader = AccessContentDevice(title_id); - if (!loader.IsValid()) - return FS_ENOENT; - - const DiscIO::NANDContent* content = loader.GetContentByIndex(content_index); - if (!content) - return FS_ENOENT; + IOS::ES::Content content; + if (!tmd.GetContent(content_index, &content)) + return ES_EINVAL; for (size_t i = 0; i < m_content_table.size(); ++i) { @@ -38,9 +34,12 @@ s32 ES::OpenContent(const IOS::ES::TMDReader& tmd, u16 content_index, u32 uid) if (entry.m_opened) continue; + if (!entry.m_file.Open(GetContentPath(title_id, content), "rb")) + return FS_ENOENT; + entry.m_opened = true; entry.m_position = 0; - entry.m_content = content->m_metadata; + entry.m_content = content; entry.m_title_id = title_id; entry.m_uid = uid; INFO_LOG(IOS_ES, "OpenContent: title ID %016" PRIx64 ", UID 0x%x, CFD %zu", title_id, uid, i); @@ -102,20 +101,14 @@ s32 ES::ReadContent(u32 cfd, u8* buffer, u32 size, u32 uid) // XXX: make this reuse the FS code... ES just does a simple "IOS_Read" call here // instead of all this duplicated filesystem logic. - if (entry.m_position + size > entry.m_content.size) - size = static_cast(entry.m_content.size) - entry.m_position; + if (entry.m_position + size > entry.m_file.GetSize()) + size = static_cast(entry.m_file.GetSize()) - entry.m_position; - const DiscIO::NANDContentLoader& ContentLoader = AccessContentDevice(entry.m_title_id); - // ContentLoader should never be invalid; rContent has been created by it. - if (ContentLoader.IsValid() && ContentLoader.GetTicket().IsValid()) + entry.m_file.Seek(entry.m_position, SEEK_SET); + if (!entry.m_file.ReadBytes(buffer, size)) { - const DiscIO::NANDContent* pContent = ContentLoader.GetContentByIndex(entry.m_content.index); - pContent->m_Data->Open(); - if (!pContent->m_Data->GetRange(entry.m_position, size, buffer)) - { - ERROR_LOG(IOS_ES, "ES: failed to read %u bytes from %u!", size, entry.m_position); - return ES_SHORT_READ; - } + ERROR_LOG(IOS_ES, "ES: failed to read %u bytes from %u!", size, entry.m_position); + return ES_SHORT_READ; } entry.m_position += size; @@ -145,15 +138,6 @@ ReturnCode ES::CloseContent(u32 cfd, u32 uid) if (!entry.m_opened) return IPC_EINVAL; - // XXX: again, this should be a simple IOS_Close. - const DiscIO::NANDContentLoader& ContentLoader = AccessContentDevice(entry.m_title_id); - // ContentLoader should never be invalid; we shouldn't be here if ES_OPENCONTENT failed before. - if (ContentLoader.IsValid()) - { - const DiscIO::NANDContent* content = ContentLoader.GetContentByIndex(entry.m_content.index); - content->m_Data->Close(); - } - entry = {}; INFO_LOG(IOS_ES, "CloseContent: CFD %u", cfd); return IPC_SUCCESS; diff --git a/Source/Core/Core/IOS/IOS.cpp b/Source/Core/Core/IOS/IOS.cpp index 3d372c7688..073323d347 100644 --- a/Source/Core/Core/IOS/IOS.cpp +++ b/Source/Core/Core/IOS/IOS.cpp @@ -54,7 +54,6 @@ #include "Core/IOS/WFS/WFSSRV.h" #include "Core/PowerPC/PowerPC.h" #include "Core/WiiRoot.h" -#include "DiscIO/NANDContentLoader.h" namespace IOS { @@ -275,23 +274,17 @@ u16 Kernel::GetGidForPPC() const // This corresponds to syscall 0x41, which loads a binary from the NAND and bootstraps the PPC. // Unlike 0x42, IOS will set up some constants in memory before booting the PPC. -bool Kernel::BootstrapPPC(const DiscIO::NANDContentLoader& content_loader) +bool Kernel::BootstrapPPC(const std::string& boot_content_path) { - if (!content_loader.IsValid()) - return false; + const DolReader dol{boot_content_path}; - const auto* content = content_loader.GetContentByIndex(content_loader.GetTMD().GetBootIndex()); - if (!content) - return false; - - const auto dol_loader = std::make_unique(content->m_Data->Get()); - if (!dol_loader->IsValid()) + if (!dol.IsValid()) return false; if (!SetupMemory(m_title_id, MemorySetupType::Full)) return false; - if (!dol_loader->LoadIntoMemory()) + if (!dol.LoadIntoMemory()) return false; // NAND titles start with address translation off at 0x3400 (via the PPC bootstub) diff --git a/Source/Core/Core/IOS/IOS.h b/Source/Core/Core/IOS/IOS.h index aaf6b18671..73f17cbe7a 100644 --- a/Source/Core/Core/IOS/IOS.h +++ b/Source/Core/Core/IOS/IOS.h @@ -19,11 +19,6 @@ class PointerWrap; -namespace DiscIO -{ -class NANDContentLoader; -} - namespace IOS { namespace HLE @@ -113,7 +108,7 @@ public: void SetGidForPPC(u16 gid); u16 GetGidForPPC() const; - bool BootstrapPPC(const DiscIO::NANDContentLoader& content_loader); + bool BootstrapPPC(const std::string& boot_content_path); bool BootIOS(u64 ios_title_id); u32 GetVersion() const; From ff6b3eb9acd25104a3b788910fae1971fabe0427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 1 Oct 2017 17:54:01 +0200 Subject: [PATCH 12/18] [Cleanup] IOS: Clean up the way ARM binaries are loaded This commit removes the last usage of NANDContentManager in IOS code. Another cleanup change is that loading ARM (IOS) binaries is now done by the kernel in the BootIOS syscall, instead of being handled as a special case in the MIOS code. This is more similar to how console works and lets us easily extend the same logic to other IOS binaries in the future, if we decide to actually load them. --- Source/Core/Core/IOS/ES/ES.cpp | 33 +++++++++++++ Source/Core/Core/IOS/IOS.cpp | 62 ++++++++++++++++++----- Source/Core/Core/IOS/IOS.h | 2 +- Source/Core/Core/IOS/MIOS.cpp | 89 ---------------------------------- 4 files changed, 84 insertions(+), 102 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index d12114c14c..eb2ba6222e 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -246,6 +246,39 @@ bool ES::LaunchTitle(u64 title_id, bool skip_reload) bool ES::LaunchIOS(u64 ios_title_id) { + // A real Wii goes through several steps before getting to MIOS. + // + // * The System Menu detects a GameCube disc and launches BC (1-100) instead of the game. + // * BC (similar to boot1) lowers the clock speed to the Flipper's and then launches boot2. + // * boot2 sees the lowered clock speed and launches MIOS (1-101) instead of the System Menu. + // + // Because we don't have boot1 and boot2, and BC is only ever used to launch MIOS + // (indirectly via boot2), we can just launch MIOS when BC is launched. + if (ios_title_id == Titles::BC) + { + NOTICE_LOG(IOS, "BC: Launching MIOS..."); + return LaunchIOS(Titles::MIOS); + } + + // IOS checks whether the system title is installed and returns an error if it isn't. + // Unfortunately, we can't rely on titles being installed as we don't require system titles, + // so only have this check for MIOS (for which having the binary is *required*). + if (ios_title_id == Titles::MIOS) + { + const IOS::ES::TMDReader tmd = FindInstalledTMD(ios_title_id); + const IOS::ES::TicketReader ticket = FindSignedTicket(ios_title_id); + IOS::ES::Content content; + if (!tmd.IsValid() || !ticket.IsValid() || !tmd.GetContent(tmd.GetBootIndex(), &content) || + !m_ios.BootIOS(ios_title_id, GetContentPath(ios_title_id, content))) + { + PanicAlertT("Could not launch IOS %016" PRIx64 " because it is missing from the NAND.\n" + "The emulated software will likely hang now.", + ios_title_id); + return false; + } + return true; + } + return m_ios.BootIOS(ios_title_id); } diff --git a/Source/Core/Core/IOS/IOS.cpp b/Source/Core/Core/IOS/IOS.cpp index 073323d347..667e92e490 100644 --- a/Source/Core/Core/IOS/IOS.cpp +++ b/Source/Core/Core/IOS/IOS.cpp @@ -19,6 +19,7 @@ #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "Core/Boot/DolReader.h" +#include "Core/Boot/ElfReader.h" #include "Core/CommonTitles.h" #include "Core/ConfigManager.h" #include "Core/Core.h" @@ -296,23 +297,60 @@ bool Kernel::BootstrapPPC(const std::string& boot_content_path) return true; } +struct ARMBinary final +{ + explicit ARMBinary(std::vector&& bytes) : m_bytes(std::move(bytes)) {} + bool IsValid() const + { + // The header is at least 0x10. + if (m_bytes.size() < 0x10) + return false; + return m_bytes.size() >= (GetHeaderSize() + GetElfOffset() + GetElfSize()); + } + + std::vector GetElf() const + { + const auto iterator = m_bytes.cbegin() + GetHeaderSize() + GetElfOffset(); + return std::vector(iterator, iterator + GetElfSize()); + } + + u32 GetHeaderSize() const { return Common::swap32(m_bytes.data()); } + u32 GetElfOffset() const { return Common::swap32(m_bytes.data() + 0x4); } + u32 GetElfSize() const { return Common::swap32(m_bytes.data() + 0x8); } +private: + std::vector m_bytes; +}; + // Similar to syscall 0x42 (ios_boot); this is used to change the current active IOS. // IOS writes the new version to 0x3140 before restarting, but it does *not* poke any // of the other constants to the memory. Warning: this resets the kernel instance. -bool Kernel::BootIOS(const u64 ios_title_id) +// +// Passing a boot content path is optional because we do not require IOSes +// to be installed at the moment. If one is passed, the boot binary must exist +// on the NAND, or the call will fail like on a Wii. +bool Kernel::BootIOS(const u64 ios_title_id, const std::string& boot_content_path) { - // A real Wii goes through several steps before getting to MIOS. - // - // * The System Menu detects a GameCube disc and launches BC (1-100) instead of the game. - // * BC (similar to boot1) lowers the clock speed to the Flipper's and then launches boot2. - // * boot2 sees the lowered clock speed and launches MIOS (1-101) instead of the System Menu. - // - // Because we currently don't have boot1 and boot2, and BC is only ever used to launch MIOS - // (indirectly via boot2), we can just launch MIOS when BC is launched. - if (ios_title_id == Titles::BC) + if (!boot_content_path.empty()) { - NOTICE_LOG(IOS, "BC: Launching MIOS..."); - return BootIOS(Titles::MIOS); + // Load the ARM binary to memory (if possible). + // Because we do not actually emulate the Starlet, only load the sections that are in MEM1. + + File::IOFile file{boot_content_path, "rb"}; + // TODO: should return IPC_ERROR_MAX. + if (file.GetSize() > 0xB00000) + return false; + + std::vector data(file.GetSize()); + if (!file.ReadBytes(data.data(), data.size())) + return false; + + ARMBinary binary{std::move(data)}; + if (!binary.IsValid()) + return false; + + ElfReader elf{binary.GetElf()}; + if (!elf.LoadIntoMemory(true)) + return false; } // Shut down the active IOS first before switching to the new one. diff --git a/Source/Core/Core/IOS/IOS.h b/Source/Core/Core/IOS/IOS.h index 73f17cbe7a..9280412698 100644 --- a/Source/Core/Core/IOS/IOS.h +++ b/Source/Core/Core/IOS/IOS.h @@ -109,7 +109,7 @@ public: u16 GetGidForPPC() const; bool BootstrapPPC(const std::string& boot_content_path); - bool BootIOS(u64 ios_title_id); + bool BootIOS(u64 ios_title_id, const std::string& boot_content_path = ""); u32 GetVersion() const; IOSC& GetIOSC(); diff --git a/Source/Core/Core/IOS/MIOS.cpp b/Source/Core/Core/IOS/MIOS.cpp index fc0e70541a..2f0f02a422 100644 --- a/Source/Core/Core/IOS/MIOS.cpp +++ b/Source/Core/Core/IOS/MIOS.cpp @@ -6,16 +6,12 @@ #include #include -#include #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Common/MsgHandler.h" -#include "Common/NandPaths.h" #include "Common/Swap.h" -#include "Core/Boot/ElfReader.h" -#include "Core/CommonTitles.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/DSPEmulator.h" @@ -24,10 +20,8 @@ #include "Core/HW/DVD/DVDInterface.h" #include "Core/HW/Memmap.h" #include "Core/HW/SystemTimers.h" -#include "Core/IOS/ES/Formats.h" #include "Core/PowerPC/PPCSymbolDB.h" #include "Core/PowerPC/PowerPC.h" -#include "DiscIO/NANDContentLoader.h" namespace IOS { @@ -35,73 +29,6 @@ namespace HLE { namespace MIOS { -// Source: https://wiibrew.org/wiki/ARM_Binaries -struct ARMBinary final -{ - explicit ARMBinary(const std::vector& bytes); - explicit ARMBinary(std::vector&& bytes); - - bool IsValid() const; - std::vector GetElf() const; - u32 GetHeaderSize() const; - u32 GetElfOffset() const; - u32 GetElfSize() const; - -private: - std::vector m_bytes; -}; - -ARMBinary::ARMBinary(const std::vector& bytes) : m_bytes(bytes) -{ -} - -ARMBinary::ARMBinary(std::vector&& bytes) : m_bytes(std::move(bytes)) -{ -} - -bool ARMBinary::IsValid() const -{ - // The header is at least 0x10. - if (m_bytes.size() < 0x10) - return false; - return m_bytes.size() >= (GetHeaderSize() + GetElfOffset() + GetElfSize()); -} - -std::vector ARMBinary::GetElf() const -{ - const auto iterator = m_bytes.cbegin() + GetHeaderSize() + GetElfOffset(); - return std::vector(iterator, iterator + GetElfSize()); -} - -u32 ARMBinary::GetHeaderSize() const -{ - return Common::swap32(m_bytes.data()); -} - -u32 ARMBinary::GetElfOffset() const -{ - return Common::swap32(m_bytes.data() + 0x4); -} - -u32 ARMBinary::GetElfSize() const -{ - return Common::swap32(m_bytes.data() + 0x8); -} - -static std::vector GetMIOSBinary() -{ - const auto& loader = - DiscIO::NANDContentManager::Access().GetNANDLoader(Titles::MIOS, Common::FROM_SESSION_ROOT); - if (!loader.IsValid()) - return {}; - - const auto* content = loader.GetContentByIndex(loader.GetTMD().GetBootIndex()); - if (!content) - return {}; - - return content->m_Data->Get(); -} - static void ReinitHardware() { SConfig::GetInstance().bWii = false; @@ -125,22 +52,6 @@ bool Load() Memory::Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE); Memory::Write_U32(0x09142001, 0x3180); - ARMBinary mios{GetMIOSBinary()}; - if (!mios.IsValid()) - { - PanicAlertT("Failed to load MIOS. It is required for launching GameCube titles from Wii mode."); - Core::QueueHostJob(Core::Stop); - return false; - } - - ElfReader elf{mios.GetElf()}; - if (!elf.LoadIntoMemory(true)) - { - PanicAlertT("Failed to load MIOS ELF into memory."); - Core::QueueHostJob(Core::Stop); - return false; - } - ReinitHardware(); NOTICE_LOG(IOS, "Reinitialised hardware."); From c03aa78c8f36184cae48e8fa0ac56e7c76d88d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 1 Oct 2017 18:31:19 +0200 Subject: [PATCH 13/18] [Cleanup] WX: Remove usage of NANDContentManager Also clean up the way the system menu label is updated. We don't want to access the NAND while emulation is running, and especially not that many times per second on an unpredictable timing. --- Source/Core/DolphinWX/Frame.cpp | 1 - Source/Core/DolphinWX/Frame.h | 3 -- Source/Core/DolphinWX/FrameTools.cpp | 22 +++++--------- Source/Core/DolphinWX/MainMenuBar.cpp | 41 ++++++++++++++++++--------- Source/Core/DolphinWX/MainMenuBar.h | 1 + 5 files changed, 36 insertions(+), 32 deletions(-) diff --git a/Source/Core/DolphinWX/Frame.cpp b/Source/Core/DolphinWX/Frame.cpp index c4f9cd7dd1..6a1c3a0c53 100644 --- a/Source/Core/DolphinWX/Frame.cpp +++ b/Source/Core/DolphinWX/Frame.cpp @@ -501,7 +501,6 @@ void CFrame::BindEvents() Bind(DOLPHIN_EVT_RELOAD_THEME_BITMAPS, &CFrame::OnReloadThemeBitmaps, this); Bind(DOLPHIN_EVT_REFRESH_GAMELIST, &CFrame::OnRefreshGameList, this); Bind(DOLPHIN_EVT_RESCAN_GAMELIST, &CFrame::OnRescanGameList, this); - Bind(DOLPHIN_EVT_UPDATE_LOAD_WII_MENU_ITEM, &CFrame::OnUpdateLoadWiiMenuItem, this); Bind(DOLPHIN_EVT_BOOT_SOFTWARE, &CFrame::OnPlay, this); Bind(DOLPHIN_EVT_STOP_SOFTWARE, &CFrame::OnStop, this); } diff --git a/Source/Core/DolphinWX/Frame.h b/Source/Core/DolphinWX/Frame.h index 24cb56a94b..30f86ae6dc 100644 --- a/Source/Core/DolphinWX/Frame.h +++ b/Source/Core/DolphinWX/Frame.h @@ -275,9 +275,6 @@ private: void OnUpdateInterpreterMenuItem(wxUpdateUIEvent& event); - void OnUpdateLoadWiiMenuItem(wxCommandEvent&); - void UpdateLoadWiiMenuItem() const; - void OnOpen(wxCommandEvent& event); // File menu void OnRefresh(wxCommandEvent& event); void OnBootDrive(wxCommandEvent& event); diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index 7ec4cb0da1..7cd566b80e 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -652,6 +652,7 @@ void CFrame::StartGame(std::unique_ptr boot) if (m_is_game_loading) return; m_is_game_loading = true; + wxPostEvent(GetMenuBar(), wxCommandEvent{DOLPHIN_EVT_UPDATE_LOAD_WII_MENU_ITEM}); GetToolBar()->EnableTool(IDM_PLAY, false); GetMenuBar()->FindItem(IDM_PLAY)->Enable(false); @@ -925,6 +926,7 @@ void CFrame::OnStopped() m_confirm_stop = false; m_is_game_loading = false; m_tried_graceful_shutdown = false; + wxPostEvent(GetMenuBar(), wxCommandEvent{DOLPHIN_EVT_UPDATE_LOAD_WII_MENU_ITEM}); UninhibitScreensaver(); @@ -1131,11 +1133,6 @@ void CFrame::OnUpdateInterpreterMenuItem(wxUpdateUIEvent& event) event.Check(SConfig::GetInstance().iCPUCore == PowerPC::CORE_INTERPRETER); } -void CFrame::OnUpdateLoadWiiMenuItem(wxCommandEvent& WXUNUSED(event)) -{ - UpdateLoadWiiMenuItem(); -} - void CFrame::ClearStatusBar() { if (this->GetStatusBar()->IsEnabled()) @@ -1260,7 +1257,7 @@ void CFrame::OnInstallWAD(wxCommandEvent& event) wxPD_REMAINING_TIME | wxPD_SMOOTH); if (WiiUtils::InstallWAD(fileName)) - UpdateLoadWiiMenuItem(); + wxPostEvent(GetMenuBar(), wxCommandEvent{DOLPHIN_EVT_UPDATE_LOAD_WII_MENU_ITEM}); } void CFrame::OnUninstallWAD(wxCommandEvent&) @@ -1284,7 +1281,7 @@ void CFrame::OnUninstallWAD(wxCommandEvent&) } if (title_id == Titles::SYSTEM_MENU) - UpdateLoadWiiMenuItem(); + wxPostEvent(GetMenuBar(), wxCommandEvent{DOLPHIN_EVT_UPDATE_LOAD_WII_MENU_ITEM}); } void CFrame::OnImportBootMiiBackup(wxCommandEvent& WXUNUSED(event)) @@ -1306,7 +1303,7 @@ void CFrame::OnImportBootMiiBackup(wxCommandEvent& WXUNUSED(event)) wxProgressDialog dialog(_("Importing NAND backup"), _("Working..."), 100, this, wxPD_APP_MODAL | wxPD_ELAPSED_TIME | wxPD_SMOOTH); DiscIO::NANDImporter().ImportNANDBin(file_name, [&dialog] { dialog.Pulse(); }); - UpdateLoadWiiMenuItem(); + wxPostEvent(GetMenuBar(), wxCommandEvent{DOLPHIN_EVT_UPDATE_LOAD_WII_MENU_ITEM}); } void CFrame::OnCheckNAND(wxCommandEvent&) @@ -1462,7 +1459,7 @@ void CFrame::OnPerformOnlineWiiUpdate(wxCommandEvent& event) const WiiUtils::UpdateResult result = ShowUpdateProgress(this, WiiUtils::DoOnlineUpdate, region); ShowUpdateResult(result); - UpdateLoadWiiMenuItem(); + wxPostEvent(GetMenuBar(), wxCommandEvent{DOLPHIN_EVT_UPDATE_LOAD_WII_MENU_ITEM}); } void CFrame::OnPerformDiscWiiUpdate(wxCommandEvent&) @@ -1475,12 +1472,7 @@ void CFrame::OnPerformDiscWiiUpdate(wxCommandEvent&) const WiiUtils::UpdateResult result = ShowUpdateProgress(this, WiiUtils::DoDiscUpdate, file_name); ShowUpdateResult(result); - UpdateLoadWiiMenuItem(); -} - -void CFrame::UpdateLoadWiiMenuItem() const -{ - GetMenuBar()->Refresh(true, nullptr); + wxPostEvent(GetMenuBar(), wxCommandEvent{DOLPHIN_EVT_UPDATE_LOAD_WII_MENU_ITEM}); } void CFrame::OnFifoPlayer(wxCommandEvent& WXUNUSED(event)) diff --git a/Source/Core/DolphinWX/MainMenuBar.cpp b/Source/Core/DolphinWX/MainMenuBar.cpp index fdb6b633c6..18eb27002c 100644 --- a/Source/Core/DolphinWX/MainMenuBar.cpp +++ b/Source/Core/DolphinWX/MainMenuBar.cpp @@ -11,10 +11,12 @@ #include "Core/CommonTitles.h" #include "Core/ConfigManager.h" #include "Core/Core.h" +#include "Core/IOS/ES/ES.h" +#include "Core/IOS/ES/Formats.h" #include "Core/PowerPC/PowerPC.h" #include "Core/State.h" #include "DiscIO/Enums.h" -#include "DiscIO/NANDContentLoader.h" +#include "DolphinWX/Frame.h" #include "DolphinWX/Globals.h" #include "DolphinWX/WxUtils.h" @@ -30,6 +32,7 @@ MainMenuBar::MainMenuBar(MenuType type, long style) : wxMenuBar{style}, m_type{t { BindEvents(); AddMenus(); + RefreshWiiSystemMenuLabel(); } void MainMenuBar::Refresh(bool erase_background, const wxRect* rect) @@ -62,6 +65,7 @@ void MainMenuBar::AddMenus() void MainMenuBar::BindEvents() { Bind(EVT_POPULATE_PERSPECTIVES_MENU, &MainMenuBar::OnPopulatePerspectivesMenu, this); + Bind(DOLPHIN_EVT_UPDATE_LOAD_WII_MENU_ITEM, &MainMenuBar::OnUpdateWiiMenuTool, this); } wxMenu* MainMenuBar::CreateFileMenu() const @@ -582,16 +586,11 @@ void MainMenuBar::RefreshWiiToolsLabels() const // result in the emulated software being confused, or even worse, exported saves having // inconsistent data. const bool enable_wii_tools = !Core::IsRunning() || !SConfig::GetInstance().bWii; - for (const int index : - {IDM_MENU_INSTALL_WAD, IDM_EXPORT_ALL_SAVE, IDM_IMPORT_SAVE, IDM_IMPORT_NAND, IDM_CHECK_NAND, - IDM_EXTRACT_CERTIFICATES, IDM_LOAD_WII_MENU, IDM_PERFORM_ONLINE_UPDATE_CURRENT, - IDM_PERFORM_ONLINE_UPDATE_EUR, IDM_PERFORM_ONLINE_UPDATE_JPN, IDM_PERFORM_ONLINE_UPDATE_KOR, - IDM_PERFORM_ONLINE_UPDATE_USA}) + for (const int index : {IDM_MENU_INSTALL_WAD, IDM_EXPORT_ALL_SAVE, IDM_IMPORT_SAVE, + IDM_IMPORT_NAND, IDM_CHECK_NAND, IDM_EXTRACT_CERTIFICATES}) { FindItem(index)->Enable(enable_wii_tools); } - if (enable_wii_tools) - RefreshWiiSystemMenuLabel(); } void MainMenuBar::EnableUpdateMenu(UpdateMenuMode mode) const @@ -608,12 +607,23 @@ void MainMenuBar::RefreshWiiSystemMenuLabel() const { auto* const item = FindItem(IDM_LOAD_WII_MENU); - const auto& sys_menu_loader = DiscIO::NANDContentManager::Access().GetNANDLoader( - Titles::SYSTEM_MENU, Common::FROM_CONFIGURED_ROOT); - - if (sys_menu_loader.IsValid()) + if (Core::IsRunning()) { - const u16 version_number = sys_menu_loader.GetTMD().GetTitleVersion(); + item->Enable(false); + for (const int idm : {IDM_PERFORM_ONLINE_UPDATE_CURRENT, IDM_PERFORM_ONLINE_UPDATE_EUR, + IDM_PERFORM_ONLINE_UPDATE_JPN, IDM_PERFORM_ONLINE_UPDATE_KOR, + IDM_PERFORM_ONLINE_UPDATE_USA}) + { + FindItem(idm)->Enable(false); + } + return; + } + + IOS::HLE::Kernel ios; + const IOS::ES::TMDReader sys_menu_tmd = ios.GetES()->FindInstalledTMD(Titles::SYSTEM_MENU); + if (sys_menu_tmd.IsValid()) + { + const u16 version_number = sys_menu_tmd.GetTitleVersion(); const wxString version_string = StrToWxStr(DiscIO::GetSysMenuVersionString(version_number)); item->Enable(); item->SetItemLabel(wxString::Format(_("Load Wii System Menu %s"), version_string)); @@ -627,6 +637,11 @@ void MainMenuBar::RefreshWiiSystemMenuLabel() const } } +void MainMenuBar::OnUpdateWiiMenuTool(wxCommandEvent&) +{ + RefreshWiiSystemMenuLabel(); +} + void MainMenuBar::ClearSavedPerspectivesMenu() const { while (m_saved_perspectives_menu->GetMenuItemCount() != 0) diff --git a/Source/Core/DolphinWX/MainMenuBar.h b/Source/Core/DolphinWX/MainMenuBar.h index d7e3d692dc..ab786c637f 100644 --- a/Source/Core/DolphinWX/MainMenuBar.h +++ b/Source/Core/DolphinWX/MainMenuBar.h @@ -42,6 +42,7 @@ private: wxMenu* CreateHelpMenu() const; void OnPopulatePerspectivesMenu(PopulatePerspectivesEvent&); + void OnUpdateWiiMenuTool(wxCommandEvent&); void RefreshMenuLabels() const; void RefreshPlayMenuLabel() const; From 346ca009f955bdb11a528732ad8ac01074d07d63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 1 Oct 2017 18:48:50 +0200 Subject: [PATCH 14/18] Remove NANDContentManager --- Source/Core/Core/Boot/Boot.cpp | 1 - Source/Core/Core/Boot/Boot_WiiWAD.cpp | 1 - Source/Core/Core/ConfigManager.cpp | 1 - Source/Core/Core/IOS/ES/ES.cpp | 11 - Source/Core/Core/IOS/ES/ES.h | 5 - Source/Core/Core/IOS/ES/TitleContents.cpp | 1 - Source/Core/Core/IOS/ES/TitleManagement.cpp | 3 - Source/Core/Core/IOS/ES/Views.cpp | 1 - Source/Core/Core/IOS/WFS/WFSI.cpp | 1 - Source/Core/Core/WiiUtils.cpp | 14 +- Source/Core/DiscIO/CMakeLists.txt | 1 - Source/Core/DiscIO/DiscIO.vcxproj | 2 - Source/Core/DiscIO/DiscIO.vcxproj.filters | 6 - Source/Core/DiscIO/NANDContentLoader.cpp | 268 ------------------ Source/Core/DiscIO/NANDContentLoader.h | 126 -------- Source/Core/DiscIO/NANDImporter.cpp | 4 - Source/Core/DiscIO/VolumeWad.h | 4 - Source/Core/DolphinQt2/GameList/GameFile.cpp | 1 - .../Core/DolphinWX/Config/PathConfigPane.cpp | 3 - Source/Core/DolphinWX/FrameTools.cpp | 1 - 20 files changed, 3 insertions(+), 452 deletions(-) delete mode 100644 Source/Core/DiscIO/NANDContentLoader.cpp delete mode 100644 Source/Core/DiscIO/NANDContentLoader.h diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 9d12c2188d..5d4bf93c7a 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -46,7 +46,6 @@ #include "Core/PowerPC/PowerPC.h" #include "DiscIO/Enums.h" -#include "DiscIO/NANDContentLoader.h" #include "DiscIO/Volume.h" BootParameters::BootParameters(Parameters&& parameters_) : parameters(std::move(parameters_)) diff --git a/Source/Core/Core/Boot/Boot_WiiWAD.cpp b/Source/Core/Core/Boot/Boot_WiiWAD.cpp index 1aa8193fff..58af4ae961 100644 --- a/Source/Core/Core/Boot/Boot_WiiWAD.cpp +++ b/Source/Core/Core/Boot/Boot_WiiWAD.cpp @@ -20,7 +20,6 @@ #include "Core/IOS/IOS.h" #include "Core/WiiUtils.h" -#include "DiscIO/NANDContentLoader.h" #include "DiscIO/WiiWad.h" bool CBoot::BootNANDTitle(const u64 title_id) diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 5c074768d0..826e17da42 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -43,7 +43,6 @@ #include "VideoCommon/HiresTextures.h" #include "DiscIO/Enums.h" -#include "DiscIO/NANDContentLoader.h" #include "DiscIO/Volume.h" #include "DiscIO/WiiWad.h" diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index eb2ba6222e..1250651024 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -27,7 +27,6 @@ #include "Core/IOS/ES/Formats.h" #include "Core/IOS/IOSC.h" #include "Core/ec_wii.h" -#include "DiscIO/NANDContentLoader.h" namespace IOS { @@ -218,11 +217,6 @@ bool ES::LaunchTitle(u64 title_id, bool skip_reload) NOTICE_LOG(IOS_ES, "Launching title %016" PRIx64 "...", title_id); - // ES_Launch should probably reset the whole state, which at least means closing all open files. - // leaving them open through ES_Launch may cause hangs and other funky behavior - // (supposedly when trying to re-open those files). - DiscIO::NANDContentManager::Access().ClearCache(); - u32 device_id; if (title_id == Titles::SHOP && (GetDeviceId(&device_id) != IPC_SUCCESS || device_id == DEFAULT_WII_DEVICE_ID)) @@ -401,8 +395,6 @@ ReturnCode ES::Close(u32 fd) INFO_LOG(IOS_ES, "ES: Close"); m_is_active = false; - // clear the NAND content cache to make sure nothing remains open. - DiscIO::NANDContentManager::Access().ClearCache(); return IPC_SUCCESS; } @@ -658,9 +650,6 @@ s32 ES::DIVerify(const IOS::ES::TMDReader& tmd, const IOS::ES::TicketReader& tic if (!tmd_file.WriteBytes(tmd_bytes.data(), tmd_bytes.size())) ERROR_LOG(IOS_ES, "DIVerify failed to write disc TMD to NAND."); } - // DI_VERIFY writes to title.tmd, which is read and cached inside the NAND Content Manager. - // clear the cache to avoid content access mismatches. - DiscIO::NANDContentManager::Access().ClearCache(); if (!UpdateUIDAndGID(*GetIOS(), m_title_context.tmd)) { diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index 433a9bad0f..3feb3dd954 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -18,11 +18,6 @@ class PointerWrap; -namespace DiscIO -{ -class NANDContentLoader; -} - namespace IOS { namespace HLE diff --git a/Source/Core/Core/IOS/ES/TitleContents.cpp b/Source/Core/Core/IOS/ES/TitleContents.cpp index 28c93b0215..8e7cbb616e 100644 --- a/Source/Core/Core/IOS/ES/TitleContents.cpp +++ b/Source/Core/Core/IOS/ES/TitleContents.cpp @@ -12,7 +12,6 @@ #include "Common/MsgHandler.h" #include "Core/HW/Memmap.h" #include "Core/IOS/ES/Formats.h" -#include "DiscIO/NANDContentLoader.h" namespace IOS { diff --git a/Source/Core/Core/IOS/ES/TitleManagement.cpp b/Source/Core/Core/IOS/ES/TitleManagement.cpp index de2fad3bc8..4a7660fd52 100644 --- a/Source/Core/Core/IOS/ES/TitleManagement.cpp +++ b/Source/Core/Core/IOS/ES/TitleManagement.cpp @@ -22,7 +22,6 @@ #include "Core/HW/Memmap.h" #include "Core/IOS/ES/Formats.h" #include "Core/ec_wii.h" -#include "DiscIO/NANDContentLoader.h" namespace IOS { @@ -506,8 +505,6 @@ ReturnCode ES::DeleteTitle(u64 title_id) ERROR_LOG(IOS_ES, "DeleteTitle: Failed to delete title directory: %s", title_dir.c_str()); return FS_EACCESS; } - // XXX: ugly, but until we drop NANDContentManager everywhere, this is going to be needed. - DiscIO::NANDContentManager::Access().ClearCache(); return IPC_SUCCESS; } diff --git a/Source/Core/Core/IOS/ES/Views.cpp b/Source/Core/Core/IOS/ES/Views.cpp index 8eb32ee326..f3227b7f0a 100644 --- a/Source/Core/Core/IOS/ES/Views.cpp +++ b/Source/Core/Core/IOS/ES/Views.cpp @@ -17,7 +17,6 @@ #include "Core/Core.h" #include "Core/HW/Memmap.h" #include "Core/IOS/ES/Formats.h" -#include "DiscIO/NANDContentLoader.h" namespace IOS { diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index d296045c7a..afb6406c2d 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -19,7 +19,6 @@ #include "Core/IOS/ES/ES.h" #include "Core/IOS/ES/Formats.h" #include "Core/IOS/WFS/WFSSRV.h" -#include "DiscIO/NANDContentLoader.h" namespace { diff --git a/Source/Core/Core/WiiUtils.cpp b/Source/Core/Core/WiiUtils.cpp index f59164472f..2f2c2287bc 100644 --- a/Source/Core/Core/WiiUtils.cpp +++ b/Source/Core/Core/WiiUtils.cpp @@ -38,7 +38,6 @@ #include "DiscIO/DiscExtractor.h" #include "DiscIO/Enums.h" #include "DiscIO/Filesystem.h" -#include "DiscIO/NANDContentLoader.h" #include "DiscIO/Volume.h" #include "DiscIO/VolumeFileBlobReader.h" #include "DiscIO/VolumeWii.h" @@ -129,10 +128,7 @@ bool InstallWAD(IOS::HLE::Kernel& ios, const DiscIO::WiiWAD& wad) return false; } - const bool result = ImportWAD(ios, wad); - - DiscIO::NANDContentManager::Access().ClearCache(); - return result; + return ImportWAD(ios, wad); } bool InstallWAD(const std::string& wad_path) @@ -695,17 +691,13 @@ UpdateResult DiscSystemUpdater::ProcessEntry(u32 type, std::bitset<32> attrs, UpdateResult DoOnlineUpdate(UpdateCallback update_callback, const std::string& region) { OnlineSystemUpdater updater{std::move(update_callback), region}; - const UpdateResult result = updater.DoOnlineUpdate(); - DiscIO::NANDContentManager::Access().ClearCache(); - return result; + return updater.DoOnlineUpdate(); } UpdateResult DoDiscUpdate(UpdateCallback update_callback, const std::string& image_path) { DiscSystemUpdater updater{std::move(update_callback), image_path}; - const UpdateResult result = updater.DoDiscUpdate(); - DiscIO::NANDContentManager::Access().ClearCache(); - return result; + return updater.DoDiscUpdate(); } NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios) diff --git a/Source/Core/DiscIO/CMakeLists.txt b/Source/Core/DiscIO/CMakeLists.txt index 1b6bb3b51d..9e095f464e 100644 --- a/Source/Core/DiscIO/CMakeLists.txt +++ b/Source/Core/DiscIO/CMakeLists.txt @@ -11,7 +11,6 @@ set(SRCS FileBlob.cpp FileSystemGCWii.cpp Filesystem.cpp - NANDContentLoader.cpp NANDImporter.cpp TGCBlob.cpp Volume.cpp diff --git a/Source/Core/DiscIO/DiscIO.vcxproj b/Source/Core/DiscIO/DiscIO.vcxproj index b20dae68bc..4c8b542a6f 100644 --- a/Source/Core/DiscIO/DiscIO.vcxproj +++ b/Source/Core/DiscIO/DiscIO.vcxproj @@ -47,7 +47,6 @@ - @@ -70,7 +69,6 @@ - diff --git a/Source/Core/DiscIO/DiscIO.vcxproj.filters b/Source/Core/DiscIO/DiscIO.vcxproj.filters index 89cfed8abb..c196ae25aa 100644 --- a/Source/Core/DiscIO/DiscIO.vcxproj.filters +++ b/Source/Core/DiscIO/DiscIO.vcxproj.filters @@ -33,9 +33,6 @@ NAND - - NAND - NAND @@ -98,9 +95,6 @@ NAND - - NAND - NAND diff --git a/Source/Core/DiscIO/NANDContentLoader.cpp b/Source/Core/DiscIO/NANDContentLoader.cpp deleted file mode 100644 index 47ea26c81a..0000000000 --- a/Source/Core/DiscIO/NANDContentLoader.cpp +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 2009 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include "DiscIO/NANDContentLoader.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Common/Align.h" -#include "Common/CommonTypes.h" -#include "Common/Crypto/AES.h" -#include "Common/File.h" -#include "Common/FileUtil.h" -#include "Common/Logging/Log.h" -#include "Common/MsgHandler.h" -#include "Common/NandPaths.h" -#include "Common/StringUtil.h" -#include "Common/Swap.h" -// TODO: kill this dependency. -#include "Core/IOS/ES/Formats.h" - -#include "DiscIO/WiiWad.h" - -namespace DiscIO -{ -NANDContentData::~NANDContentData() = default; - -NANDContentDataFile::NANDContentDataFile(const std::string& filename) : m_filename{filename} -{ -} - -NANDContentDataFile::~NANDContentDataFile() = default; - -void NANDContentDataFile::EnsureOpen() -{ - if (!m_file) - m_file = std::make_unique(m_filename, "rb"); - else if (!m_file->IsOpen()) - m_file->Open(m_filename, "rb"); -} -void NANDContentDataFile::Open() -{ - EnsureOpen(); -} -std::vector NANDContentDataFile::Get() -{ - EnsureOpen(); - - if (!m_file->IsGood()) - return {}; - - u64 size = m_file->GetSize(); - if (size == 0) - return {}; - - std::vector result(size); - m_file->ReadBytes(result.data(), result.size()); - - return result; -} - -bool NANDContentDataFile::GetRange(u32 start, u32 size, u8* buffer) -{ - EnsureOpen(); - if (!m_file->IsGood()) - return false; - - if (!m_file->Seek(start, SEEK_SET)) - return false; - - return m_file->ReadBytes(buffer, static_cast(size)); -} -void NANDContentDataFile::Close() -{ - if (m_file && m_file->IsOpen()) - m_file->Close(); -} - -bool NANDContentDataBuffer::GetRange(u32 start, u32 size, u8* buffer) -{ - if (start + size > m_buffer.size()) - return false; - - std::copy_n(&m_buffer[start], size, buffer); - return true; -} - -NANDContentLoader::NANDContentLoader(const std::string& content_name, Common::FromWhichRoot from) - : m_root(from) -{ - m_Valid = Initialize(content_name); -} - -NANDContentLoader::~NANDContentLoader() -{ -} - -bool NANDContentLoader::IsValid() const -{ - return m_Valid; -} - -const NANDContent* NANDContentLoader::GetContentByID(u32 id) const -{ - const auto iterator = std::find_if(m_Content.begin(), m_Content.end(), [id](const auto& content) { - return content.m_metadata.id == id; - }); - return iterator != m_Content.end() ? &*iterator : nullptr; -} - -const NANDContent* NANDContentLoader::GetContentByIndex(int index) const -{ - for (auto& Content : m_Content) - { - if (Content.m_metadata.index == index) - { - return &Content; - } - } - return nullptr; -} - -bool NANDContentLoader::Initialize(const std::string& name) -{ - if (name.empty()) - return false; - - m_Path = name; - - WiiWAD wad(name); - std::vector data_app; - - if (wad.IsValid()) - { - m_IsWAD = true; - m_ticket = wad.GetTicket(); - m_tmd = wad.GetTMD(); - data_app = wad.GetDataApp(); - } - else - { - std::string tmd_filename(m_Path); - - if (tmd_filename.back() == '/') - tmd_filename += "title.tmd"; - else - m_Path = tmd_filename.substr(0, tmd_filename.find("title.tmd")); - - File::IOFile tmd_file(tmd_filename, "rb"); - if (!tmd_file) - { - WARN_LOG(DISCIO, "CreateFromDirectory: error opening %s", tmd_filename.c_str()); - return false; - } - - std::vector bytes(tmd_file.GetSize()); - tmd_file.ReadBytes(bytes.data(), bytes.size()); - m_tmd.SetBytes(std::move(bytes)); - - m_ticket = FindSignedTicket(m_tmd.GetTitleId()); - } - - InitializeContentEntries(data_app); - return true; -} - -void NANDContentLoader::InitializeContentEntries(const std::vector& data_app) -{ - if (!m_ticket.IsValid()) - { - ERROR_LOG(IOS_ES, "No valid ticket for title %016" PRIx64, m_tmd.GetTitleId()); - return; - } - - const std::vector contents = m_tmd.GetContents(); - m_Content.resize(contents.size()); - - u32 data_app_offset = 0; - const std::array title_key = m_ticket.GetTitleKey(); - IOS::ES::SharedContentMap shared_content{m_root}; - - for (size_t i = 0; i < contents.size(); ++i) - { - const auto& content = contents.at(i); - - if (m_IsWAD) - { - // The content index is used as IV (2 bytes); the remaining 14 bytes are zeroes. - std::array iv{}; - iv[0] = static_cast(content.index >> 8) & 0xFF; - iv[1] = static_cast(content.index) & 0xFF; - - u32 rounded_size = Common::AlignUp(static_cast(content.size), 0x40); - - m_Content[i].m_Data = std::make_unique(Common::AES::Decrypt( - title_key.data(), iv.data(), &data_app[data_app_offset], rounded_size)); - data_app_offset += rounded_size; - } - else - { - std::string filename; - if (content.IsShared()) - filename = *shared_content.GetFilenameFromSHA1(content.sha1); - else - filename = StringFromFormat("%s/%08x.app", m_Path.c_str(), content.id); - - m_Content[i].m_Data = std::make_unique(filename); - } - - m_Content[i].m_metadata = std::move(content); - } -} - -NANDContentManager::~NANDContentManager() -{ -} - -const NANDContentLoader& NANDContentManager::GetNANDLoader(const std::string& content_path, - Common::FromWhichRoot from) -{ - auto it = m_map.find(content_path); - if (it != m_map.end()) - return *it->second; - return *m_map - .emplace_hint(it, std::make_pair(content_path, std::make_unique( - content_path, from))) - ->second; -} - -const NANDContentLoader& NANDContentManager::GetNANDLoader(u64 title_id, Common::FromWhichRoot from) -{ - std::string path = Common::GetTitleContentPath(title_id, from); - return GetNANDLoader(path, from); -} - -void NANDContentManager::ClearCache() -{ - m_map.clear(); -} - -IOS::ES::TicketReader FindSignedTicket(u64 title_id) -{ - std::string ticket_filename = Common::GetTicketFileName(title_id, Common::FROM_CONFIGURED_ROOT); - File::IOFile ticket_file(ticket_filename, "rb"); - if (!ticket_file) - { - return IOS::ES::TicketReader{}; - } - - std::vector signed_ticket(ticket_file.GetSize()); - if (!ticket_file.ReadBytes(signed_ticket.data(), signed_ticket.size())) - { - return IOS::ES::TicketReader{}; - } - - return IOS::ES::TicketReader{std::move(signed_ticket)}; -} -} // namespace end diff --git a/Source/Core/DiscIO/NANDContentLoader.h b/Source/Core/DiscIO/NANDContentLoader.h deleted file mode 100644 index aa7d1c168e..0000000000 --- a/Source/Core/DiscIO/NANDContentLoader.h +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2009 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include -#include - -#include "Common/CommonTypes.h" -#include "Common/NandPaths.h" -#include "Core/IOS/ES/Formats.h" - -namespace File -{ -class IOFile; -} - -namespace DiscIO -{ -enum class Region; - -// TODO: move some of these to Core/IOS/ES. -IOS::ES::TicketReader FindSignedTicket(u64 title_id); - -class NANDContentData -{ -public: - virtual ~NANDContentData() = 0; - virtual void Open() {} - virtual std::vector Get() = 0; - virtual bool GetRange(u32 start, u32 size, u8* buffer) = 0; - virtual void Close() {} -}; - -class NANDContentDataFile final : public NANDContentData -{ -public: - explicit NANDContentDataFile(const std::string& filename); - ~NANDContentDataFile(); - - void Open() override; - std::vector Get() override; - bool GetRange(u32 start, u32 size, u8* buffer) override; - void Close() override; - -private: - void EnsureOpen(); - - const std::string m_filename; - std::unique_ptr m_file; -}; - -class NANDContentDataBuffer final : public NANDContentData -{ -public: - explicit NANDContentDataBuffer(const std::vector& buffer) : m_buffer(buffer) {} - std::vector Get() override { return m_buffer; } - bool GetRange(u32 start, u32 size, u8* buffer) override; - -private: - const std::vector m_buffer; -}; - -struct NANDContent -{ - IOS::ES::Content m_metadata; - std::unique_ptr m_Data; -}; - -// Instances of this class must be created by NANDContentManager -class NANDContentLoader final -{ -public: - explicit NANDContentLoader(const std::string& content_name, Common::FromWhichRoot from); - ~NANDContentLoader(); - - bool IsValid() const; - const NANDContent* GetContentByID(u32 id) const; - const NANDContent* GetContentByIndex(int index) const; - const IOS::ES::TMDReader& GetTMD() const { return m_tmd; } - const IOS::ES::TicketReader& GetTicket() const { return m_ticket; } - const std::vector& GetContent() const { return m_Content; } -private: - bool Initialize(const std::string& name); - void InitializeContentEntries(const std::vector& data_app); - - bool m_Valid = false; - bool m_IsWAD = false; - Common::FromWhichRoot m_root; - std::string m_Path; - IOS::ES::TMDReader m_tmd; - IOS::ES::TicketReader m_ticket; - - std::vector m_Content; -}; - -// we open the NAND Content files too often... let's cache them -class NANDContentManager -{ -public: - static NANDContentManager& Access() - { - static NANDContentManager instance; - return instance; - } - - const NANDContentLoader& GetNANDLoader(const std::string& content_path, - Common::FromWhichRoot from = Common::FROM_CONFIGURED_ROOT); - const NANDContentLoader& GetNANDLoader(u64 title_id, - Common::FromWhichRoot from = Common::FROM_CONFIGURED_ROOT); - void ClearCache(); - -private: - NANDContentManager() {} - ~NANDContentManager(); - - NANDContentManager(NANDContentManager const&) = delete; - void operator=(NANDContentManager const&) = delete; - - std::unordered_map> m_map; -}; -} diff --git a/Source/Core/DiscIO/NANDImporter.cpp b/Source/Core/DiscIO/NANDImporter.cpp index 220a241390..5a9983ce03 100644 --- a/Source/Core/DiscIO/NANDImporter.cpp +++ b/Source/Core/DiscIO/NANDImporter.cpp @@ -17,7 +17,6 @@ #include "Common/StringUtil.h" #include "Common/Swap.h" #include "Core/IOS/ES/Formats.h" -#include "DiscIO/NANDContentLoader.h" namespace DiscIO { @@ -44,9 +43,6 @@ void NANDImporter::ImportNANDBin(const std::string& path_to_bin, ProcessEntry(0, nand_root); ExportKeys(nand_root); ExtractCertificates(nand_root); - - // We have to clear the cache so the new NAND takes effect - DiscIO::NANDContentManager::Access().ClearCache(); } bool NANDImporter::ReadNANDBin(const std::string& path_to_bin) diff --git a/Source/Core/DiscIO/VolumeWad.h b/Source/Core/DiscIO/VolumeWad.h index a97f2d078e..33bfe4f7a6 100644 --- a/Source/Core/DiscIO/VolumeWad.h +++ b/Source/Core/DiscIO/VolumeWad.h @@ -14,10 +14,6 @@ #include "Core/IOS/ES/Formats.h" #include "DiscIO/Volume.h" -// --- this volume type is used for Wad files --- -// Some of this code might look redundant with the NANDContentLoader class, however, -// We do not do any decryption here, we do raw read, so things are -Faster- - namespace DiscIO { class BlobReader; diff --git a/Source/Core/DolphinQt2/GameList/GameFile.cpp b/Source/Core/DolphinQt2/GameList/GameFile.cpp index 035028c9f9..9f5314a444 100644 --- a/Source/Core/DolphinQt2/GameList/GameFile.cpp +++ b/Source/Core/DolphinQt2/GameList/GameFile.cpp @@ -18,7 +18,6 @@ #include "Core/WiiUtils.h" #include "DiscIO/Blob.h" #include "DiscIO/Enums.h" -#include "DiscIO/NANDContentLoader.h" #include "DiscIO/Volume.h" #include "DolphinQt2/GameList/GameFile.h" #include "DolphinQt2/Resources.h" diff --git a/Source/Core/DolphinWX/Config/PathConfigPane.cpp b/Source/Core/DolphinWX/Config/PathConfigPane.cpp index 0d54738192..ce1c2a78a4 100644 --- a/Source/Core/DolphinWX/Config/PathConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/PathConfigPane.cpp @@ -18,7 +18,6 @@ #include "Common/FileUtil.h" #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "DiscIO/NANDContentLoader.h" #include "DolphinWX/Config/ConfigMain.h" #include "DolphinWX/Frame.h" #include "DolphinWX/WxEventUtils.h" @@ -202,8 +201,6 @@ void PathConfigPane::OnNANDRootChanged(wxCommandEvent& event) File::SetUserPath(D_WIIROOT_IDX, nand_path); m_nand_root_dirpicker->SetPath(StrToWxStr(nand_path)); - DiscIO::NANDContentManager::Access().ClearCache(); - wxCommandEvent update_event{DOLPHIN_EVT_UPDATE_LOAD_WII_MENU_ITEM, GetId()}; update_event.SetEventObject(this); AddPendingEvent(update_event); diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index 7cd566b80e..05b819a99b 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -60,7 +60,6 @@ #include "Core/WiiUtils.h" #include "DiscIO/Enums.h" -#include "DiscIO/NANDContentLoader.h" #include "DiscIO/NANDImporter.h" #include "DiscIO/VolumeWad.h" From 8e0869aff6c50a23cd1ca9b2e03ad7c484ee2585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 1 Oct 2017 22:00:30 +0200 Subject: [PATCH 15/18] DiscIO: Remove comments that state obvious facts --- Source/Core/DiscIO/VolumeGC.h | 2 -- Source/Core/DiscIO/VolumeWii.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/Source/Core/DiscIO/VolumeGC.h b/Source/Core/DiscIO/VolumeGC.h index fc065a8d60..4f878c3bc9 100644 --- a/Source/Core/DiscIO/VolumeGC.h +++ b/Source/Core/DiscIO/VolumeGC.h @@ -15,8 +15,6 @@ #include "DiscIO/Filesystem.h" #include "DiscIO/Volume.h" -// --- this volume type is used for GC disc images --- - namespace DiscIO { class BlobReader; diff --git a/Source/Core/DiscIO/VolumeWii.h b/Source/Core/DiscIO/VolumeWii.h index 97604887a3..84d58a530c 100644 --- a/Source/Core/DiscIO/VolumeWii.h +++ b/Source/Core/DiscIO/VolumeWii.h @@ -17,8 +17,6 @@ #include "DiscIO/Filesystem.h" #include "DiscIO/Volume.h" -// --- this volume type is used for Wii disc images --- - namespace DiscIO { class BlobReader; From 4b4a9a64865bbeeb55161a977bcadcb5ed58ade3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Mon, 2 Oct 2017 00:09:07 +0200 Subject: [PATCH 16/18] UI: Implement a command line option to boot NAND title --- Source/Core/DolphinNoGUI/MainNoGUI.cpp | 22 ++++++++++---- Source/Core/DolphinQt2/Main.cpp | 18 +++++++++++- Source/Core/DolphinQt2/MainWindow.cpp | 5 +++- Source/Core/DolphinQt2/MainWindow.h | 2 +- Source/Core/DolphinWX/Frame.h | 2 +- Source/Core/DolphinWX/Main.cpp | 36 +++++++++++++---------- Source/Core/DolphinWX/Main.h | 5 ++-- Source/Core/UICommon/CommandLineParse.cpp | 5 ++++ 8 files changed, 69 insertions(+), 26 deletions(-) diff --git a/Source/Core/DolphinNoGUI/MainNoGUI.cpp b/Source/Core/DolphinNoGUI/MainNoGUI.cpp index ecd2d3ba88..5619689abc 100644 --- a/Source/Core/DolphinNoGUI/MainNoGUI.cpp +++ b/Source/Core/DolphinNoGUI/MainNoGUI.cpp @@ -360,14 +360,26 @@ int main(int argc, char* argv[]) optparse::Values& options = CommandLineParse::ParseArguments(parser.get(), argc, argv); std::vector args = parser->args(); - std::string boot_filename; + std::unique_ptr boot; if (options.is_set("exec")) { - boot_filename = static_cast(options.get("exec")); + boot = BootParameters::GenerateFromFile(static_cast(options.get("exec"))); + } + else if (options.is_set("nand_title")) + { + const std::string hex_string = static_cast(options.get("nand_title")); + if (hex_string.length() != 16) + { + fprintf(stderr, "Invalid title ID\n"); + parser->print_help(); + return 1; + } + const u64 title_id = std::stoull(hex_string, nullptr, 16); + boot = std::make_unique(BootParameters::NANDTitle{title_id}); } else if (args.size()) { - boot_filename = args.front(); + boot = BootParameters::GenerateFromFile(args.front()); args.erase(args.begin()); } else @@ -408,9 +420,9 @@ int main(int argc, char* argv[]) DolphinAnalytics::Instance()->ReportDolphinStart("nogui"); - if (!BootManager::BootCore(BootParameters::GenerateFromFile(boot_filename))) + if (!BootManager::BootCore(std::move(boot))) { - fprintf(stderr, "Could not boot %s\n", boot_filename.c_str()); + fprintf(stderr, "Could not boot the specified file\n"); return 1; } diff --git a/Source/Core/DolphinQt2/Main.cpp b/Source/Core/DolphinQt2/Main.cpp index fea2b56379..1a9b66cbae 100644 --- a/Source/Core/DolphinQt2/Main.cpp +++ b/Source/Core/DolphinQt2/Main.cpp @@ -10,6 +10,7 @@ #include "Common/MsgHandler.h" #include "Core/Analytics.h" +#include "Core/Boot/Boot.h" #include "Core/BootManager.h" #include "Core/Core.h" #include "DolphinQt2/Host.h" @@ -84,6 +85,21 @@ int main(int argc, char* argv[]) QObject::connect(QAbstractEventDispatcher::instance(), &QAbstractEventDispatcher::aboutToBlock, &app, &Core::HostDispatchJobs); + std::unique_ptr boot; + if (options.is_set("nand_title")) + { + const std::string hex_string = static_cast(options.get("nand_title")); + if (hex_string.length() == 16) + { + const u64 title_id = std::stoull(hex_string, nullptr, 16); + boot = std::make_unique(BootParameters::NANDTitle{title_id}); + } + else + { + QMessageBox::critical(nullptr, QObject::tr("Error"), QObject::tr("Invalid title ID.")); + } + } + int retval = 0; if (SConfig::GetInstance().m_show_development_warning) @@ -95,7 +111,7 @@ int main(int argc, char* argv[]) { DolphinAnalytics::Instance()->ReportDolphinStart("qt"); - MainWindow win; + MainWindow win{std::move(boot)}; win.show(); #if defined(USE_ANALYTICS) && USE_ANALYTICS diff --git a/Source/Core/DolphinQt2/MainWindow.cpp b/Source/Core/DolphinQt2/MainWindow.cpp index 7ebc6e9546..304327a4b7 100644 --- a/Source/Core/DolphinQt2/MainWindow.cpp +++ b/Source/Core/DolphinQt2/MainWindow.cpp @@ -65,7 +65,7 @@ #include "UICommon/X11Utils.h" #endif -MainWindow::MainWindow() : QMainWindow(nullptr) +MainWindow::MainWindow(std::unique_ptr boot_parameters) : QMainWindow(nullptr) { setWindowTitle(QString::fromStdString(Common::scm_rev_str)); setWindowIcon(QIcon(Resources::GetMisc(Resources::LOGO_SMALL))); @@ -84,6 +84,9 @@ MainWindow::MainWindow() : QMainWindow(nullptr) InitCoreCallbacks(); NetPlayInit(); + + if (boot_parameters) + StartGame(std::move(boot_parameters)); } MainWindow::~MainWindow() diff --git a/Source/Core/DolphinQt2/MainWindow.h b/Source/Core/DolphinQt2/MainWindow.h index 93d5431334..d8db4fc01b 100644 --- a/Source/Core/DolphinQt2/MainWindow.h +++ b/Source/Core/DolphinQt2/MainWindow.h @@ -35,7 +35,7 @@ class MainWindow final : public QMainWindow Q_OBJECT public: - explicit MainWindow(); + explicit MainWindow(std::unique_ptr boot_parameters); ~MainWindow(); bool eventFilter(QObject* object, QEvent* event) override; diff --git a/Source/Core/DolphinWX/Frame.h b/Source/Core/DolphinWX/Frame.h index 30f86ae6dc..4e33b645e5 100644 --- a/Source/Core/DolphinWX/Frame.h +++ b/Source/Core/DolphinWX/Frame.h @@ -106,6 +106,7 @@ public: void StatusBarMessage(const char* format, ...); void ClearStatusBar(); void BootGame(const std::string& filename); + void StartGame(std::unique_ptr boot); bool RendererHasFocus(); bool RendererIsFullscreen(); void OpenGeneralConfiguration(wxWindowID tab_id = wxID_ANY); @@ -193,7 +194,6 @@ private: void InitializeTASDialogs(); void InitializeCoreCallbacks(); - void StartGame(std::unique_ptr boot); void SetDebuggerStartupParameters() const; // Utility diff --git a/Source/Core/DolphinWX/Main.cpp b/Source/Core/DolphinWX/Main.cpp index bff1c34adb..fd87aaea8e 100644 --- a/Source/Core/DolphinWX/Main.cpp +++ b/Source/Core/DolphinWX/Main.cpp @@ -34,6 +34,7 @@ #include "Common/Version.h" #include "Core/Analytics.h" +#include "Core/Boot/Boot.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/HW/Wiimote.h" @@ -169,13 +170,24 @@ void DolphinApp::ParseCommandLine() if (options.is_set("exec")) { - m_load_file = true; - m_file_to_load = static_cast(options.get("exec")); + m_boot = BootParameters::GenerateFromFile(static_cast(options.get("exec"))); + } + else if (options.is_set("nand_title")) + { + const std::string hex_string = static_cast(options.get("nand_title")); + if (hex_string.length() == 16) + { + const u64 title_id = std::stoull(hex_string, nullptr, 16); + m_boot = std::make_unique(BootParameters::NANDTitle{title_id}); + } + else + { + WxUtils::ShowErrorDialog(_("The title ID is invalid.")); + } } else if (args.size()) { - m_load_file = true; - m_file_to_load = args.front(); + m_boot = BootParameters::GenerateFromFile(args.front()); args.erase(args.begin()); } @@ -201,9 +213,7 @@ void DolphinApp::ParseCommandLine() #ifdef __APPLE__ void DolphinApp::MacOpenFile(const wxString& fileName) { - m_file_to_load = fileName; - m_load_file = true; - main_frame->BootGame(WxStrToStr(m_file_to_load)); + main_frame->StartGame(BootParameters::GenerateFromFile(fileName.ToStdString())); } #endif @@ -241,20 +251,16 @@ void DolphinApp::AfterInit() { if (Movie::PlayInput(WxStrToStr(m_movie_file))) { - if (m_load_file && !m_file_to_load.empty()) - { - main_frame->BootGame(WxStrToStr(m_file_to_load)); - } + if (m_boot) + main_frame->StartGame(std::move(m_boot)); else - { main_frame->BootGame(""); - } } } // First check if we have an exec command line. - else if (m_load_file && !m_file_to_load.empty()) + else if (m_boot) { - main_frame->BootGame(WxStrToStr(m_file_to_load)); + main_frame->StartGame(std::move(m_boot)); } // If we have selected Automatic Start, start the default ISO, // or if no default ISO exists, start the last loaded ISO diff --git a/Source/Core/DolphinWX/Main.h b/Source/Core/DolphinWX/Main.h index 46f3d80e91..324051fdbd 100644 --- a/Source/Core/DolphinWX/Main.h +++ b/Source/Core/DolphinWX/Main.h @@ -13,6 +13,8 @@ class wxLocale; extern CFrame* main_frame; +struct BootParameters; + // Define a new application class DolphinApp : public wxApp { @@ -43,7 +45,6 @@ private: bool m_batch_mode = false; bool m_confirm_stop = false; bool m_is_active = true; - bool m_load_file = false; bool m_play_movie = false; bool m_use_debugger = false; bool m_use_logger = false; @@ -53,7 +54,7 @@ private: wxString m_video_backend_name; wxString m_audio_emulation_name; wxString m_user_path; - wxString m_file_to_load; + std::unique_ptr m_boot; wxString m_movie_file; std::unique_ptr m_locale; }; diff --git a/Source/Core/UICommon/CommandLineParse.cpp b/Source/Core/UICommon/CommandLineParse.cpp index c5db8b57e0..d76a2052c4 100644 --- a/Source/Core/UICommon/CommandLineParse.cpp +++ b/Source/Core/UICommon/CommandLineParse.cpp @@ -73,6 +73,11 @@ std::unique_ptr CreateParser(ParserOptions options) .metavar("") .type("string") .help("Load the specified file"); + parser->add_option("-n", "--nand_title") + .action("store") + .metavar("<16-character ASCII title ID>") + .type("string") + .help("Launch a NAND title"); parser->add_option("-C", "--config") .action("append") .metavar(".
.=") From dedb61e5bfec7827166b0a3b5d2b21e414b8c35a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Tue, 3 Oct 2017 16:07:28 +0200 Subject: [PATCH 17/18] Boot: Install WADs temporarily Because the Wii NAND size is finite, mark titles that were installed only for booting as temporary, and remove them whenever we need to install another title (to make room). This is exactly what the System Menu does for temporary SD card title data. --- Source/Core/Core/Boot/Boot_WiiWAD.cpp | 2 +- Source/Core/Core/WiiUtils.cpp | 35 ++++++++++++++++++++++----- Source/Core/Core/WiiUtils.h | 11 +++++++-- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/Source/Core/Core/Boot/Boot_WiiWAD.cpp b/Source/Core/Core/Boot/Boot_WiiWAD.cpp index 58af4ae961..fd62f17cf8 100644 --- a/Source/Core/Core/Boot/Boot_WiiWAD.cpp +++ b/Source/Core/Core/Boot/Boot_WiiWAD.cpp @@ -38,7 +38,7 @@ bool CBoot::BootNANDTitle(const u64 title_id) bool CBoot::Boot_WiiWAD(const DiscIO::WiiWAD& wad) { - if (!WiiUtils::InstallWAD(*IOS::HLE::GetIOS(), wad)) + if (!WiiUtils::InstallWAD(*IOS::HLE::GetIOS(), wad, WiiUtils::InstallType::Temporary)) { PanicAlertT("Cannot boot this WAD because it could not be installed to the NAND."); return false; diff --git a/Source/Core/Core/WiiUtils.cpp b/Source/Core/Core/WiiUtils.cpp index 2f2c2287bc..bde5e04a10 100644 --- a/Source/Core/Core/WiiUtils.cpp +++ b/Source/Core/Core/WiiUtils.cpp @@ -29,6 +29,7 @@ #include "Common/NandPaths.h" #include "Common/StringUtil.h" #include "Common/Swap.h" +#include "Common/SysConf.h" #include "Core/CommonTitles.h" #include "Core/ConfigManager.h" #include "Core/IOS/Device.h" @@ -109,7 +110,7 @@ static bool ImportWAD(IOS::HLE::Kernel& ios, const DiscIO::WiiWAD& wad) return true; } -bool InstallWAD(IOS::HLE::Kernel& ios, const DiscIO::WiiWAD& wad) +bool InstallWAD(IOS::HLE::Kernel& ios, const DiscIO::WiiWAD& wad, InstallType install_type) { if (!wad.GetTMD().IsValid()) return false; @@ -121,20 +122,42 @@ bool InstallWAD(IOS::HLE::Kernel& ios, const DiscIO::WiiWAD& wad) // If a different version is currently installed, warn the user to make sure // they don't overwrite the current version by mistake. - if (ios.GetES()->FindInstalledTMD(wad.GetTMD().GetTitleId()).IsValid() && - !AskYesNoT("A different version of this title is already installed on the NAND. " - "Installing this WAD will replace it irreversibly. Continue?")) + const u64 title_id = wad.GetTMD().GetTitleId(); + const IOS::ES::TMDReader installed_tmd = ios.GetES()->FindInstalledTMD(title_id); + const bool has_another_version = + installed_tmd.IsValid() && installed_tmd.GetTitleVersion() != wad.GetTMD().GetTitleVersion(); + if (has_another_version && + !AskYesNoT("A different version of this title is already installed on the NAND.\n\n" + "Installed version: %u\nWAD version: %u\n\n" + "Installing this WAD will replace it irreversibly. Continue?", + installed_tmd.GetTitleVersion(), wad.GetTMD().GetTitleVersion())) { return false; } - return ImportWAD(ios, wad); + // Delete a previous temporary title, if it exists. + SysConf sysconf{Common::FROM_SESSION_ROOT}; + SysConf::Entry* tid_entry = sysconf.GetOrAddEntry("IPL.TID", SysConf::Entry::Type::LongLong); + if (const u64 previous_temporary_title_id = Common::swap64(tid_entry->GetData(0))) + ios.GetES()->DeleteTitleContent(previous_temporary_title_id); + + if (!ImportWAD(ios, wad)) + return false; + + // Keep track of the title ID so this title can be removed to make room for any future install. + // We use the same mechanism as the System Menu for temporary SD card title data. + if (!has_another_version && install_type == InstallType::Temporary) + tid_entry->SetData(Common::swap64(title_id)); + else + tid_entry->SetData(0); + + return true; } bool InstallWAD(const std::string& wad_path) { IOS::HLE::Kernel ios; - return InstallWAD(ios, DiscIO::WiiWAD{wad_path}); + return InstallWAD(ios, DiscIO::WiiWAD{wad_path}, InstallType::Permanent); } // Common functionality for system updaters. diff --git a/Source/Core/Core/WiiUtils.h b/Source/Core/Core/WiiUtils.h index eb7d669672..b07863fa3b 100644 --- a/Source/Core/Core/WiiUtils.h +++ b/Source/Core/Core/WiiUtils.h @@ -27,8 +27,15 @@ class Kernel; namespace WiiUtils { -bool InstallWAD(IOS::HLE::Kernel& ios, const DiscIO::WiiWAD& wad); -// Same as the above, but constructs a temporary IOS and WiiWAD instance for importing. +enum class InstallType +{ + Permanent, + Temporary, +}; + +bool InstallWAD(IOS::HLE::Kernel& ios, const DiscIO::WiiWAD& wad, InstallType type); +// Same as the above, but constructs a temporary IOS and WiiWAD instance for importing +// and does a permanent install. bool InstallWAD(const std::string& wad_path); enum class UpdateResult From 4cc1bd972a12186b320d5e1142f10ab145df3203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Wed, 4 Oct 2017 10:48:49 +0200 Subject: [PATCH 18/18] CommonTitles: Add a named constant for IOS TIDs --- Source/Core/Core/Boot/Boot.cpp | 2 +- Source/Core/Core/CommonTitles.h | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 5d4bf93c7a..a3083308ef 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -339,7 +339,7 @@ bool CBoot::BootUp(std::unique_ptr boot) // Because there is no TMD to get the requested system (IOS) version from, // we default to IOS58, which is the version used by the Homebrew Channel. SetupWiiMemory(); - IOS::HLE::GetIOS()->BootIOS(0x000000010000003a); + IOS::HLE::GetIOS()->BootIOS(Titles::IOS(58)); } else { diff --git a/Source/Core/Core/CommonTitles.h b/Source/Core/Core/CommonTitles.h index 5b86db8f17..3ed6176e2f 100644 --- a/Source/Core/Core/CommonTitles.h +++ b/Source/Core/Core/CommonTitles.h @@ -12,11 +12,16 @@ constexpr u64 BOOT2 = 0x0000000100000001; constexpr u64 SYSTEM_MENU = 0x0000000100000002; -// IOS used by the latest System Menu (4.3). Corresponds to IOS80. -constexpr u64 SYSTEM_MENU_IOS = 0x0000000100000050; - -constexpr u64 BC = 0x0000000100000100; -constexpr u64 MIOS = 0x0000000100000101; - constexpr u64 SHOP = 0x0001000248414241; + +constexpr u64 IOS(u32 major_version) +{ + return 0x0000000100000000 | major_version; +} + +// IOS used by the latest System Menu (4.3). Corresponds to IOS80. +constexpr u64 SYSTEM_MENU_IOS = IOS(80); + +constexpr u64 BC = IOS(0x100); +constexpr u64 MIOS = IOS(0x101); } // namespace Titles