From f750208aa31a860414fc877346ed17001c0df512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 14 Feb 2021 00:58:27 +0100 Subject: [PATCH] IOS/ES: Emulate FS timings for content wrapper IPC commands Filesystem accesses aren't magically faster when they are done by ES, so this commit changes our content wrapper IPC commands to take FS access times and read operations into account. This should make content read timings a lot more accurate and closer to console. Note that the accuracy of the timings are limited to the accuracy of the emulated FS timings, and currently performance differences between IOS9-IOS28 and newer IOS versions are not emulated. Part 1 of fixing https://bugs.dolphin-emu.org/issues/11346 (part 2 will involve emulating those differences) --- Source/Core/Core/IOS/ES/ES.h | 10 +- Source/Core/Core/IOS/ES/TitleContents.cpp | 122 +++++++++++--------- Source/Core/Core/IOS/ES/TitleManagement.cpp | 2 +- 3 files changed, 71 insertions(+), 63 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index 4e2d0fa8d9..10af9fbd02 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -105,10 +105,10 @@ public: std::vector> GetSharedContents() const; // Title contents - s32 OpenContent(const ES::TMDReader& tmd, u16 content_index, u32 uid); - ReturnCode CloseContent(u32 cfd, u32 uid); - s32 ReadContent(u32 cfd, u8* buffer, u32 size, u32 uid); - s32 SeekContent(u32 cfd, u32 offset, SeekMode mode, u32 uid); + s32 OpenContent(const ES::TMDReader& tmd, u16 content_index, u32 uid, Ticks ticks = {}); + s32 CloseContent(u32 cfd, u32 uid, Ticks ticks = {}); + s32 ReadContent(u32 cfd, u8* buffer, u32 size, u32 uid, Ticks ticks = {}); + s32 SeekContent(u32 cfd, u32 offset, SeekMode mode, u32 uid, Ticks ticks = {}); // Title management enum class TicketImportType @@ -371,7 +371,7 @@ private: struct OpenedContent { bool m_opened = false; - FS::Fd m_fd; + u64 m_fd; u64 m_title_id = 0; ES::Content m_content; u32 m_uid = 0; diff --git a/Source/Core/Core/IOS/ES/TitleContents.cpp b/Source/Core/Core/IOS/ES/TitleContents.cpp index 547df70eaf..9a68475743 100644 --- a/Source/Core/Core/IOS/ES/TitleContents.cpp +++ b/Source/Core/Core/IOS/ES/TitleContents.cpp @@ -4,18 +4,17 @@ #include "Core/IOS/ES/ES.h" -#include #include #include "Common/Logging/Log.h" -#include "Common/MsgHandler.h" #include "Core/HW/Memmap.h" #include "Core/IOS/ES/Formats.h" +#include "Core/IOS/FS/FileSystemProxy.h" #include "Core/IOS/Uids.h" namespace IOS::HLE { -s32 ESDevice::OpenContent(const ES::TMDReader& tmd, u16 content_index, u32 uid) +s32 ESDevice::OpenContent(const ES::TMDReader& tmd, u16 content_index, u32 uid, Ticks ticks) { const u64 title_id = tmd.GetTitleId(); @@ -29,13 +28,13 @@ s32 ESDevice::OpenContent(const ES::TMDReader& tmd, u16 content_index, u32 uid) if (entry.m_opened) continue; - auto file = m_ios.GetFS()->OpenFile(PID_KERNEL, PID_KERNEL, GetContentPath(title_id, content), - FS::Mode::Read); - if (!file) - return FS::ConvertResult(file.Error()); + const std::string path = GetContentPath(title_id, content, ticks); + s64 fd = m_ios.GetFSDevice()->Open(PID_KERNEL, PID_KERNEL, path, FS::Mode::Read, {}, ticks); + if (fd < 0) + return fd; entry.m_opened = true; - entry.m_fd = file->Release(); + entry.m_fd = fd; entry.m_content = content; entry.m_title_id = title_id; entry.m_uid = uid; @@ -50,43 +49,48 @@ s32 ESDevice::OpenContent(const ES::TMDReader& tmd, u16 content_index, u32 uid) IPCReply ESDevice::OpenContent(u32 uid, const IOCtlVRequest& request) { - if (!request.HasNumberOfValidVectors(3, 0) || request.in_vectors[0].size != sizeof(u64) || - request.in_vectors[1].size != sizeof(ES::TicketView) || - request.in_vectors[2].size != sizeof(u32)) - { - return IPCReply(ES_EINVAL); - } + return MakeIPCReply(IPC_OVERHEAD_TICKS, [&](Ticks ticks) -> s32 { + if (!request.HasNumberOfValidVectors(3, 0) || request.in_vectors[0].size != sizeof(u64) || + request.in_vectors[1].size != sizeof(ES::TicketView) || + request.in_vectors[2].size != sizeof(u32)) + { + return ES_EINVAL; + } - const u64 title_id = Memory::Read_U64(request.in_vectors[0].address); - const u32 content_index = Memory::Read_U32(request.in_vectors[2].address); - // TODO: check the ticket view, check permissions. + const u64 title_id = Memory::Read_U64(request.in_vectors[0].address); + const u32 content_index = Memory::Read_U32(request.in_vectors[2].address); + // TODO: check the ticket view, check permissions. - const auto tmd = FindInstalledTMD(title_id); - if (!tmd.IsValid()) - return IPCReply(FS_ENOENT); + const auto tmd = FindInstalledTMD(title_id, ticks); + if (!tmd.IsValid()) + return FS_ENOENT; - return IPCReply(OpenContent(tmd, content_index, uid)); + return OpenContent(tmd, content_index, uid, ticks); + }); } IPCReply ESDevice::OpenActiveTitleContent(u32 caller_uid, const IOCtlVRequest& request) { - if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u32)) - return IPCReply(ES_EINVAL); + return MakeIPCReply(IPC_OVERHEAD_TICKS, [&](Ticks ticks) -> s32 { + if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u32)) + return ES_EINVAL; - const u32 content_index = Memory::Read_U32(request.in_vectors[0].address); + const u32 content_index = Memory::Read_U32(request.in_vectors[0].address); - if (!m_title_context.active) - return IPCReply(ES_EINVAL); + if (!m_title_context.active) + return ES_EINVAL; - ES::UIDSys uid_map{m_ios.GetFSDevice()}; - const u32 uid = uid_map.GetOrInsertUIDForTitle(m_title_context.tmd.GetTitleId()); - if (caller_uid != 0 && caller_uid != uid) - return IPCReply(ES_EACCES); + ES::UIDSys uid_map{m_ios.GetFSDevice()}; + const u32 uid = uid_map.GetOrInsertUIDForTitle(m_title_context.tmd.GetTitleId()); + ticks.Add(uid_map.GetTicks()); + if (caller_uid != 0 && caller_uid != uid) + return ES_EACCES; - return IPCReply(OpenContent(m_title_context.tmd, content_index, caller_uid)); + return OpenContent(m_title_context.tmd, content_index, caller_uid, ticks); + }); } -s32 ESDevice::ReadContent(u32 cfd, u8* buffer, u32 size, u32 uid) +s32 ESDevice::ReadContent(u32 cfd, u8* buffer, u32 size, u32 uid, Ticks ticks) { if (cfd >= m_content_table.size()) return ES_EINVAL; @@ -97,25 +101,26 @@ s32 ESDevice::ReadContent(u32 cfd, u8* buffer, u32 size, u32 uid) if (!entry.m_opened) return IPC_EINVAL; - const auto result = m_ios.GetFS()->ReadBytesFromFile(entry.m_fd, buffer, size); - return result.Succeeded() ? *result : FS::ConvertResult(result.Error()); + return m_ios.GetFSDevice()->Read(entry.m_fd, buffer, size, {}, ticks); } IPCReply ESDevice::ReadContent(u32 uid, const IOCtlVRequest& request) { - if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32)) - return IPCReply(ES_EINVAL); + return MakeIPCReply(IPC_OVERHEAD_TICKS, [&](Ticks ticks) -> s32 { + if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32)) + return ES_EINVAL; - const u32 cfd = Memory::Read_U32(request.in_vectors[0].address); - const u32 size = request.io_vectors[0].size; - const u32 addr = request.io_vectors[0].address; + const u32 cfd = Memory::Read_U32(request.in_vectors[0].address); + const u32 size = request.io_vectors[0].size; + const u32 addr = request.io_vectors[0].address; - INFO_LOG_FMT(IOS_ES, "ReadContent(uid={:#x}, cfd={}, size={}, addr={:08x})", uid, cfd, size, - addr); - return IPCReply(ReadContent(cfd, Memory::GetPointer(addr), size, uid)); + INFO_LOG_FMT(IOS_ES, "ReadContent(uid={:#x}, cfd={}, size={}, addr={:08x})", uid, cfd, size, + addr); + return ReadContent(cfd, Memory::GetPointer(addr), size, uid, ticks); + }); } -ReturnCode ESDevice::CloseContent(u32 cfd, u32 uid) +s32 ESDevice::CloseContent(u32 cfd, u32 uid, Ticks ticks) { if (cfd >= m_content_table.size()) return ES_EINVAL; @@ -126,7 +131,7 @@ ReturnCode ESDevice::CloseContent(u32 cfd, u32 uid) if (!entry.m_opened) return IPC_EINVAL; - m_ios.GetFS()->Close(entry.m_fd); + m_ios.GetFSDevice()->Close(entry.m_fd, ticks); entry = {}; INFO_LOG_FMT(IOS_ES, "CloseContent: CFD {}", cfd); return IPC_SUCCESS; @@ -134,14 +139,16 @@ ReturnCode ESDevice::CloseContent(u32 cfd, u32 uid) IPCReply ESDevice::CloseContent(u32 uid, const IOCtlVRequest& request) { - if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u32)) - return IPCReply(ES_EINVAL); + return MakeIPCReply(IPC_OVERHEAD_TICKS, [&](Ticks ticks) -> s32 { + if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u32)) + return ES_EINVAL; - const u32 cfd = Memory::Read_U32(request.in_vectors[0].address); - return IPCReply(CloseContent(cfd, uid)); + const u32 cfd = Memory::Read_U32(request.in_vectors[0].address); + return CloseContent(cfd, uid, ticks); + }); } -s32 ESDevice::SeekContent(u32 cfd, u32 offset, SeekMode mode, u32 uid) +s32 ESDevice::SeekContent(u32 cfd, u32 offset, SeekMode mode, u32 uid, Ticks ticks) { if (cfd >= m_content_table.size()) return ES_EINVAL; @@ -152,19 +159,20 @@ s32 ESDevice::SeekContent(u32 cfd, u32 offset, SeekMode mode, u32 uid) if (!entry.m_opened) return IPC_EINVAL; - const auto result = m_ios.GetFS()->SeekFile(entry.m_fd, offset, static_cast(mode)); - return result.Succeeded() ? *result : FS::ConvertResult(result.Error()); + return m_ios.GetFSDevice()->Seek(entry.m_fd, offset, static_cast(mode), ticks); } IPCReply ESDevice::SeekContent(u32 uid, const IOCtlVRequest& request) { - if (!request.HasNumberOfValidVectors(3, 0)) - return IPCReply(ES_EINVAL); + return MakeIPCReply(IPC_OVERHEAD_TICKS, [&](Ticks ticks) -> s32 { + if (!request.HasNumberOfValidVectors(3, 0)) + return ES_EINVAL; - const u32 cfd = Memory::Read_U32(request.in_vectors[0].address); - const u32 offset = Memory::Read_U32(request.in_vectors[1].address); - const SeekMode mode = static_cast(Memory::Read_U32(request.in_vectors[2].address)); + const u32 cfd = Memory::Read_U32(request.in_vectors[0].address); + const u32 offset = Memory::Read_U32(request.in_vectors[1].address); + const auto mode = static_cast(Memory::Read_U32(request.in_vectors[2].address)); - return IPCReply(SeekContent(cfd, offset, mode, uid)); + return SeekContent(cfd, offset, mode, uid, ticks); + }); } } // namespace IOS::HLE diff --git a/Source/Core/Core/IOS/ES/TitleManagement.cpp b/Source/Core/Core/IOS/ES/TitleManagement.cpp index df9c6ec9c2..cf63efd8f6 100644 --- a/Source/Core/Core/IOS/ES/TitleManagement.cpp +++ b/Source/Core/Core/IOS/ES/TitleManagement.cpp @@ -793,7 +793,7 @@ ReturnCode ESDevice::ExportContentEnd(Context& context, u32 content_fd) { if (!context.title_import_export.valid || !context.title_import_export.content.valid) return ES_EINVAL; - return CloseContent(content_fd, 0); + return static_cast(CloseContent(content_fd, 0)); } IPCReply ESDevice::ExportContentEnd(Context& context, const IOCtlVRequest& request)