From 9263cb199676327c5f8fd0035583fc5ee8f782b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Mon, 27 Feb 2017 23:17:32 +0100 Subject: [PATCH 1/6] IOS/ES: Handle adding shared contents properly --- Source/Core/Core/IOS/ES/ES.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index 29499ad8a2..51306f5056 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -516,12 +516,22 @@ IPCCommandResult ES::AddContentFinish(const IOCtlVRequest& request) mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, m_addtitle_content_buffer.size(), iv, m_addtitle_content_buffer.data(), decrypted_data.data()); - std::string path = StringFromFormat( - "%s%08x.app", - Common::GetTitleContentPath(m_addtitle_tmd.GetTitleId(), Common::FROM_SESSION_ROOT).c_str(), - m_addtitle_content_id); + std::string content_path; + if (content_info.type & 0x8000) + { + // Shared content. + DiscIO::CSharedContent shared_content{Common::FROM_SESSION_ROOT}; + content_path = shared_content.AddSharedContent(content_info.sha1.data()); + } + else + { + content_path = StringFromFormat( + "%s%08x.app", + Common::GetTitleContentPath(m_addtitle_tmd.GetTitleId(), Common::FROM_SESSION_ROOT).c_str(), + m_addtitle_content_id); + } - File::IOFile fp(path, "wb"); + File::IOFile fp(content_path, "wb"); fp.WriteBytes(decrypted_data.data(), content_info.size); m_addtitle_content_id = 0xFFFFFFFF; From 1e3f8c1a1de022ff498ca4417b78398e8c79396c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Mon, 27 Feb 2017 23:20:30 +0100 Subject: [PATCH 2/6] IOS/ES: Add sanity checks to AddTitleFinish --- Source/Core/Core/IOS/ES/ES.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index 51306f5056..9bf1977bd8 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -540,10 +540,11 @@ IPCCommandResult ES::AddContentFinish(const IOCtlVRequest& request) IPCCommandResult ES::AddTitleFinish(const IOCtlVRequest& request) { - if (!request.HasNumberOfValidVectors(0, 0)) + if (!request.HasNumberOfValidVectors(0, 0) || !m_addtitle_tmd.IsValid()) return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); INFO_LOG(IOS_ES, "IOCTL_ES_ADDTITLEFINISH"); + m_addtitle_tmd.SetBytes({}); return GetDefaultReply(IPC_SUCCESS); } From e5d9bcaf431f610b388c8c6f6bf5a7da8ec22553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Mon, 27 Feb 2017 23:20:58 +0100 Subject: [PATCH 3/6] IOS/ES: Edit uid.sys on AddTitleStart This allows channels to be registered and installed properly. (And it is what IOS does.) --- 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 9bf1977bd8..2ad2a319b4 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -422,6 +422,9 @@ IPCCommandResult ES::AddTitleStart(const IOCtlVRequest& request) if (!WriteTMD(m_addtitle_tmd)) return GetDefaultReply(ES_WRITE_FAILURE); + DiscIO::cUIDsys uid_sys{Common::FROM_CONFIGURED_ROOT}; + uid_sys.AddTitle(m_addtitle_tmd.GetTitleId()); + return GetDefaultReply(IPC_SUCCESS); } From 90aaefaef79540cca951c73fd1023b4f820f44bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Mon, 27 Feb 2017 23:49:54 +0100 Subject: [PATCH 4/6] IOS/ES: Drop 'fake IOS titles' hack It prevents system updates from working properly, because we always returned that the latest version of every single IOS was installed. --- Source/Core/Core/IOS/ES/ES.cpp | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index 2ad2a319b4..d203c5b049 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -831,12 +831,7 @@ IPCCommandResult ES::GetViewCount(const IOCtlVRequest& request) const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); size_t view_count = 0; - if (TitleID >> 32 == 0x00000001 && TitleID != TITLEID_SYSMENU) - { - // Fake a ticket view to make IOS reload work. - view_count = 1; - } - else if (Loader.IsValid() && Loader.GetTicket().IsValid()) + if (Loader.IsValid() && Loader.GetTicket().IsValid()) { view_count = Loader.GetTicket().GetNumberOfTickets(); } @@ -858,20 +853,7 @@ IPCCommandResult ES::GetViews(const IOCtlVRequest& request) const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); - if (TitleID >> 32 == 0x00000001 && TitleID != TITLEID_SYSMENU) - { - // For IOS titles, the ticket view isn't normally parsed by either the - // SDK or libogc, just passed to LaunchTitle, so this - // shouldn't matter at all. Just fill out some fields just - // to be on the safe side. - u32 Address = request.io_vectors[0].address; - Memory::Memset(Address, 0, 0xD8); - Memory::Write_U64(TitleID, Address + 4 + (0x1dc - 0x1d0)); // title ID - Memory::Write_U16(0xffff, Address + 4 + (0x1e4 - 0x1d0)); // unnnown - Memory::Write_U32(0xff00, Address + 4 + (0x1ec - 0x1d0)); // access mask - Memory::Memset(Address + 4 + (0x222 - 0x1d0), 0xff, 0x20); // content permissions - } - else if (Loader.IsValid() && Loader.GetTicket().IsValid()) + if (Loader.IsValid() && Loader.GetTicket().IsValid()) { u32 number_of_views = std::min(maxViews, Loader.GetTicket().GetNumberOfTickets()); for (u32 view = 0; view < number_of_views; ++view) From 3bd34008c9c402db2838c9846d3e94d4577451d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Tue, 28 Feb 2017 00:04:47 +0100 Subject: [PATCH 5/6] IOS/ES: Fix GetTMDView when title doesn't exist This fixes ES_GetTMDView and ES_GetTMDViewSize to return -106 (FS_ENOENT) if the title does not exist (and more specifically when no TMD exists in the NAND). This allows installed (or not installed) IOSes to be detected properly. --- Source/Core/Core/IOS/ES/ES.cpp | 26 +++++++++++++------------- Source/Core/Core/IOS/ES/ES.h | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index d203c5b049..1a75f1c21f 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -303,7 +303,7 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request) case IOCTL_ES_GETVIEWS: return GetViews(request); case IOCTL_ES_GETTMDVIEWCNT: - return GetTMDViewCount(request); + return GetTMDViewSize(request); case IOCTL_ES_GETTMDVIEWS: return GetTMDViews(request); case IOCTL_ES_GETCONSUMPTION: @@ -870,8 +870,7 @@ IPCCommandResult ES::GetViews(const IOCtlVRequest& request) return GetDefaultReply(IPC_SUCCESS); } -// TODO: rename this to GetTMDViewSize. There is only one TMD, so the name doesn't make sense. -IPCCommandResult ES::GetTMDViewCount(const IOCtlVRequest& request) +IPCCommandResult ES::GetTMDViewSize(const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(1, 1)) return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); @@ -880,9 +879,10 @@ IPCCommandResult ES::GetTMDViewCount(const IOCtlVRequest& request) const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); - u32 view_size = 0; - if (Loader.IsValid()) - view_size = static_cast(Loader.GetTMD().GetRawView().size()); + if (!Loader.IsValid()) + return GetDefaultReply(FS_ENOENT); + + const u32 view_size = static_cast(Loader.GetTMD().GetRawView().size()); Memory::Write_U32(view_size, request.io_vectors[0].address); INFO_LOG(IOS_ES, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x (view size %i)", (u32)(TitleID >> 32), @@ -903,14 +903,14 @@ IPCCommandResult ES::GetTMDViews(const IOCtlVRequest& request) INFO_LOG(IOS_ES, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x buffer size: %i", (u32)(TitleID >> 32), (u32)TitleID, MaxCount); - if (Loader.IsValid()) - { - const std::vector raw_view = Loader.GetTMD().GetRawView(); - if (raw_view.size() != request.io_vectors[0].size) - return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + if (!Loader.IsValid()) + return GetDefaultReply(FS_ENOENT); - Memory::CopyToEmu(request.io_vectors[0].address, raw_view.data(), raw_view.size()); - } + const std::vector raw_view = Loader.GetTMD().GetRawView(); + if (raw_view.size() != request.io_vectors[0].size) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + Memory::CopyToEmu(request.io_vectors[0].address, raw_view.data(), raw_view.size()); INFO_LOG(IOS_ES, "IOCTL_ES_GETTMDVIEWS: title: %08x/%08x (buffer size: %i)", (u32)(TitleID >> 32), (u32)TitleID, MaxCount); diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index 30348749d5..6521eaa360 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -174,7 +174,7 @@ private: IPCCommandResult GetTitles(const IOCtlVRequest& request); IPCCommandResult GetViewCount(const IOCtlVRequest& request); IPCCommandResult GetViews(const IOCtlVRequest& request); - IPCCommandResult GetTMDViewCount(const IOCtlVRequest& request); + IPCCommandResult GetTMDViewSize(const IOCtlVRequest& request); IPCCommandResult GetTMDViews(const IOCtlVRequest& request); IPCCommandResult GetConsumption(const IOCtlVRequest& request); IPCCommandResult DeleteTitle(const IOCtlVRequest& request); From ac27aff9c8c7ba52bbf067ea7933b6b1f8ca4619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Tue, 28 Feb 2017 17:24:02 +0100 Subject: [PATCH 6/6] Add ES::Content::IsShared to avoid hardcoding 0x8000 --- Source/Core/Core/IOS/ES/ES.cpp | 3 +-- Source/Core/Core/IOS/ES/Formats.cpp | 5 +++++ Source/Core/Core/IOS/ES/Formats.h | 1 + Source/Core/DiscIO/NANDContentLoader.cpp | 6 +++--- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index 1a75f1c21f..79a69e2317 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -520,9 +520,8 @@ IPCCommandResult ES::AddContentFinish(const IOCtlVRequest& request) m_addtitle_content_buffer.data(), decrypted_data.data()); std::string content_path; - if (content_info.type & 0x8000) + if (content_info.IsShared()) { - // Shared content. DiscIO::CSharedContent shared_content{Common::FROM_SESSION_ROOT}; content_path = shared_content.AddSharedContent(content_info.sha1.data()); } diff --git a/Source/Core/Core/IOS/ES/Formats.cpp b/Source/Core/Core/IOS/ES/Formats.cpp index 38e285285c..7e94798305 100644 --- a/Source/Core/Core/IOS/ES/Formats.cpp +++ b/Source/Core/Core/IOS/ES/Formats.cpp @@ -26,6 +26,11 @@ bool IsTitleType(u64 title_id, TitleType title_type) return static_cast(title_id >> 32) == static_cast(title_type); } +bool Content::IsShared() const +{ + return (type & 0x8000) != 0; +} + TMDReader::TMDReader(const std::vector& bytes) : m_bytes(bytes) { } diff --git a/Source/Core/Core/IOS/ES/Formats.h b/Source/Core/Core/IOS/ES/Formats.h index 297a18abda..268506bec3 100644 --- a/Source/Core/Core/IOS/ES/Formats.h +++ b/Source/Core/Core/IOS/ES/Formats.h @@ -61,6 +61,7 @@ static_assert(sizeof(TMDHeader) == 0x1e4, "TMDHeader has the wrong size"); struct Content { + bool IsShared() const; u32 id; u16 index; u16 type; diff --git a/Source/Core/DiscIO/NANDContentLoader.cpp b/Source/Core/DiscIO/NANDContentLoader.cpp index 02a2462ab9..914e23191e 100644 --- a/Source/Core/DiscIO/NANDContentLoader.cpp +++ b/Source/Core/DiscIO/NANDContentLoader.cpp @@ -260,7 +260,7 @@ void CNANDContentLoader::InitializeContentEntries(const std::vector& data_ap else { std::string filename; - if (content.type & 0x8000) // shared app + if (content.IsShared()) filename = shared_content.GetFilenameFromSHA1(content.sha1.data()); else filename = StringFromFormat("%s/%08x.app", m_Path.c_str(), content.id); @@ -317,7 +317,7 @@ void CNANDContentLoader::RemoveTitle() const // remove TMD? for (const auto& content : m_Content) { - if (!(content.m_metadata.type & 0x8000)) // skip shared apps + if (!content.m_metadata.IsShared()) { std::string path = StringFromFormat("%s/%08x.app", m_Path.c_str(), content.m_metadata.id); INFO_LOG(DISCIO, "Delete %s", path.c_str()); @@ -430,7 +430,7 @@ u64 CNANDContentManager::Install_WiiWAD(const std::string& filename) for (const auto& content : content_loader.GetContent()) { std::string app_filename; - if (content.m_metadata.type & 0x8000) // shared + if (content.m_metadata.IsShared()) app_filename = shared_content.AddSharedContent(content.m_metadata.sha1.data()); else app_filename = StringFromFormat("%s%08x.app", content_path.c_str(), content.m_metadata.id);