diff --git a/src/core/file_sys/archive_selfncch.cpp b/src/core/file_sys/archive_selfncch.cpp index 0e6a6d61b..32d5fff23 100644 --- a/src/core/file_sys/archive_selfncch.cpp +++ b/src/core/file_sys/archive_selfncch.cpp @@ -56,6 +56,17 @@ public: return ERROR_UNSUPPORTED_OPEN_FLAGS; } + u64 GetReadDelayNs(size_t length) const { + // The delay was 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(94); + static constexpr u64 offset(582778); + static constexpr u64 minimum(663124); + u64 IPCDelayNanoseconds = std::max(static_cast(length) * slope + offset, minimum); + return IPCDelayNanoseconds; + } + u64 GetSize() const override { return data->size(); } diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp index 677f92467..0fae8301f 100644 --- a/src/core/file_sys/disk_archive.cpp +++ b/src/core/file_sys/disk_archive.cpp @@ -36,6 +36,20 @@ ResultVal DiskFile::Write(const u64 offset, const size_t length, const b return MakeResult(written); } +u64 DiskFile::GetReadDelayNs(size_t length) const { + // TODO(B3N30): figure out the time a 3ds needs for those write + // for that backend. + // For now take the results from the romfs test. + // The delay was 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 DiskFile::GetSize() const { return file->GetSize(); } diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h index 912d264e8..2c22da661 100644 --- a/src/core/file_sys/disk_archive.h +++ b/src/core/file_sys/disk_archive.h @@ -29,6 +29,7 @@ public: ResultVal Read(u64 offset, size_t length, u8* buffer) const override; ResultVal Write(u64 offset, size_t length, bool flush, const u8* buffer) override; + u64 GetReadDelayNs(size_t length) const override; u64 GetSize() const override; bool SetSize(u64 size) const override; bool Close() const override; diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h index 009ee139a..003e24429 100644 --- a/src/core/file_sys/file_backend.h +++ b/src/core/file_sys/file_backend.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include "common/common_types.h" #include "core/hle/result.h" @@ -37,6 +38,24 @@ public: */ virtual ResultVal Write(u64 offset, size_t length, bool flush, const u8* buffer) = 0; + /** + * Get the amount of time a 3ds needs to read those data + * @param length Length in bytes of data read from file + * @return Nanoseconds for the delay + */ + virtual u64 GetReadDelayNs(size_t length) const { + // Return the default delay for the case that the subclass backend didn't + // implement one. We take the one measured for romfs reads + // This should be removed as soon as every subclass backend + // has one implemented + LOG_WARNING(Service_FS, "Using default delay for read"); + static constexpr u64 slope(94); + static constexpr u64 offset(582778); + static constexpr u64 minimum(663124); + u64 IPCDelayNanoseconds = std::max(static_cast(length) * slope + offset, minimum); + return IPCDelayNanoseconds; + } + /** * 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 7cd09ed07..18b260487 100644 --- a/src/core/file_sys/ivfc_archive.cpp +++ b/src/core/file_sys/ivfc_archive.cpp @@ -107,6 +107,17 @@ ResultVal IVFCFile::Write(const u64 offset, const size_t length, const b return MakeResult(0); } +u64 IVFCFile::GetReadDelayNs(size_t length) const { + // The delay was 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(94); + static constexpr u64 offset(582778); + static constexpr u64 minimum(663124); + u64 IPCDelayNanoseconds = std::max(static_cast(length) * slope + offset, minimum); + return IPCDelayNanoseconds; +} + u64 IVFCFile::GetSize() const { return data_size; } diff --git a/src/core/file_sys/ivfc_archive.h b/src/core/file_sys/ivfc_archive.h index 768084036..a6f26199c 100644 --- a/src/core/file_sys/ivfc_archive.h +++ b/src/core/file_sys/ivfc_archive.h @@ -54,6 +54,7 @@ public: ResultVal Read(u64 offset, size_t length, u8* buffer) const override; ResultVal Write(u64 offset, size_t length, bool flush, const u8* buffer) override; + u64 GetReadDelayNs(size_t length) const override; u64 GetSize() const override; bool SetSize(u64 size) const override; bool Close() const override { diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index db304812c..3370302dd 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -31,6 +31,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/handle_table.h" #include "core/hle/kernel/server_session.h" #include "core/hle/result.h" @@ -121,6 +122,13 @@ void File::Read(Kernel::HLERequestContext& ctx) { rb.Push(*read); } rb.PushMappedBuffer(buffer); + + u64 read_timeout_ns = backend->GetReadDelayNs(length); + ctx.SleepClientThread(Kernel::GetCurrentThread(), "file::read", read_timeout_ns, + [](Kernel::SharedPtr thread, + Kernel::HLERequestContext& ctx, ThreadWakeupReason reason) { + // Nothing to do here + }); } void File::Write(Kernel::HLERequestContext& ctx) {