diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index a8d72b96a8..ef3864bcf8 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -158,6 +158,21 @@ IPCCommandResult ES::GetTitleID(const IOCtlVRequest& request) return GetDefaultReply(IPC_SUCCESS); } +static bool UpdateUIDAndGID(const IOS::ES::TMDReader& tmd) +{ + IOS::ES::UIDSys uid_sys{Common::FromWhichRoot::FROM_SESSION_ROOT}; + const u64 title_id = tmd.GetTitleId(); + const u32 uid = uid_sys.GetOrInsertUIDForTitle(title_id); + if (!uid) + { + ERROR_LOG(IOS_ES, "Failed to get UID for title %016" PRIx64, title_id); + return false; + } + SetUIDForPPC(uid); + SetGIDForPPC(tmd.GetGroupId()); + return true; +} + IPCCommandResult ES::SetUID(const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(1, 0)) @@ -226,6 +241,16 @@ bool ES::LaunchPPCTitle(u64 title_id, bool skip_reload) s_title_context.Update(content_loader); INFO_LOG(IOS_ES, "LaunchPPCTitle: Title context changed: %016" PRIx64, s_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(s_title_context.tmd)) + { + s_title_context.Clear(); + INFO_LOG(IOS_ES, "LaunchPPCTitle: Title context changed: (none)"); + return false; + } + return BootstrapPPC(content_loader); } @@ -533,6 +558,9 @@ 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); + 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); File::CreateFullPath(tmd_path); @@ -545,14 +573,15 @@ 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."); } - IOS::ES::UIDSys uid_sys{Common::FromWhichRoot::FROM_SESSION_ROOT}; - 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(); - s_title_context.Update(tmd, ticket); - INFO_LOG(IOS_ES, "ES_DIVerify: Title context changed: %016" PRIx64, tmd.GetTitleId()); + if (!UpdateUIDAndGID(s_title_context.tmd)) + { + return ES_SHORT_READ; + } + return IPC_SUCCESS; } } // namespace Device diff --git a/Source/Core/Core/IOS/ES/Formats.cpp b/Source/Core/Core/IOS/ES/Formats.cpp index e4da96e2d0..d57bffb460 100644 --- a/Source/Core/Core/IOS/ES/Formats.cpp +++ b/Source/Core/Core/IOS/ES/Formats.cpp @@ -446,11 +446,11 @@ UIDSys::UIDSys(Common::FromWhichRoot root) if (m_entries.empty()) { - AddTitle(TITLEID_SYSMENU); + GetOrInsertUIDForTitle(TITLEID_SYSMENU); } } -u32 UIDSys::GetUIDFromTitle(u64 title_id) +u32 UIDSys::GetUIDFromTitle(u64 title_id) const { const auto it = std::find_if(m_entries.begin(), m_entries.end(), [title_id](const auto& entry) { return entry.second == title_id; }); @@ -464,26 +464,33 @@ u32 UIDSys::GetNextUID() const return m_entries.rbegin()->first + 1; } -void UIDSys::AddTitle(u64 title_id) +u32 UIDSys::GetOrInsertUIDForTitle(const u64 title_id) { - if (GetUIDFromTitle(title_id)) + const u32 current_uid = GetUIDFromTitle(title_id); + if (current_uid) { INFO_LOG(IOS_ES, "Title %016" PRIx64 " already exists in uid.sys", title_id); - return; + return current_uid; } - u32 uid = GetNextUID(); + const u32 uid = GetNextUID(); m_entries.insert({uid, title_id}); // Byte swap before writing. - title_id = Common::swap64(title_id); - uid = Common::swap32(uid); + const u64 swapped_title_id = Common::swap64(title_id); + const u32 swapped_uid = Common::swap32(uid); File::CreateFullPath(m_file_path); File::IOFile file(m_file_path, "ab"); - if (!file.WriteBytes(&title_id, sizeof(title_id)) || !file.WriteBytes(&uid, sizeof(uid))) + if (!file.WriteBytes(&swapped_title_id, sizeof(title_id)) || + !file.WriteBytes(&swapped_uid, sizeof(uid))) + { ERROR_LOG(IOS_ES, "Failed to write to /sys/uid.sys"); + return 0; + } + + return uid; } } // namespace ES } // namespace IOS diff --git a/Source/Core/Core/IOS/ES/Formats.h b/Source/Core/Core/IOS/ES/Formats.h index d073544ad1..691babdc9b 100644 --- a/Source/Core/Core/IOS/ES/Formats.h +++ b/Source/Core/Core/IOS/ES/Formats.h @@ -219,8 +219,8 @@ class UIDSys final public: explicit UIDSys(Common::FromWhichRoot root); - u32 GetUIDFromTitle(u64 title_id); - void AddTitle(u64 title_id); + u32 GetUIDFromTitle(u64 title_id) const; + u32 GetOrInsertUIDForTitle(u64 title_id); u32 GetNextUID() const; private: diff --git a/Source/Core/Core/IOS/ES/NandUtils.cpp b/Source/Core/Core/IOS/ES/NandUtils.cpp index 7d60f5c5e6..fd586010e5 100644 --- a/Source/Core/Core/IOS/ES/NandUtils.cpp +++ b/Source/Core/Core/IOS/ES/NandUtils.cpp @@ -194,7 +194,7 @@ bool InitImport(u64 title_id) } UIDSys uid_sys{Common::FROM_CONFIGURED_ROOT}; - uid_sys.AddTitle(title_id); + uid_sys.GetOrInsertUIDForTitle(title_id); // IOS moves the title content directory to /import if the TMD exists during an import. if (File::Exists(Common::GetTMDFileName(title_id, Common::FROM_SESSION_ROOT))) diff --git a/Source/Core/Core/IOS/IPC.cpp b/Source/Core/Core/IOS/IPC.cpp index bfbcf7c4b6..00d20877f9 100644 --- a/Source/Core/Core/IOS/IPC.cpp +++ b/Source/Core/Core/IOS/IPC.cpp @@ -91,6 +91,9 @@ static u64 s_last_reply_time; static u64 s_active_title_id; +static u32 s_ppc_uid; +static u16 s_ppc_gid; + static constexpr u64 ENQUEUE_REQUEST_FLAG = 0x100000000ULL; static constexpr u64 ENQUEUE_ACKNOWLEDGEMENT_FLAG = 0x200000000ULL; @@ -702,6 +705,28 @@ bool Reload(const u64 ios_title_id) return true; } +// Since we don't have actual processes, we keep track of only the PPC's UID/GID. +// These functions roughly correspond to syscalls 0x2b, 0x2c, 0x2d, 0x2e (though only for the PPC). +void SetUIDForPPC(u32 uid) +{ + s_ppc_uid = uid; +} + +u32 GetUIDForPPC() +{ + return s_ppc_uid; +} + +void SetGIDForPPC(u16 gid) +{ + s_ppc_gid = gid; +} + +u16 GetGIDForPPC() +{ + return s_ppc_gid; +} + // 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) @@ -783,6 +808,8 @@ void DoState(PointerWrap& p) p.Do(s_reply_queue); p.Do(s_last_reply_time); p.Do(s_active_title_id); + p.Do(s_ppc_uid); + p.Do(s_ppc_gid); if (s_active_title_id == MIOS_TITLE_ID) return; diff --git a/Source/Core/Core/IOS/IPC.h b/Source/Core/Core/IOS/IPC.h index e35608de0c..0d9e93ad70 100644 --- a/Source/Core/Core/IOS/IPC.h +++ b/Source/Core/Core/IOS/IPC.h @@ -59,6 +59,11 @@ void Shutdown(); bool Reload(u64 ios_title_id); u32 GetVersion(); +void SetUIDForPPC(u32 uid); +u32 GetUIDForPPC(); +void SetGIDForPPC(u16 gid); +u16 GetGIDForPPC(); + bool BootstrapPPC(const DiscIO::CNANDContentLoader& content_loader); // Do State diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 28d41b5961..1d1f92cd2f 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 = 79; // Last changed in PR 4981 +static const u32 STATE_VERSION = 80; // Last changed in PR 5309 // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list, diff --git a/Source/Core/DiscIO/NANDContentLoader.cpp b/Source/Core/DiscIO/NANDContentLoader.cpp index 58594d6fc5..79242d1307 100644 --- a/Source/Core/DiscIO/NANDContentLoader.cpp +++ b/Source/Core/DiscIO/NANDContentLoader.cpp @@ -336,7 +336,7 @@ u64 CNANDContentManager::Install_WiiWAD(const std::string& filename) } IOS::ES::UIDSys uid_sys{Common::FromWhichRoot::FROM_CONFIGURED_ROOT}; - uid_sys.AddTitle(title_id); + uid_sys.GetOrInsertUIDForTitle(title_id); ClearCache();