diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 46176ecf5c..6e0ffebba6 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -278,8 +278,6 @@ bool CBoot::BootUp() PanicAlertT("Warning - starting ISO in wrong console mode!"); } - IOS::HLE::ES_DIVerify(pVolume.GetTMD()); - _StartupPara.bWii = pVolume.GetVolumeType() == DiscIO::Platform::WII_DISC; // HLE BS2 or not diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index 605579f597..e320d93e71 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -21,6 +21,7 @@ #include "Core/HW/DVDInterface.h" #include "Core/HW/EXI/EXI_DeviceIPL.h" #include "Core/HW/Memmap.h" +#include "Core/IOS/ES/ES.h" #include "Core/IOS/ES/Formats.h" #include "Core/IOS/IPC.h" #include "Core/PatchEngine.h" @@ -311,6 +312,11 @@ bool CBoot::EmulatedBS2_Wii() if (DVDInterface::GetVolume().GetVolumeType() != DiscIO::Platform::WII_DISC) return false; + const IOS::ES::TMDReader tmd = DVDInterface::GetVolume().GetTMD(); + + if (!SetupWiiMemory(tmd.GetIOSId())) + return false; + // This is some kind of consistency check that is compared to the 0x00 // values as the game boots. This location keeps the 4 byte ID for as long // as the game is running. The 6 byte ID at 0x00 is overwritten sometime @@ -346,11 +352,6 @@ bool CBoot::EmulatedBS2_Wii() PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer - IOS::ES::TMDReader tmd = DVDInterface::GetVolume().GetTMD(); - - if (!SetupWiiMemory(tmd.GetIOSId())) - return false; - // Execute the apploader const u32 apploader_offset = 0x2440; // 0x1c40; @@ -383,11 +384,7 @@ bool CBoot::EmulatedBS2_Wii() PowerPC::ppcState.gpr[3] = 0x81300000; RunFunction(iAppLoaderInit); - // Let the apploader load the exe to memory. At this point I get an unknown IPC command - // (command zero) when I load Wii Sports or other games a second time. I don't notice - // any side effects however. It's a little disconcerting however that Start after Stop - // behaves differently than the first Start after starting Dolphin. It means something - // was not reset correctly. + // Let the apploader load the exe to memory DEBUG_LOG(BOOT, "Run iAppLoaderMain"); do { @@ -410,8 +407,7 @@ bool CBoot::EmulatedBS2_Wii() DEBUG_LOG(BOOT, "Run iAppLoaderClose"); RunFunction(iAppLoaderClose); - // Load patches and run startup patches - PatchEngine::LoadPatches(); + IOS::HLE::Device::ES::DIVerify(tmd, DVDInterface::GetVolume().GetTicket()); // return PC = PowerPC::ppcState.gpr[3]; diff --git a/Source/Core/Core/Boot/Boot_WiiWAD.cpp b/Source/Core/Core/Boot/Boot_WiiWAD.cpp index 612ddc8fe8..eff9775006 100644 --- a/Source/Core/Core/Boot/Boot_WiiWAD.cpp +++ b/Source/Core/Core/Boot/Boot_WiiWAD.cpp @@ -11,6 +11,7 @@ #include "Common/NandPaths.h" #include "Core/Boot/Boot.h" +#include "Core/IOS/ES/ES.h" #include "Core/IOS/FS/FileIO.h" #include "Core/IOS/IPC.h" #include "Core/PatchEngine.h" @@ -87,7 +88,7 @@ bool CBoot::Boot_WiiWAD(const std::string& _pFilename) if (!SetupWiiMemory(ContentLoader.GetTMD().GetIOSId())) return false; - IOS::HLE::SetDefaultContentFile(_pFilename); + IOS::HLE::Device::ES::LoadWAD(_pFilename); if (!IOS::HLE::BootstrapPPC(ContentLoader)) return false; diff --git a/Source/Core/Core/IOS/DI/DI.cpp b/Source/Core/Core/IOS/DI/DI.cpp index bd91eb11d5..4dc743b81c 100644 --- a/Source/Core/Core/IOS/DI/DI.cpp +++ b/Source/Core/Core/IOS/DI/DI.cpp @@ -14,8 +14,8 @@ #include "Core/HW/DVDInterface.h" #include "Core/HW/Memmap.h" #include "Core/IOS/DI/DI.h" +#include "Core/IOS/ES/ES.h" #include "Core/IOS/ES/Formats.h" -#include "Core/IOS/IPC.h" #include "DiscIO/Volume.h" namespace IOS @@ -106,10 +106,10 @@ IPCCommandResult DI::IOCtlV(const IOCtlVRequest& request) INFO_LOG(IOS_DI, "DVDLowOpenPartition: partition_offset 0x%016" PRIx64, partition_offset); // Read TMD to the buffer - const ES::TMDReader tmd = DVDInterface::GetVolume().GetTMD(); + const IOS::ES::TMDReader tmd = DVDInterface::GetVolume().GetTMD(); const std::vector raw_tmd = tmd.GetRawTMD(); Memory::CopyToEmu(request.io_vectors[0].address, raw_tmd.data(), raw_tmd.size()); - ES_DIVerify(tmd); + ES::DIVerify(tmd, DVDInterface::GetVolume().GetTicket()); return_value = 1; break; diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index 79a69e2317..e2cb1ce188 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -20,17 +20,22 @@ #include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/NandPaths.h" +#include "Core/Boot/Boot.h" #include "Core/Boot/Boot_DOL.h" #include "Core/ConfigManager.h" +#include "Core/HLE/HLE.h" #include "Core/HW/DVDInterface.h" #include "Core/HW/Memmap.h" #include "Core/IOS/ES/ES.h" #include "Core/IOS/ES/Formats.h" +#include "Core/PatchEngine.h" +#include "Core/PowerPC/PPCSymbolDB.h" #include "Core/PowerPC/PowerPC.h" #include "Core/WiiRoot.h" #include "Core/ec_wii.h" #include "DiscIO/NANDContentLoader.h" #include "DiscIO/Volume.h" +#include "VideoCommon/HiresTextures.h" namespace IOS { @@ -38,7 +43,27 @@ namespace HLE { namespace Device { -std::string ES::m_ContentFile; +struct TitleContext +{ + void Clear(); + void DoState(PointerWrap& p); + void Update(const DiscIO::CNANDContentLoader& content_loader); + void Update(const IOS::ES::TMDReader& tmd_, const IOS::ES::TicketReader& ticket_); + void UpdateRunningGame() const; + + IOS::ES::TicketReader ticket; + IOS::ES::TMDReader tmd; + bool active = false; + bool first_change = true; +}; + +// Shared across all ES instances. +static std::string s_content_file; +static std::vector s_title_ids; +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; constexpr u8 s_key_sd[0x10] = {0xab, 0x01, 0xb9, 0xd8, 0xe1, 0x62, 0x2b, 0x08, 0xaf, 0xba, 0xd8, 0x4d, 0xbf, 0xc2, 0xa5, 0x5d}; @@ -67,9 +92,111 @@ ES::ES(u32 device_id, const std::string& device_name) : Device(device_id, device { } +void ES::Init() +{ + s_content_file = ""; + s_title_context = TitleContext{}; + + s_title_ids.clear(); + DiscIO::cUIDsys uid_sys{Common::FromWhichRoot::FROM_SESSION_ROOT}; + uid_sys.GetTitleIDs(s_title_ids); + + // uncomment if ES_GetOwnedTitlesCount / ES_GetOwnedTitles is implemented + // s_title_idsOwned.clear(); + // DiscIO::cUIDsys::AccessInstance().GetTitleIDs(s_title_idsOwned, true); + + if (s_title_to_launch != 0) + { + NOTICE_LOG(IOS, "Re-launching title after IOS reload."); + LaunchTitle(s_title_to_launch, true); + s_title_to_launch = 0; + } +} + +void TitleContext::Clear() +{ + ticket.SetBytes({}); + tmd.SetBytes({}); + active = false; +} + +void TitleContext::DoState(PointerWrap& p) +{ + ticket.DoState(p); + tmd.DoState(p); + p.Do(active); +} + +void TitleContext::Update(const DiscIO::CNANDContentLoader& 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()) + { + ERROR_LOG(IOS_ES, "TMD or ticket is not valid -- refusing to update title context"); + return; + } + + ticket = ticket_; + tmd = tmd_; + active = true; + + // Interesting title changes (channel or disc game launch) always happen after an IOS reload. + if (first_change) + { + UpdateRunningGame(); + first_change = false; + } +} + +void TitleContext::UpdateRunningGame() const +{ + // This one does not always make sense for Wii titles, so let's reset it back to a sane value. + SConfig::GetInstance().m_strName = ""; + if (IOS::ES::IsTitleType(tmd.GetTitleId(), IOS::ES::TitleType::Game) || + IOS::ES::IsTitleType(tmd.GetTitleId(), IOS::ES::TitleType::GameWithChannel)) + { + const u32 title_identifier = Common::swap32(static_cast(tmd.GetTitleId())); + const u16 group_id = Common::swap16(tmd.GetGroupId()); + + char ascii_game_id[6]; + std::memcpy(ascii_game_id, &title_identifier, sizeof(title_identifier)); + std::memcpy(ascii_game_id + sizeof(title_identifier), &group_id, sizeof(group_id)); + + SConfig::GetInstance().m_strGameID = ascii_game_id; + } + else + { + SConfig::GetInstance().m_strGameID = StringFromFormat("%016" PRIX64, tmd.GetTitleId()); + } + + SConfig::GetInstance().m_title_id = tmd.GetTitleId(); + + // TODO: have a callback mechanism for title changes? + g_symbolDB.Clear(); + CBoot::LoadMapFromFilename(); + ::HLE::Clear(); + ::HLE::PatchFunctions(); + PatchEngine::Shutdown(); + PatchEngine::LoadPatches(); + HiresTexture::Update(); + + NOTICE_LOG(IOS_ES, "Active title: %016" PRIx64, tmd.GetTitleId()); +} + void ES::LoadWAD(const std::string& _rContentFile) { - m_ContentFile = _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::CNANDContentManager::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()); } void ES::DecryptContent(u32 key_index, u8* iv, u8* input, u32 size, u8* new_iv, u8* output) @@ -80,8 +207,11 @@ void ES::DecryptContent(u32 key_index, u8* iv, u8* input, u32 size, u8* new_iv, mbedtls_aes_crypt_cbc(&AES_ctx, MBEDTLS_AES_DECRYPT, size, new_iv, input, output); } -bool ES::LaunchTitle(u64 title_id, bool skip_reload) const +bool ES::LaunchTitle(u64 title_id, bool skip_reload) { + s_title_context.Clear(); + INFO_LOG(IOS_ES, "ES_Launch: Title context changed: (none)"); + 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. @@ -94,12 +224,12 @@ bool ES::LaunchTitle(u64 title_id, bool skip_reload) const return LaunchPPCTitle(title_id, skip_reload); } -bool ES::LaunchIOS(u64 ios_title_id) const +bool ES::LaunchIOS(u64 ios_title_id) { return Reload(ios_title_id); } -bool ES::LaunchPPCTitle(u64 title_id, bool skip_reload) const +bool ES::LaunchPPCTitle(u64 title_id, bool skip_reload) { const DiscIO::CNANDContentLoader& content_loader = AccessContentDevice(title_id); if (!content_loader.IsValid()) @@ -115,52 +245,24 @@ bool ES::LaunchPPCTitle(u64 title_id, bool skip_reload) const // again with the reload skipped, and the PPC will be bootstrapped then. if (!skip_reload) { - SetTitleToLaunch(title_id); + s_title_to_launch = title_id; const u64 required_ios = content_loader.GetTMD().GetIOSId(); return LaunchTitle(required_ios); } - SetDefaultContentFile(Common::GetTitleContentPath(title_id, Common::FROM_SESSION_ROOT)); + s_title_context.Update(content_loader); + INFO_LOG(IOS_ES, "LaunchPPCTitle: Title context changed: %016" PRIx64, + s_title_context.tmd.GetTitleId()); return BootstrapPPC(content_loader); } -void ES::OpenInternal() -{ - auto& contentLoader = DiscIO::CNANDContentManager::Access().GetNANDLoader(m_ContentFile); - - // check for cd ... - if (contentLoader.IsValid()) - { - m_TitleID = contentLoader.GetTMD().GetTitleId(); - - m_TitleIDs.clear(); - DiscIO::cUIDsys uid_sys{Common::FromWhichRoot::FROM_SESSION_ROOT}; - uid_sys.GetTitleIDs(m_TitleIDs); - // uncomment if ES_GetOwnedTitlesCount / ES_GetOwnedTitles is implemented - // m_TitleIDsOwned.clear(); - // DiscIO::cUIDsys::AccessInstance().GetTitleIDs(m_TitleIDsOwned, true); - } - else if (DVDInterface::VolumeIsValid()) - { - // blindly grab the titleID from the disc - it's unencrypted at: - // offset 0x0F8001DC and 0x0F80044C - DVDInterface::GetVolume().GetTitleID(&m_TitleID); - } - else - { - m_TitleID = ((u64)0x00010000 << 32) | 0xF00DBEEF; - } - - INFO_LOG(IOS_ES, "Set default title to %08x/%08x", (u32)(m_TitleID >> 32), (u32)m_TitleID); -} - void ES::DoState(PointerWrap& p) { Device::DoState(p); - p.Do(m_ContentFile); - OpenInternal(); + p.Do(s_content_file); p.Do(m_AccessIdentID); - p.Do(m_TitleIDs); + p.Do(s_title_ids); + s_title_context.DoState(p); m_addtitle_tmd.DoState(p); p.Do(m_addtitle_content_id); @@ -197,8 +299,6 @@ void ES::DoState(PointerWrap& p) ReturnCode ES::Open(const OpenRequest& request) { - OpenInternal(); - if (m_is_active) INFO_LOG(IOS_ES, "Device was re-opened."); return Device::Open(request); @@ -206,9 +306,8 @@ ReturnCode ES::Open(const OpenRequest& request) void ES::Close() { + // XXX: does IOS really clear the content access map here? m_ContentAccessMap.clear(); - m_TitleIDs.clear(); - m_TitleID = -1; m_AccessIdentID = 0; INFO_LOG(IOS_ES, "ES: Close"); @@ -628,7 +727,10 @@ IPCCommandResult ES::OpenContent(const IOCtlVRequest& request) return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); u32 Index = Memory::Read_U32(request.in_vectors[0].address); - s32 CFD = OpenTitleContent(m_AccessIdentID++, m_TitleID, Index); + if (!s_title_context.active) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + s32 CFD = OpenTitleContent(m_AccessIdentID++, s_title_context.tmd.GetTitleId(), Index); INFO_LOG(IOS_ES, "IOCTL_ES_OPENCONTENT: Index %i -> got CFD %x", Index, CFD); return GetDefaultReply(CFD); @@ -771,8 +873,13 @@ IPCCommandResult ES::GetTitleID(const IOCtlVRequest& request) if (!request.HasNumberOfValidVectors(0, 1)) return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); - Memory::Write_U64(m_TitleID, request.io_vectors[0].address); - INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLEID: %08x/%08x", (u32)(m_TitleID >> 32), (u32)m_TitleID); + if (!s_title_context.active) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + const u64 title_id = s_title_context.tmd.GetTitleId(); + Memory::Write_U64(title_id, request.io_vectors[0].address); + INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLEID: %08x/%08x", static_cast(title_id >> 32), + static_cast(title_id)); return GetDefaultReply(IPC_SUCCESS); } @@ -792,9 +899,9 @@ IPCCommandResult ES::GetTitleCount(const IOCtlVRequest& request) if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != 4) return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); - Memory::Write_U32((u32)m_TitleIDs.size(), request.io_vectors[0].address); + Memory::Write_U32((u32)s_title_ids.size(), request.io_vectors[0].address); - INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLECNT: Number of Titles %zu", m_TitleIDs.size()); + INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLECNT: Number of Titles %zu", s_title_ids.size()); return GetDefaultReply(IPC_SUCCESS); } @@ -806,11 +913,11 @@ IPCCommandResult ES::GetTitles(const IOCtlVRequest& request) u32 MaxCount = Memory::Read_U32(request.in_vectors[0].address); u32 Count = 0; - for (int i = 0; i < (int)m_TitleIDs.size(); i++) + for (int i = 0; i < (int)s_title_ids.size(); i++) { - Memory::Write_U64(m_TitleIDs[i], request.io_vectors[0].address + i * 8); - INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLES: %08x/%08x", (u32)(m_TitleIDs[i] >> 32), - (u32)m_TitleIDs[i]); + Memory::Write_U64(s_title_ids[i], request.io_vectors[0].address + i * 8); + INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLES: %08x/%08x", (u32)(s_title_ids[i] >> 32), + (u32)s_title_ids[i]); Count++; if (Count >= MaxCount) break; @@ -1327,8 +1434,12 @@ 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 (!s_title_context.active) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + const EcWii& ec = EcWii::GetInstance(); - MakeAPSigAndCert(sig_out, ap_cert_out, m_TitleID, data, data_size, ec.GetNGPriv(), ec.GetNGID()); + MakeAPSigAndCert(sig_out, ap_cert_out, s_title_context.tmd.GetTitleId(), data, data_size, + ec.GetNGPriv(), ec.GetNGID()); return GetDefaultReply(IPC_SUCCESS); } @@ -1365,36 +1476,38 @@ IPCCommandResult ES::GetOwnedTitleCount(const IOCtlVRequest& request) return GetDefaultReply(IPC_SUCCESS); } -const DiscIO::CNANDContentLoader& ES::AccessContentDevice(u64 title_id) const +const DiscIO::CNANDContentLoader& ES::AccessContentDevice(u64 title_id) { - // for WADs, the passed title id and the stored title id match; along with m_ContentFile 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 (m_TitleID == title_id && !m_ContentFile.empty()) - return DiscIO::CNANDContentManager::Access().GetNANDLoader(m_ContentFile); + // 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::CNANDContentManager::Access().GetNANDLoader(s_content_file); + } return DiscIO::CNANDContentManager::Access().GetNANDLoader(title_id, Common::FROM_SESSION_ROOT); } -u32 ES::ES_DIVerify(const IOS::ES::TMDReader& tmd) +// This is technically an ioctlv in IOS's ES, but it is an internal API which cannot be +// used from the PowerPC (for unpatched IOSes anyway). +s32 ES::DIVerify(const IOS::ES::TMDReader& tmd, const IOS::ES::TicketReader& ticket) { - if (!tmd.IsValid()) - return -1; + s_title_context.Clear(); + INFO_LOG(IOS_ES, "ES_DIVerify: Title context changed: (none)"); - u64 title_id = 0xDEADBEEFDEADBEEFull; - u64 tmd_title_id = tmd.GetTitleId(); + if (!tmd.IsValid() || !ticket.IsValid()) + return ES_PARAMETER_SIZE_OR_ALIGNMENT; - DVDInterface::GetVolume().GetTitleID(&title_id); - if (title_id != tmd_title_id) - return -1; + if (tmd.GetTitleId() != ticket.GetTitleId()) + return ES_PARAMETER_SIZE_OR_ALIGNMENT; - std::string tmd_path = Common::GetTMDFileName(tmd_title_id, Common::FROM_SESSION_ROOT); + std::string tmd_path = Common::GetTMDFileName(tmd.GetTitleId(), Common::FROM_SESSION_ROOT); File::CreateFullPath(tmd_path); - File::CreateFullPath(Common::GetTitleDataPath(tmd_title_id, Common::FROM_SESSION_ROOT)); + File::CreateFullPath(Common::GetTitleDataPath(tmd.GetTitleId(), Common::FROM_SESSION_ROOT)); if (!File::Exists(tmd_path)) { @@ -1404,11 +1517,14 @@ u32 ES::ES_DIVerify(const IOS::ES::TMDReader& tmd) ERROR_LOG(IOS_ES, "DIVerify failed to write disc TMD to NAND."); } DiscIO::cUIDsys uid_sys{Common::FromWhichRoot::FROM_SESSION_ROOT}; - uid_sys.AddTitle(tmd_title_id); + uid_sys.AddTitle(tmd.GetTitleId()); // 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::CNANDContentManager::Access().ClearCache(); - return 0; + + s_title_context.Update(tmd, ticket); + INFO_LOG(IOS_ES, "ES_DIVerify: Title context changed: %016" PRIx64, tmd.GetTitleId()); + return IPC_SUCCESS; } } // namespace Device } // namespace HLE diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index 6521eaa360..8adb54e8e9 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -34,13 +34,15 @@ class ES : public Device public: ES(u32 device_id, const std::string& device_name); - void LoadWAD(const std::string& _rContentFile); - bool LaunchTitle(u64 title_id, bool skip_reload = false) const; + // Called after an IOS reload. + static void Init(); + + static s32 DIVerify(const IOS::ES::TMDReader& tmd, const IOS::ES::TicketReader& ticket); + static void LoadWAD(const std::string& _rContentFile); + static bool LaunchTitle(u64 title_id, bool skip_reload = false); // Internal implementation of the ES_DECRYPT ioctlv. - void DecryptContent(u32 key_index, u8* iv, u8* input, u32 size, u8* new_iv, u8* output); - - void OpenInternal(); + static void DecryptContent(u32 key_index, u8* iv, u8* input, u32 size, u8* new_iv, u8* output); void DoState(PointerWrap& p) override; @@ -48,11 +50,6 @@ public: void Close() override; IPCCommandResult IOCtlV(const IOCtlVRequest& request) override; - static u32 ES_DIVerify(const IOS::ES::TMDReader& tmd); - - // This should only be cleared on power reset - static std::string m_ContentFile; - private: enum { @@ -200,18 +197,16 @@ private: IPCCommandResult DIGetTicketView(const IOCtlVRequest& request); IPCCommandResult GetOwnedTitleCount(const IOCtlVRequest& request); - bool LaunchIOS(u64 ios_title_id) const; - bool LaunchPPCTitle(u64 title_id, bool skip_reload) const; + static bool LaunchIOS(u64 ios_title_id); + static bool LaunchPPCTitle(u64 title_id, bool skip_reload); - const DiscIO::CNANDContentLoader& AccessContentDevice(u64 title_id) const; + static const DiscIO::CNANDContentLoader& AccessContentDevice(u64 title_id); u32 OpenTitleContent(u32 CFD, u64 TitleID, u16 Index); using ContentAccessMap = std::map; ContentAccessMap m_ContentAccessMap; - std::vector m_TitleIDs; - u64 m_TitleID = -1; u32 m_AccessIdentID = 0; // For title installation (ioctls IOCTL_ES_ADDTITLE*). diff --git a/Source/Core/Core/IOS/ES/Formats.cpp b/Source/Core/Core/IOS/ES/Formats.cpp index 7e94798305..96a81004e5 100644 --- a/Source/Core/Core/IOS/ES/Formats.cpp +++ b/Source/Core/Core/IOS/ES/Formats.cpp @@ -126,6 +126,11 @@ u16 TMDReader::GetTitleVersion() const return Common::swap16(m_bytes.data() + offsetof(TMDHeader, title_version)); } +u16 TMDReader::GetGroupId() const +{ + return Common::swap16(m_bytes.data() + offsetof(TMDHeader, group_id)); +} + u16 TMDReader::GetNumContents() const { return Common::swap16(m_bytes.data() + offsetof(TMDHeader, num_contents)); @@ -212,6 +217,11 @@ bool TicketReader::IsValid() const return true; } +void TicketReader::DoState(PointerWrap& p) +{ + p.Do(m_bytes); +} + u32 TicketReader::GetNumberOfTickets() const { return static_cast(m_bytes.size() / (GetOffset() + sizeof(Ticket))); diff --git a/Source/Core/Core/IOS/ES/Formats.h b/Source/Core/Core/IOS/ES/Formats.h index 268506bec3..de31b78d0b 100644 --- a/Source/Core/Core/IOS/ES/Formats.h +++ b/Source/Core/Core/IOS/ES/Formats.h @@ -137,6 +137,7 @@ public: DiscIO::Region GetRegion() const; u64 GetTitleId() const; u16 GetTitleVersion() const; + u16 GetGroupId() const; u16 GetNumContents() const; bool GetContent(u16 index, Content* content) const; @@ -160,6 +161,7 @@ public: void SetBytes(std::vector&& bytes); bool IsValid() const; + void DoState(PointerWrap& p); const std::vector& GetRawTicket() const; u32 GetNumberOfTickets() const; diff --git a/Source/Core/Core/IOS/IPC.cpp b/Source/Core/Core/IOS/IPC.cpp index 1ebedf5d3d..e8bb80f1aa 100644 --- a/Source/Core/Core/IOS/IPC.cpp +++ b/Source/Core/Core/IOS/IPC.cpp @@ -95,7 +95,6 @@ static CoreTiming::EventType* s_event_sdio_notify; static u64 s_last_reply_time; static u64 s_active_title_id; -static u64 s_title_to_launch; static constexpr u64 ENQUEUE_REQUEST_FLAG = 0x100000000ULL; static constexpr u64 ENQUEUE_ACKNOWLEDGEMENT_FLAG = 0x200000000ULL; @@ -586,7 +585,6 @@ static void AddStaticDevices() { std::lock_guard lock(s_device_map_mutex); _assert_msg_(IOS, s_device_map.empty(), "Reinit called while already initialized"); - Device::ES::m_ContentFile = ""; num_devices = 0; @@ -706,20 +704,10 @@ bool Reload(const u64 ios_title_id) AddStaticDevices(); - if (s_title_to_launch != 0) - { - NOTICE_LOG(IOS, "Re-launching title after IOS reload."); - s_es_handles[0]->LaunchTitle(s_title_to_launch, true); - s_title_to_launch = 0; - } + Device::ES::Init(); return true; } -void SetTitleToLaunch(const u64 title_id) -{ - s_title_to_launch = title_id; -} - // 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 BootstrapPPC(const DiscIO::CNANDContentLoader& content_loader) @@ -749,18 +737,6 @@ bool BootstrapPPC(const DiscIO::CNANDContentLoader& content_loader) return true; } -void SetDefaultContentFile(const std::string& file_name) -{ - std::lock_guard lock(s_device_map_mutex); - for (const auto& es : s_es_handles) - es->LoadWAD(file_name); -} - -void ES_DIVerify(const ES::TMDReader& tmd) -{ - Device::ES::ES_DIVerify(tmd); -} - void SDIO_EventNotify() { // TODO: Potential race condition: If IsRunning() becomes false after diff --git a/Source/Core/Core/IOS/IPC.h b/Source/Core/Core/IOS/IPC.h index 39acad15fa..9bf4f9a24a 100644 --- a/Source/Core/Core/IOS/IPC.h +++ b/Source/Core/Core/IOS/IPC.h @@ -21,11 +21,6 @@ class CNANDContentLoader; namespace IOS { -namespace ES -{ -class TMDReader; -} - namespace HLE { namespace Device @@ -67,16 +62,10 @@ bool Reload(u64 ios_title_id); u32 GetVersion(); bool BootstrapPPC(const DiscIO::CNANDContentLoader& content_loader); -// This sets a title to launch after IOS has been reset and reloaded (similar to /sys/launch.sys). -void SetTitleToLaunch(u64 title_id); // Do State void DoState(PointerWrap& p); -// Set default content file -void SetDefaultContentFile(const std::string& file_name); -void ES_DIVerify(const ES::TMDReader& tmd); - void SDIO_EventNotify(); std::shared_ptr GetDeviceByName(const std::string& device_name); diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index f8ae519dc3..209afb1865 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -71,7 +71,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 = 78; // Last changed in PR 49XX +static const u32 STATE_VERSION = 79; // Last changed in PR 4981 // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list, diff --git a/Source/Core/DiscIO/Volume.h b/Source/Core/DiscIO/Volume.h index 1190565004..f3f530e5e4 100644 --- a/Source/Core/DiscIO/Volume.h +++ b/Source/Core/DiscIO/Volume.h @@ -37,6 +37,7 @@ public: } virtual bool GetTitleID(u64*) const { return false; } + virtual IOS::ES::TicketReader GetTicket() const { return {}; } virtual IOS::ES::TMDReader GetTMD() const { return {}; } virtual u64 PartitionOffsetToRawOffset(u64 offset) const { return offset; } virtual std::string GetGameID() const = 0; diff --git a/Source/Core/DiscIO/VolumeWiiCrypted.cpp b/Source/Core/DiscIO/VolumeWiiCrypted.cpp index ef291fa237..71e50252db 100644 --- a/Source/Core/DiscIO/VolumeWiiCrypted.cpp +++ b/Source/Core/DiscIO/VolumeWiiCrypted.cpp @@ -114,6 +114,13 @@ bool CVolumeWiiCrypted::GetTitleID(u64* buffer) const return true; } +IOS::ES::TicketReader CVolumeWiiCrypted::GetTicket() const +{ + std::vector buffer(0x2a4); + Read(m_VolumeOffset, buffer.size(), buffer.data(), false); + return IOS::ES::TicketReader{std::move(buffer)}; +} + IOS::ES::TMDReader CVolumeWiiCrypted::GetTMD() const { u32 tmd_size; diff --git a/Source/Core/DiscIO/VolumeWiiCrypted.h b/Source/Core/DiscIO/VolumeWiiCrypted.h index dfeb74ad66..d7e7c4bddb 100644 --- a/Source/Core/DiscIO/VolumeWiiCrypted.h +++ b/Source/Core/DiscIO/VolumeWiiCrypted.h @@ -33,6 +33,7 @@ public: ~CVolumeWiiCrypted(); bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, bool decrypt) const override; bool GetTitleID(u64* buffer) const override; + IOS::ES::TicketReader GetTicket() const override; IOS::ES::TMDReader GetTMD() const override; u64 PartitionOffsetToRawOffset(u64 offset) const override; std::string GetGameID() const override;