From 5049451a8590490dd1b0242278e40399986d1b8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 5 Mar 2017 01:57:12 +0100 Subject: [PATCH] IOS/ES: Implement ES_DIGetTMDView (and GetTMDViewSize) This is required for online updates to work in the system menu. --- Source/Core/Core/IOS/ES/ES.cpp | 98 +++++++++++++++++++++++++++++++++- Source/Core/Core/IOS/ES/ES.h | 11 ++-- 2 files changed, 104 insertions(+), 5 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index 0a65a21318..4c2e26a373 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -397,10 +397,19 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request) return GetViewCount(request); case IOCTL_ES_GETVIEWS: return GetViews(request); + case IOCTL_ES_DIGETTICKETVIEW: + return DIGetTicketView(request); + case IOCTL_ES_GETTMDVIEWCNT: return GetTMDViewSize(request); case IOCTL_ES_GETTMDVIEWS: return GetTMDViews(request); + + case IOCTL_ES_DIGETTMDVIEWSIZE: + return DIGetTMDViewSize(request); + case IOCTL_ES_DIGETTMDVIEW: + return DIGetTMDView(request); + case IOCTL_ES_GETCONSUMPTION: return GetConsumption(request); case IOCTL_ES_DELETETITLE: @@ -439,8 +448,6 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request) return Sign(request); case IOCTL_ES_GETBOOT2VERSION: return GetBoot2Version(request); - case IOCTL_ES_DIGETTICKETVIEW: - return DIGetTicketView(request); default: request.DumpUnknown(GetDeviceName(), LogTypes::IOS); break; @@ -1104,6 +1111,93 @@ IPCCommandResult ES::GetTMDViews(const IOCtlVRequest& request) return GetDefaultReply(IPC_SUCCESS); } +IPCCommandResult ES::DIGetTMDViewSize(const IOCtlVRequest& request) +{ + if (!request.HasNumberOfValidVectors(1, 1)) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + // Sanity check the TMD size. + if (request.in_vectors[0].size >= 4 * 1024 * 1024) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + if (request.io_vectors[0].size != sizeof(u32)) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + const bool has_tmd = request.in_vectors[0].size != 0; + size_t tmd_view_size = 0; + + if (has_tmd) + { + std::vector tmd_bytes(request.in_vectors[0].size); + Memory::CopyFromEmu(tmd_bytes.data(), request.in_vectors[0].address, tmd_bytes.size()); + const IOS::ES::TMDReader tmd{std::move(tmd_bytes)}; + + // Yes, this returns -1017, not ES_INVALID_TMD. + // IOS simply checks whether the TMD has all required content entries. + if (!tmd.IsValid()) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + tmd_view_size = tmd.GetRawView().size(); + } + else + { + // If no TMD was passed in and no title is active, IOS returns -1017. + if (!s_title_context.active) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + tmd_view_size = s_title_context.tmd.GetRawView().size(); + } + + Memory::Write_U32(static_cast(tmd_view_size), request.io_vectors[0].address); + return GetDefaultReply(IPC_SUCCESS); +} + +IPCCommandResult ES::DIGetTMDView(const IOCtlVRequest& request) +{ + if (!request.HasNumberOfValidVectors(2, 1)) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + // Sanity check the TMD size. + if (request.in_vectors[0].size >= 4 * 1024 * 1024) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + // Check whether the TMD view size is consistent. + if (request.in_vectors[1].size != sizeof(u32) || + Memory::Read_U32(request.in_vectors[1].address) != request.io_vectors[0].size) + { + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + } + + const bool has_tmd = request.in_vectors[0].size != 0; + std::vector tmd_view; + + if (has_tmd) + { + std::vector tmd_bytes(request.in_vectors[0].size); + Memory::CopyFromEmu(tmd_bytes.data(), request.in_vectors[0].address, tmd_bytes.size()); + const IOS::ES::TMDReader tmd{std::move(tmd_bytes)}; + + if (!tmd.IsValid()) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + tmd_view = tmd.GetRawView(); + } + else + { + // If no TMD was passed in and no title is active, IOS returns -1017. + if (!s_title_context.active) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + tmd_view = s_title_context.tmd.GetRawView(); + } + + if (tmd_view.size() != request.io_vectors[0].size) + return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT); + + Memory::CopyToEmu(request.io_vectors[0].address, tmd_view.data(), tmd_view.size()); + return GetDefaultReply(IPC_SUCCESS); +} + IPCCommandResult ES::GetConsumption(const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(1, 2)) diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index 49278c4d88..24b7d172ee 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -77,8 +77,8 @@ private: IOCTL_ES_GETCONSUMPTION = 0x16, IOCTL_ES_DELETETITLE = 0x17, IOCTL_ES_DELETETICKET = 0x18, - // IOCTL_ES_DIGETTMDVIEWSIZE = 0x19, - // IOCTL_ES_DIGETTMDVIEW = 0x1A, + IOCTL_ES_DIGETTMDVIEWSIZE = 0x19, + IOCTL_ES_DIGETTMDVIEW = 0x1A, IOCTL_ES_DIGETTICKETVIEW = 0x1B, IOCTL_ES_DIVERIFY = 0x1C, IOCTL_ES_GETTITLEDIR = 0x1D, @@ -177,8 +177,14 @@ private: IPCCommandResult GetViewCount(const IOCtlVRequest& request); IPCCommandResult GetViews(const IOCtlVRequest& request); + IPCCommandResult DIGetTicketView(const IOCtlVRequest& request); + IPCCommandResult GetTMDViewSize(const IOCtlVRequest& request); IPCCommandResult GetTMDViews(const IOCtlVRequest& request); + + IPCCommandResult DIGetTMDViewSize(const IOCtlVRequest& request); + IPCCommandResult DIGetTMDView(const IOCtlVRequest& request); + IPCCommandResult GetConsumption(const IOCtlVRequest& request); IPCCommandResult DeleteTitle(const IOCtlVRequest& request); IPCCommandResult DeleteTicket(const IOCtlVRequest& request); @@ -200,7 +206,6 @@ private: IPCCommandResult GetDeviceCertificate(const IOCtlVRequest& request); IPCCommandResult Sign(const IOCtlVRequest& request); IPCCommandResult GetBoot2Version(const IOCtlVRequest& request); - IPCCommandResult DIGetTicketView(const IOCtlVRequest& request); static bool LaunchIOS(u64 ios_title_id); static bool LaunchPPCTitle(u64 title_id, bool skip_reload);