From fc7e6c9cc90699f587c7b2ebe73cad6adad25d00 Mon Sep 17 00:00:00 2001 From: fearlessTobi Date: Fri, 2 Nov 2018 18:11:22 +0100 Subject: [PATCH] fs_user: Add a delay for each file open --- src/core/file_sys/archive_backend.h | 22 +++++++++++++++++ src/core/file_sys/archive_extsavedata.cpp | 19 ++++++++++++--- src/core/file_sys/archive_sdmc.cpp | 11 ++++++++- src/core/file_sys/archive_sdmc.h | 6 ++++- src/core/file_sys/archive_sdmcwriteonly.cpp | 27 ++++++++++++++++++++- src/core/file_sys/archive_sdmcwriteonly.h | 4 ++- src/core/file_sys/delay_generator.cpp | 7 ++++++ src/core/file_sys/delay_generator.h | 2 ++ src/core/file_sys/file_backend.h | 9 +++++++ src/core/file_sys/ivfc_archive.cpp | 6 ++++- src/core/file_sys/ivfc_archive.h | 26 +++++++++++++++++++- src/core/file_sys/savedata_archive.cpp | 8 ++++++ src/core/hle/service/fs/archive.h | 4 +-- src/core/hle/service/fs/fs_user.cpp | 13 ++++++++++ 14 files changed, 153 insertions(+), 11 deletions(-) diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h index 1a57e12d3..1e9ee2c60 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/archive_backend.h @@ -12,6 +12,7 @@ #include "common/common_types.h" #include "common/swap.h" #include "core/hle/result.h" +#include "delay_generator.h" namespace FileSys { @@ -153,6 +154,27 @@ public: * @return The number of free bytes in the archive */ virtual u64 GetFreeBytes() const = 0; + + u64 GetReadDelayNs(std::size_t length) { + if (delay_generator != nullptr) { + return delay_generator->GetReadDelayNs(length); + } + LOG_ERROR(Service_FS, "Delay generator was not initalized. Using default"); + delay_generator = std::make_unique(); + return delay_generator->GetReadDelayNs(length); + } + + u64 GetOpenDelayNs() { + if (delay_generator != nullptr) { + return delay_generator->GetOpenDelayNs(); + } + LOG_ERROR(Service_FS, "Delay generator was not initalized. Using default"); + delay_generator = std::make_unique(); + return delay_generator->GetOpenDelayNs(); + } + +protected: + std::unique_ptr delay_generator; }; class ArchiveFactory : NonCopyable { diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp index 2839483f5..519c233de 100644 --- a/src/core/file_sys/archive_extsavedata.cpp +++ b/src/core/file_sys/archive_extsavedata.cpp @@ -59,7 +59,7 @@ private: class ExtSaveDataDelayGenerator : public DelayGenerator { public: u64 GetReadDelayNs(std::size_t length) override { - // This is the delay measured for a savedate read, + // This is the delay measured for a savedata read, // not for extsaveData // For now we will take that static constexpr u64 slope(183); @@ -69,6 +69,14 @@ public: std::max(static_cast(length) * slope + offset, minimum); return ipc_delay_nanoseconds; } + + u64 GetOpenDelayNs() override { + // This is the delay measured for a savedata open, + // not for extsaveData + // For now we will take that + static constexpr u64 IPCDelayNanoseconds(269082); + return IPCDelayNanoseconds; + } }; /** @@ -80,7 +88,11 @@ public: */ class ExtSaveDataArchive : public SaveDataArchive { public: - explicit ExtSaveDataArchive(const std::string& mount_point) : SaveDataArchive(mount_point) {} + explicit ExtSaveDataArchive(const std::string& mount_point, + std::unique_ptr delay_generator_) + : SaveDataArchive(mount_point) { + delay_generator = std::move(delay_generator_); + } std::string GetName() const override { return "ExtSaveDataArchive: " + mount_point; @@ -232,7 +244,8 @@ ResultVal> ArchiveFactory_ExtSaveData::Open(cons return ERR_NOT_FORMATTED; } } - auto archive = std::make_unique(fullpath); + std::unique_ptr delay_generator = std::make_unique(); + auto archive = std::make_unique(fullpath, std::move(delay_generator)); return MakeResult>(std::move(archive)); } diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp index cff4cd395..d2269fe7c 100644 --- a/src/core/file_sys/archive_sdmc.cpp +++ b/src/core/file_sys/archive_sdmc.cpp @@ -29,6 +29,14 @@ public: u64 IPCDelayNanoseconds = std::max(static_cast(length) * slope + offset, minimum); return IPCDelayNanoseconds; } + + u64 GetOpenDelayNs() override { + // This is the delay measured on O3DS and O2DS with + // https://gist.github.com/FearlessTobi/c37e143c314789251f98f2c45cd706d2 + // from the results the average of each length was taken. + static constexpr u64 IPCDelayNanoseconds(269082); + return IPCDelayNanoseconds; + } }; ResultVal> SDMCArchive::OpenFile(const Path& path, @@ -378,7 +386,8 @@ bool ArchiveFactory_SDMC::Initialize() { ResultVal> ArchiveFactory_SDMC::Open(const Path& path, u64 program_id) { - auto archive = std::make_unique(sdmc_directory); + std::unique_ptr delay_generator = std::make_unique(); + auto archive = std::make_unique(sdmc_directory, std::move(delay_generator)); return MakeResult>(std::move(archive)); } diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h index 637d4dc16..41d7b7c59 100644 --- a/src/core/file_sys/archive_sdmc.h +++ b/src/core/file_sys/archive_sdmc.h @@ -17,7 +17,11 @@ namespace FileSys { /// Archive backend for SDMC archive class SDMCArchive : public ArchiveBackend { public: - explicit SDMCArchive(const std::string& mount_point_) : mount_point(mount_point_) {} + explicit SDMCArchive(const std::string& mount_point_, + std::unique_ptr delay_generator_) + : mount_point(mount_point_) { + delay_generator = std::move(delay_generator_); + } std::string GetName() const override { return "SDMCArchive: " + mount_point; diff --git a/src/core/file_sys/archive_sdmcwriteonly.cpp b/src/core/file_sys/archive_sdmcwriteonly.cpp index b9534f12d..74552d751 100644 --- a/src/core/file_sys/archive_sdmcwriteonly.cpp +++ b/src/core/file_sys/archive_sdmcwriteonly.cpp @@ -15,6 +15,28 @@ namespace FileSys { +class SDMCWriteOnlyDelayGenerator : public DelayGenerator { +public: + u64 GetReadDelayNs(std::size_t length) override { + // This is the delay measured on O3DS and O2DS with + // https://gist.github.com/B3n30/ac40eac20603f519ff106107f4ac9182 + // from the results the average of each length was taken. + static constexpr u64 slope(183); + static constexpr u64 offset(524879); + static constexpr u64 minimum(631826); + u64 IPCDelayNanoseconds = std::max(static_cast(length) * slope + offset, minimum); + return IPCDelayNanoseconds; + } + + u64 GetOpenDelayNs() override { + // This is the delay measured on O3DS and O2DS with + // https://gist.github.com/FearlessTobi/c37e143c314789251f98f2c45cd706d2 + // from the results the average of each length was taken. + static constexpr u64 IPCDelayNanoseconds(269082); + return IPCDelayNanoseconds; + } +}; + ResultVal> SDMCWriteOnlyArchive::OpenFile(const Path& path, const Mode& mode) const { if (mode.read_flag) { @@ -51,7 +73,10 @@ bool ArchiveFactory_SDMCWriteOnly::Initialize() { ResultVal> ArchiveFactory_SDMCWriteOnly::Open(const Path& path, u64 program_id) { - auto archive = std::make_unique(sdmc_directory); + std::unique_ptr delay_generator = + std::make_unique(); + auto archive = + std::make_unique(sdmc_directory, std::move(delay_generator)); return MakeResult>(std::move(archive)); } diff --git a/src/core/file_sys/archive_sdmcwriteonly.h b/src/core/file_sys/archive_sdmcwriteonly.h index 050fc19c8..8191f053f 100644 --- a/src/core/file_sys/archive_sdmcwriteonly.h +++ b/src/core/file_sys/archive_sdmcwriteonly.h @@ -19,7 +19,9 @@ namespace FileSys { */ class SDMCWriteOnlyArchive : public SDMCArchive { public: - explicit SDMCWriteOnlyArchive(const std::string& mount_point) : SDMCArchive(mount_point) {} + explicit SDMCWriteOnlyArchive(const std::string& mount_point, + std::unique_ptr delay_generator_) + : SDMCArchive(mount_point, std::move(delay_generator_)) {} std::string GetName() const override { return "SDMCWriteOnlyArchive: " + mount_point; diff --git a/src/core/file_sys/delay_generator.cpp b/src/core/file_sys/delay_generator.cpp index 654550061..04f877f83 100644 --- a/src/core/file_sys/delay_generator.cpp +++ b/src/core/file_sys/delay_generator.cpp @@ -19,4 +19,11 @@ u64 DefaultDelayGenerator::GetReadDelayNs(std::size_t length) { return IPCDelayNanoseconds; } +u64 DefaultDelayGenerator::GetOpenDelayNs() { + // This is the delay measured for a romfs open. + // For now we will take that as a default + static constexpr u64 IPCDelayNanoseconds(9438006); + return IPCDelayNanoseconds; +} + } // namespace FileSys diff --git a/src/core/file_sys/delay_generator.h b/src/core/file_sys/delay_generator.h index 06ef97281..d530f2ee2 100644 --- a/src/core/file_sys/delay_generator.h +++ b/src/core/file_sys/delay_generator.h @@ -13,6 +13,7 @@ class DelayGenerator { public: virtual ~DelayGenerator(); virtual u64 GetReadDelayNs(std::size_t length) = 0; + virtual u64 GetOpenDelayNs() = 0; // TODO (B3N30): Add getter for all other file/directory io operations }; @@ -20,6 +21,7 @@ public: class DefaultDelayGenerator : public DelayGenerator { public: u64 GetReadDelayNs(std::size_t length) override; + u64 GetOpenDelayNs() override; }; } // namespace FileSys diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h index 103b81d60..c865c98e8 100644 --- a/src/core/file_sys/file_backend.h +++ b/src/core/file_sys/file_backend.h @@ -55,6 +55,15 @@ public: return delay_generator->GetReadDelayNs(length); } + u64 GetOpenDelayNs() { + if (delay_generator != nullptr) { + return delay_generator->GetOpenDelayNs(); + } + LOG_ERROR(Service_FS, "Delay generator was not initalized. Using default"); + delay_generator = std::make_unique(); + return delay_generator->GetOpenDelayNs(); + } + /** * Get the size of the file in bytes * @return Size of the file in bytes diff --git a/src/core/file_sys/ivfc_archive.cpp b/src/core/file_sys/ivfc_archive.cpp index 5a11e786d..ba16f8cd8 100644 --- a/src/core/file_sys/ivfc_archive.cpp +++ b/src/core/file_sys/ivfc_archive.cpp @@ -14,7 +14,11 @@ namespace FileSys { -IVFCArchive::IVFCArchive(std::shared_ptr file) : romfs_file(std::move(file)) {} +IVFCArchive::IVFCArchive(std::shared_ptr file, + std::unique_ptr delay_generator_) + : romfs_file(std::move(file)) { + delay_generator = std::move(delay_generator_); +} std::string IVFCArchive::GetName() const { return "IVFC"; diff --git a/src/core/file_sys/ivfc_archive.h b/src/core/file_sys/ivfc_archive.h index ded0b9075..8168e04f4 100644 --- a/src/core/file_sys/ivfc_archive.h +++ b/src/core/file_sys/ivfc_archive.h @@ -31,6 +31,13 @@ class IVFCDelayGenerator : public DelayGenerator { u64 IPCDelayNanoseconds = std::max(static_cast(length) * slope + offset, minimum); return IPCDelayNanoseconds; } + + u64 GetOpenDelayNs() override { + // This is the delay measured for a romfs open. + // For now we will take that as a default + static constexpr u64 IPCDelayNanoseconds(9438006); + return IPCDelayNanoseconds; + } }; class RomFSDelayGenerator : public DelayGenerator { @@ -45,6 +52,14 @@ public: u64 IPCDelayNanoseconds = std::max(static_cast(length) * slope + offset, minimum); return IPCDelayNanoseconds; } + + u64 GetOpenDelayNs() override { + // This is the delay measured on O3DS and O2DS with + // https://gist.github.com/FearlessTobi/eb1d70619c65c7e6f02141d71e79a36e + // from the results the average of each length was taken. + static constexpr u64 IPCDelayNanoseconds(9438006); + return IPCDelayNanoseconds; + } }; class ExeFSDelayGenerator : public DelayGenerator { @@ -59,6 +74,14 @@ public: u64 IPCDelayNanoseconds = std::max(static_cast(length) * slope + offset, minimum); return IPCDelayNanoseconds; } + + u64 GetOpenDelayNs() override { + // This is the delay measured on O3DS and O2DS with + // https://gist.github.com/FearlessTobi/eb1d70619c65c7e6f02141d71e79a36e + // from the results the average of each length was taken. + static constexpr u64 IPCDelayNanoseconds(9438006); + return IPCDelayNanoseconds; + } }; /** @@ -68,7 +91,8 @@ public: */ class IVFCArchive : public ArchiveBackend { public: - IVFCArchive(std::shared_ptr file); + IVFCArchive(std::shared_ptr file, + std::unique_ptr delay_generator_); std::string GetName() const override; diff --git a/src/core/file_sys/savedata_archive.cpp b/src/core/file_sys/savedata_archive.cpp index b2569e498..8d7830468 100644 --- a/src/core/file_sys/savedata_archive.cpp +++ b/src/core/file_sys/savedata_archive.cpp @@ -25,6 +25,14 @@ public: u64 IPCDelayNanoseconds = std::max(static_cast(length) * slope + offset, minimum); return IPCDelayNanoseconds; } + + u64 GetOpenDelayNs() override { + // This is the delay measured on O3DS and O2DS with + // https://gist.github.com/FearlessTobi/c37e143c314789251f98f2c45cd706d2 + // from the results the average of each length was taken. + static constexpr u64 IPCDelayNanoseconds(269082); + return IPCDelayNanoseconds; + } }; ResultVal> SaveDataArchive::OpenFile(const Path& path, diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index c1dd2bd1b..45f6b7eec 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -234,6 +234,8 @@ public: /// Registers a new NCCH file with the SelfNCCH archive factory void RegisterSelfNCCH(Loader::AppLoader& app_loader); + ArchiveBackend* GetArchive(ArchiveHandle handle); + private: Core::System& system; @@ -248,8 +250,6 @@ private: /// Register all archive types void RegisterArchiveTypes(); - ArchiveBackend* GetArchive(ArchiveHandle handle); - /** * Map of registered archives, identified by id code. Once an archive is registered here, it is * never removed until UnregisterArchiveTypes is called. diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index bbcc2e6fd..c4b8843c3 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -16,6 +16,7 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/event.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/server_session.h" #include "core/hle/result.h" @@ -70,6 +71,18 @@ void FS_USER::OpenFile(Kernel::HLERequestContext& ctx) { rb.PushMoveObjects(nullptr); LOG_ERROR(Service_FS, "failed to get a handle for file {}", file_path.DebugStr()); } + + auto archive = archives.GetArchive(archive_handle); + if (archive == nullptr) + return; + + std::chrono::nanoseconds open_timeout_ns{archive->GetOpenDelayNs()}; + ctx.SleepClientThread(system.Kernel().GetThreadManager().GetCurrentThread(), "fs_user::open", + open_timeout_ns, + [](Kernel::SharedPtr thread, + Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) { + // Nothing to do here + }); } void FS_USER::OpenFileDirectly(Kernel::HLERequestContext& ctx) {