From 6e38081165f6180180f824fa1864605ec4db1614 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 19 Feb 2018 00:30:30 -0500 Subject: [PATCH 1/5] ResultCode: Mark any error code that isn't 0 as an error. --- src/core/hle/result.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 656e1b4a7..97fef7a48 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -108,11 +108,11 @@ union ResultCode { } constexpr bool IsSuccess() const { - return is_error.ExtractValue(raw) == 0; + return raw == 0; } constexpr bool IsError() const { - return is_error.ExtractValue(raw) == 1; + return raw != 0; } }; From d140c8ecf7514e925340cbd3340991c8df0d0c15 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 19 Feb 2018 00:32:00 -0500 Subject: [PATCH 2/5] Filesystem: Added a SaveData Factory and associated Disk_FileSystem. --- src/core/CMakeLists.txt | 4 + src/core/file_sys/disk_filesystem.cpp | 147 ++++++++++++++++++ src/core/file_sys/disk_filesystem.h | 66 ++++++++ src/core/file_sys/filesystem.h | 25 ++- src/core/file_sys/romfs_filesystem.cpp | 12 +- src/core/file_sys/romfs_filesystem.h | 7 +- src/core/file_sys/savedata_factory.cpp | 41 +++++ src/core/file_sys/savedata_factory.h | 31 ++++ .../hle/service/filesystem/filesystem.cpp | 11 +- src/core/hle/service/filesystem/filesystem.h | 1 + 10 files changed, 329 insertions(+), 16 deletions(-) create mode 100644 src/core/file_sys/disk_filesystem.cpp create mode 100644 src/core/file_sys/disk_filesystem.h create mode 100644 src/core/file_sys/savedata_factory.cpp create mode 100644 src/core/file_sys/savedata_factory.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1bc536075..6ad04d19d 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -7,6 +7,8 @@ add_library(core STATIC core_timing.cpp core_timing.h file_sys/directory.h + file_sys/disk_filesystem.cpp + file_sys/disk_filesystem.h file_sys/errors.h file_sys/filesystem.cpp file_sys/filesystem.h @@ -18,6 +20,8 @@ add_library(core STATIC file_sys/romfs_factory.h file_sys/romfs_filesystem.cpp file_sys/romfs_filesystem.h + file_sys/savedata_factory.cpp + file_sys/savedata_factory.h file_sys/storage.h frontend/emu_window.cpp frontend/emu_window.h diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp new file mode 100644 index 000000000..be7574fdb --- /dev/null +++ b/src/core/file_sys/disk_filesystem.cpp @@ -0,0 +1,147 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include "common/common_types.h" +#include "common/logging/log.h" +#include "core/file_sys/disk_filesystem.h" + +namespace FileSys { + +std::string Disk_FileSystem::GetName() const { + return "Disk"; +} + +ResultVal> Disk_FileSystem::OpenFile(const std::string& path, + Mode mode) const { + ASSERT_MSG(mode == Mode::Read || mode == Mode::Write, "Other file modes are not supported"); + + std::string full_path = base_directory + path; + auto file = std::make_shared(full_path, mode == Mode::Read ? "rb" : "wb"); + + if (!file->IsOpen()) { + // TODO(Subv): Find out the correct error code. + return ResultCode(-1); + } + + return MakeResult>( + std::make_unique(std::move(file))); +} + +ResultCode Disk_FileSystem::DeleteFile(const Path& path) const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + // TODO(bunnei): Use correct error code + return ResultCode(-1); +} + +ResultCode Disk_FileSystem::RenameFile(const Path& src_path, const Path& dest_path) const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + // TODO(wwylele): Use correct error code + return ResultCode(-1); +} + +ResultCode Disk_FileSystem::DeleteDirectory(const Path& path) const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + // TODO(wwylele): Use correct error code + return ResultCode(-1); +} + +ResultCode Disk_FileSystem::DeleteDirectoryRecursively(const Path& path) const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + // TODO(wwylele): Use correct error code + return ResultCode(-1); +} + +ResultCode Disk_FileSystem::CreateFile(const std::string& path, u64 size) const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + + std::string full_path = base_directory + path; + if (size == 0) { + FileUtil::CreateEmptyFile(full_path); + return RESULT_SUCCESS; + } + + FileUtil::IOFile file(full_path, "wb"); + // Creates a sparse file (or a normal file on filesystems without the concept of sparse files) + // We do this by seeking to the right size, then writing a single null byte. + if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1) { + return RESULT_SUCCESS; + } + + LOG_ERROR(Service_FS, "Too large file"); + // TODO(Subv): Find out the correct error code + return ResultCode(-1); +} + +ResultCode Disk_FileSystem::CreateDirectory(const Path& path) const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + // TODO(wwylele): Use correct error code + return ResultCode(-1); +} + +ResultCode Disk_FileSystem::RenameDirectory(const Path& src_path, const Path& dest_path) const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + // TODO(wwylele): Use correct error code + return ResultCode(-1); +} + +ResultVal> Disk_FileSystem::OpenDirectory( + const Path& path) const { + return MakeResult>(std::make_unique()); +} + +u64 Disk_FileSystem::GetFreeSpaceSize() const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + return 0; +} + +ResultVal Disk_FileSystem::GetEntryType(const std::string& path) const { + std::string full_path = base_directory + path; + if (!FileUtil::Exists(full_path)) { + // TODO(Subv): Find out what this actually means + return ResultCode(ErrorModule::FS, 1); + } + + // TODO(Subv): Find out the EntryType values + UNIMPLEMENTED_MSG("Unimplemented GetEntryType"); +} + +ResultVal Disk_Storage::Read(const u64 offset, const size_t length, u8* buffer) const { + LOG_TRACE(Service_FS, "called offset=%llu, length=%zu", offset, length); + file->Seek(offset, SEEK_SET); + return MakeResult(file->ReadBytes(buffer, length)); +} + +ResultVal Disk_Storage::Write(const u64 offset, const size_t length, const bool flush, + const u8* buffer) const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + file->Seek(offset, SEEK_SET); + size_t written = file->WriteBytes(buffer, length); + if (flush) { + file->Flush(); + } + return MakeResult(written); +} + +u64 Disk_Storage::GetSize() const { + return file->GetSize(); +} + +bool Disk_Storage::SetSize(const u64 size) const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + return false; +} + +u32 Disk_Directory::Read(const u32 count, Entry* entries) { + LOG_WARNING(Service_FS, "(STUBBED) called"); + return 0; +} + +bool Disk_Directory::Close() const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + return true; +} + +} // namespace FileSys diff --git a/src/core/file_sys/disk_filesystem.h b/src/core/file_sys/disk_filesystem.h new file mode 100644 index 000000000..53767b949 --- /dev/null +++ b/src/core/file_sys/disk_filesystem.h @@ -0,0 +1,66 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include "common/common_types.h" +#include "common/file_util.h" +#include "core/file_sys/directory.h" +#include "core/file_sys/filesystem.h" +#include "core/file_sys/storage.h" +#include "core/hle/result.h" + +namespace FileSys { + +class Disk_FileSystem : public FileSystemBackend { +public: + explicit Disk_FileSystem(std::string base_directory) + : base_directory(std::move(base_directory)) {} + + std::string GetName() const override; + + ResultVal> OpenFile(const std::string& path, + Mode mode) const override; + ResultCode DeleteFile(const Path& path) const override; + ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override; + ResultCode DeleteDirectory(const Path& path) const override; + ResultCode DeleteDirectoryRecursively(const Path& path) const override; + ResultCode CreateFile(const std::string& path, u64 size) const override; + ResultCode CreateDirectory(const Path& path) const override; + ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; + ResultVal> OpenDirectory(const Path& path) const override; + u64 GetFreeSpaceSize() const override; + ResultVal GetEntryType(const std::string& path) const override; + +protected: + std::string base_directory; +}; + +class Disk_Storage : public StorageBackend { +public: + Disk_Storage(std::shared_ptr file) : file(std::move(file)) {} + + ResultVal Read(u64 offset, size_t length, u8* buffer) const override; + ResultVal Write(u64 offset, size_t length, bool flush, const u8* buffer) const override; + u64 GetSize() const override; + bool SetSize(u64 size) const override; + bool Close() const override { + return false; + } + void Flush() const override {} + +private: + std::shared_ptr file; +}; + +class Disk_Directory : public DirectoryBackend { +public: + u32 Read(const u32 count, Entry* entries) override; + bool Close() const override; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/filesystem.h b/src/core/file_sys/filesystem.h index 02705506b..df4e66a0b 100644 --- a/src/core/file_sys/filesystem.h +++ b/src/core/file_sys/filesystem.h @@ -27,11 +27,14 @@ enum LowPathType : u32 { Wchar = 4, }; -union Mode { - u32 hex; - BitField<0, 1, u32> read_flag; - BitField<1, 1, u32> write_flag; - BitField<2, 1, u32> create_flag; +enum EntryType : u32 { + Directory = 0, + File = 1, +}; + +enum class Mode : u32 { + Read = 1, + Write = 2, }; class Path { @@ -86,7 +89,7 @@ public: * @param size The size of the new file, filled with zeroes * @return Result of the operation */ - virtual ResultCode CreateFile(const Path& path, u64 size) const = 0; + virtual ResultCode CreateFile(const std::string& path, u64 size) const = 0; /** * Delete a file specified by its path @@ -138,8 +141,8 @@ public: * @param mode Mode to open the file with * @return Opened file, or error code */ - virtual ResultVal> OpenFile(const Path& path, - const Mode& mode) const = 0; + virtual ResultVal> OpenFile(const std::string& path, + Mode mode) const = 0; /** * Open a directory specified by its path @@ -153,6 +156,12 @@ public: * @return The number of free bytes in the archive */ virtual u64 GetFreeSpaceSize() const = 0; + + /** + * Get the type of the specified path + * @return The type of the specified path or error code + */ + virtual ResultVal GetEntryType(const std::string& path) const = 0; }; class FileSystemFactory : NonCopyable { diff --git a/src/core/file_sys/romfs_filesystem.cpp b/src/core/file_sys/romfs_filesystem.cpp index ca1463d7c..f1f9b4d04 100644 --- a/src/core/file_sys/romfs_filesystem.cpp +++ b/src/core/file_sys/romfs_filesystem.cpp @@ -14,8 +14,8 @@ std::string RomFS_FileSystem::GetName() const { return "RomFS"; } -ResultVal> RomFS_FileSystem::OpenFile(const Path& path, - const Mode& mode) const { +ResultVal> RomFS_FileSystem::OpenFile(const std::string& path, + Mode mode) const { return MakeResult>( std::make_unique(romfs_file, data_offset, data_size)); } @@ -48,7 +48,7 @@ ResultCode RomFS_FileSystem::DeleteDirectoryRecursively(const Path& path) const return ResultCode(-1); } -ResultCode RomFS_FileSystem::CreateFile(const Path& path, u64 size) const { +ResultCode RomFS_FileSystem::CreateFile(const std::string& path, u64 size) const { LOG_CRITICAL(Service_FS, "Attempted to create a file in an ROMFS archive (%s).", GetName().c_str()); // TODO(bunnei): Use correct error code @@ -79,6 +79,12 @@ u64 RomFS_FileSystem::GetFreeSpaceSize() const { return 0; } +ResultVal RomFS_FileSystem::GetEntryType(const std::string& path) const { + LOG_CRITICAL(Service_FS, "Called within an ROMFS archive (path %s).", path.c_str()); + // TODO(wwylele): Use correct error code + return ResultCode(-1); +} + ResultVal RomFS_Storage::Read(const u64 offset, const size_t length, u8* buffer) const { LOG_TRACE(Service_FS, "called offset=%llu, length=%zu", offset, length); romfs_file->Seek(data_offset + offset, SEEK_SET); diff --git a/src/core/file_sys/romfs_filesystem.h b/src/core/file_sys/romfs_filesystem.h index 900ea567a..cedd70645 100644 --- a/src/core/file_sys/romfs_filesystem.h +++ b/src/core/file_sys/romfs_filesystem.h @@ -29,17 +29,18 @@ public: std::string GetName() const override; - ResultVal> OpenFile(const Path& path, - const Mode& mode) const override; + ResultVal> OpenFile(const std::string& path, + Mode mode) const override; ResultCode DeleteFile(const Path& path) const override; ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override; ResultCode DeleteDirectory(const Path& path) const override; ResultCode DeleteDirectoryRecursively(const Path& path) const override; - ResultCode CreateFile(const Path& path, u64 size) const override; + ResultCode CreateFile(const std::string& path, u64 size) const override; ResultCode CreateDirectory(const Path& path) const override; ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; ResultVal> OpenDirectory(const Path& path) const override; u64 GetFreeSpaceSize() const override; + ResultVal GetEntryType(const std::string& path) const override; protected: std::shared_ptr romfs_file; diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp new file mode 100644 index 000000000..0df754e7c --- /dev/null +++ b/src/core/file_sys/savedata_factory.cpp @@ -0,0 +1,41 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include "common/common_types.h" +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/file_sys/disk_filesystem.h" +#include "core/file_sys/savedata_factory.h" + +namespace FileSys { + +SaveData_Factory::SaveData_Factory(std::string nand_directory) + : nand_directory(std::move(nand_directory)) {} + +ResultVal> SaveData_Factory::Open(const Path& path) { + // TODO(Subv): Somehow obtain these values. + u64 title_id = 0; + u32 user = 0; + std::string save_directory = Common::StringFromFormat("%ssave/%016" PRIX64 "/%08X", + nand_directory.c_str(), title_id, user); + auto archive = std::make_unique(save_directory); + return MakeResult>(std::move(archive)); +} + +ResultCode SaveData_Factory::Format(const Path& path, + const FileSys::ArchiveFormatInfo& format_info) { + LOG_ERROR(Service_FS, "Unimplemented Format archive %s", GetName().c_str()); + // TODO(bunnei): Find the right error code for this + return ResultCode(-1); +} + +ResultVal SaveData_Factory::GetFormatInfo(const Path& path) const { + LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); + // TODO(bunnei): Find the right error code for this + return ResultCode(-1); +} + +} // namespace FileSys diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h new file mode 100644 index 000000000..726743fde --- /dev/null +++ b/src/core/file_sys/savedata_factory.h @@ -0,0 +1,31 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include "common/common_types.h" +#include "core/file_sys/filesystem.h" +#include "core/hle/result.h" + +namespace FileSys { + +/// File system interface to the SaveData archive +class SaveData_Factory final : public FileSystemFactory { +public: + explicit SaveData_Factory(std::string nand_directory); + + std::string GetName() const override { + return "SaveData_Factory"; + } + ResultVal> Open(const Path& path) override; + ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; + ResultVal GetFormatInfo(const Path& path) const override; + +private: + std::string nand_directory; +}; + +} // namespace FileSys diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 4b47548fd..32752aea5 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -3,7 +3,9 @@ // Refer to the license.txt file included. #include +#include "common/file_util.h" #include "core/file_sys/filesystem.h" +#include "core/file_sys/savedata_factory.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/fsp_srv.h" @@ -41,12 +43,17 @@ ResultVal> OpenFileSystem(Type type, return itr->second->Open(path); } -void UnregisterFileSystems() { +void RegisterFileSystems() { filesystem_map.clear(); + + std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); + + auto savedata = std::make_unique(std::move(nand_directory)); + RegisterFileSystem(std::move(savedata), Type::SaveData); } void InstallInterfaces(SM::ServiceManager& service_manager) { - UnregisterFileSystems(); + RegisterFileSystems(); std::make_shared()->InstallAsService(service_manager); } diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index a674c9493..80f318676 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -25,6 +25,7 @@ namespace FileSystem { /// Supported FileSystem types enum class Type { RomFS = 1, + SaveData = 2, }; /** From cc6e4ae6cf496f787c5277135aaa3e63cb98b780 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 19 Feb 2018 00:33:48 -0500 Subject: [PATCH 3/5] FS: Implement MountSaveData and some of the IFile interface. --- src/core/hle/service/filesystem/fsp_srv.cpp | 188 ++++++++++++++++++++ src/core/hle/service/filesystem/fsp_srv.h | 1 + 2 files changed, 189 insertions(+) diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 87a07e457..3ac5a96cb 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include "common/logging/log.h" #include "core/core.h" #include "core/file_sys/filesystem.h" @@ -65,10 +66,186 @@ private: } }; +class IFile final : public ServiceFramework { +public: + explicit IFile(std::unique_ptr&& backend) + : ServiceFramework("IFile"), backend(std::move(backend)) { + static const FunctionInfo functions[] = { + {0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"}, {2, nullptr, "Flush"}, + {3, nullptr, "SetSize"}, {4, nullptr, "GetSize"}, + }; + RegisterHandlers(functions); + } + +private: + std::unique_ptr backend; + + void Read(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 unk = rp.Pop(); + const s64 offset = rp.Pop(); + const s64 length = rp.Pop(); + + LOG_DEBUG(Service_FS, "called, offset=0x%llx, length=0x%llx", offset, length); + + // Error checking + if (length < 0) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); + return; + } + if (offset < 0) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); + return; + } + + // Read the data from the Storage backend + std::vector output(length); + ResultVal res = backend->Read(offset, length, output.data()); + if (res.Failed()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res.Code()); + return; + } + + // Write the data to memory + ctx.WriteBuffer(output); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push(static_cast(*res)); + } + + void Write(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 unk = rp.Pop(); + const s64 offset = rp.Pop(); + const s64 length = rp.Pop(); + + LOG_DEBUG(Service_FS, "called, offset=0x%llx, length=0x%llx", offset, length); + + // Error checking + if (length < 0) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); + return; + } + if (offset < 0) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); + return; + } + + // Write the data to the Storage backend + std::vector data = ctx.ReadBuffer(); + ResultVal res = backend->Write(offset, length, true, data.data()); + if (res.Failed()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res.Code()); + return; + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } +}; + +class IFileSystem final : public ServiceFramework { +public: + explicit IFileSystem(std::unique_ptr&& backend) + : ServiceFramework("IFileSystem"), backend(std::move(backend)) { + static const FunctionInfo functions[] = { + {0, &IFileSystem::CreateFile, "CreateFile"}, + {7, &IFileSystem::GetEntryType, "GetEntryType"}, + {8, &IFileSystem::OpenFile, "OpenFile"}, + {10, &IFileSystem::Commit, "Commit"}, + }; + RegisterHandlers(functions); + } + + void CreateFile(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + auto file_buffer = ctx.ReadBuffer(); + auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); + + std::string name(file_buffer.begin(), end); + + u64 mode = rp.Pop(); + u32 size = rp.Pop(); + + LOG_DEBUG(Service_FS, "called file %s mode 0x%" PRIX64 " size 0x%08X", name.c_str(), mode, + size); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend->CreateFile(name, size)); + } + + void OpenFile(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + auto file_buffer = ctx.ReadBuffer(); + auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); + + std::string name(file_buffer.begin(), end); + + auto mode = static_cast(rp.Pop()); + + LOG_DEBUG(Service_FS, "called file %s mode %u", name.c_str(), static_cast(mode)); + + auto result = backend->OpenFile(name, mode); + if (result.Failed()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result.Code()); + return; + } + + auto file = std::move(result.Unwrap()); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(std::move(file)); + } + + void GetEntryType(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + auto file_buffer = ctx.ReadBuffer(); + auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); + + std::string name(file_buffer.begin(), end); + + LOG_DEBUG(Service_FS, "called file %s", name.c_str()); + + auto result = backend->GetEntryType(name); + if (result.Failed()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result.Code()); + return; + } + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(static_cast(*result)); + } + + void Commit(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + +private: + std::unique_ptr backend; +}; + FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { static const FunctionInfo functions[] = { {1, &FSP_SRV::Initalize, "Initalize"}, {18, &FSP_SRV::MountSdCard, "MountSdCard"}, + {51, &FSP_SRV::MountSaveData, "MountSaveData"}, {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"}, {202, nullptr, "OpenDataStorageByDataId"}, {203, &FSP_SRV::OpenRomStorage, "OpenRomStorage"}, @@ -102,6 +279,17 @@ void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } +void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called"); + + FileSys::Path unused; + auto filesystem = OpenFileSystem(Type::SaveData, unused).Unwrap(); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(std::move(filesystem)); +} + void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_FS, "(STUBBED) called"); diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index 56afc4b90..f19b2f2c4 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h @@ -24,6 +24,7 @@ private: void Initalize(Kernel::HLERequestContext& ctx); void MountSdCard(Kernel::HLERequestContext& ctx); + void MountSaveData(Kernel::HLERequestContext& ctx); void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); void OpenRomStorage(Kernel::HLERequestContext& ctx); From 827f8ca3c77ad0b7e667c64b5c983b3b3ffe8d7d Mon Sep 17 00:00:00 2001 From: Subv Date: Tue, 27 Feb 2018 10:22:15 -0500 Subject: [PATCH 4/5] Kernel: Store the program id in the Process class instead of the CodeSet class. There may be many CodeSets per Process, so it's wasteful and overcomplicated to store the program id in each of them. --- src/core/hle/kernel/process.cpp | 8 +++----- src/core/hle/kernel/process.h | 9 +++++---- src/core/loader/deconstructed_rom_directory.cpp | 6 +++--- src/core/loader/elf.cpp | 4 ++-- src/core/loader/nro.cpp | 4 ++-- src/core/loader/nso.cpp | 8 ++++---- src/core/loader/nso.h | 2 +- src/tests/core/arm/arm_test_common.cpp | 2 +- src/tests/core/memory/memory.cpp | 8 ++++---- 9 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 8e74059ea..bb6dc28d7 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -20,12 +20,9 @@ namespace Kernel { // Lists all processes that exist in the current session. static std::vector> process_list; -SharedPtr CodeSet::Create(std::string name, u64 program_id) { +SharedPtr CodeSet::Create(std::string name) { SharedPtr codeset(new CodeSet); - codeset->name = std::move(name); - codeset->program_id = program_id; - return codeset; } @@ -34,13 +31,14 @@ CodeSet::~CodeSet() {} u32 Process::next_process_id; -SharedPtr Process::Create(std::string&& name) { +SharedPtr Process::Create(std::string&& name, u64 program_id) { SharedPtr process(new Process); process->name = std::move(name); process->flags.raw = 0; process->flags.memory_region.Assign(MemoryRegion::APPLICATION); process->status = ProcessStatus::Created; + process->program_id = program_id; process_list.push_back(process); return process; diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index add98472f..1de12efd3 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -56,7 +56,7 @@ class ResourceLimit; struct MemoryRegionInfo; struct CodeSet final : public Object { - static SharedPtr Create(std::string name, u64 program_id); + static SharedPtr Create(std::string name); std::string GetTypeName() const override { return "CodeSet"; @@ -72,8 +72,6 @@ struct CodeSet final : public Object { /// Name of the process std::string name; - /// Title ID corresponding to the process - u64 program_id; std::shared_ptr> memory; @@ -97,7 +95,7 @@ private: class Process final : public Object { public: - static SharedPtr Create(std::string&& name); + static SharedPtr Create(std::string&& name, u64 program_id); std::string GetTypeName() const override { return "Process"; @@ -113,6 +111,9 @@ public: static u32 next_process_id; + /// Title ID corresponding to the process + u64 program_id; + /// Resource limit descriptor for this process SharedPtr resource_limit; diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 864cf25cd..459d127c2 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -110,8 +110,6 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( return ResultStatus::Error; } - process = Kernel::Process::Create("main"); - const std::string directory = filepath.substr(0, filepath.find_last_of("/\\")) + DIR_SEP; const std::string npdm_path = directory + DIR_SEP + "main.npdm"; @@ -121,13 +119,15 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( } metadata.Print(); + process = Kernel::Process::Create("main", metadata.GetTitleID()); + // Load NSO modules VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR}; for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { const std::string path = directory + DIR_SEP + module; const VAddr load_addr = next_load_addr; - next_load_addr = AppLoader_NSO::LoadModule(path, load_addr, metadata.GetTitleID()); + next_load_addr = AppLoader_NSO::LoadModule(path, load_addr); if (next_load_addr) { LOG_DEBUG(Loader, "loaded module %s @ 0x%" PRIx64, module, load_addr); } else { diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index b87320656..cdd41f237 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -300,7 +300,7 @@ SharedPtr ElfReader::LoadInto(u32 vaddr) { std::vector program_image(total_image_size); size_t current_image_position = 0; - SharedPtr codeset = CodeSet::Create("", 0); + SharedPtr codeset = CodeSet::Create(""); for (unsigned int i = 0; i < header->e_phnum; ++i) { Elf32_Phdr* p = &segments[i]; @@ -406,7 +406,7 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr& process) { SharedPtr codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR); codeset->name = filename; - process = Kernel::Process::Create("main"); + process = Kernel::Process::Create("main", 0); process->LoadModule(codeset, codeset->entrypoint); process->svc_access_mask.set(); process->address_mappings = default_address_mappings; diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 6f8a2f21e..c557b66dc 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -83,7 +83,7 @@ bool AppLoader_NRO::LoadNro(const std::string& path, VAddr load_base) { } // Build program image - Kernel::SharedPtr codeset = Kernel::CodeSet::Create("", 0); + Kernel::SharedPtr codeset = Kernel::CodeSet::Create(""); std::vector program_image; program_image.resize(PageAlignSize(nro_header.file_size)); file.Seek(0, SEEK_SET); @@ -125,7 +125,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr& process) { return ResultStatus::Error; } - process = Kernel::Process::Create("main"); + process = Kernel::Process::Create("main", 0); // Load NRO static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR}; diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 7f8d24dd6..00b5d1d49 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -92,7 +92,7 @@ static constexpr u32 PageAlignSize(u32 size) { return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; } -VAddr AppLoader_NSO::LoadModule(const std::string& path, VAddr load_base, u64 tid) { +VAddr AppLoader_NSO::LoadModule(const std::string& path, VAddr load_base) { FileUtil::IOFile file(path, "rb"); if (!file.IsOpen()) { return {}; @@ -109,7 +109,7 @@ VAddr AppLoader_NSO::LoadModule(const std::string& path, VAddr load_base, u64 ti } // Build program image - Kernel::SharedPtr codeset = Kernel::CodeSet::Create("", tid); + Kernel::SharedPtr codeset = Kernel::CodeSet::Create(""); std::vector program_image; for (int i = 0; i < nso_header.segments.size(); ++i) { std::vector data = @@ -155,10 +155,10 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr& process) { return ResultStatus::Error; } - process = Kernel::Process::Create("main"); + process = Kernel::Process::Create("main", 0); // Load module - LoadModule(filepath, Memory::PROCESS_IMAGE_VADDR, 0); + LoadModule(filepath, Memory::PROCESS_IMAGE_VADDR); LOG_DEBUG(Loader, "loaded module %s @ 0x%" PRIx64, filepath.c_str(), Memory::PROCESS_IMAGE_VADDR); diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index 14eb1d87e..1ae30a824 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h @@ -29,7 +29,7 @@ public: return IdentifyType(file, filepath); } - static VAddr LoadModule(const std::string& path, VAddr load_base, u64 tid); + static VAddr LoadModule(const std::string& path, VAddr load_base); ResultStatus Load(Kernel::SharedPtr& process) override; diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp index 88bbbc95c..9296e1e94 100644 --- a/src/tests/core/arm/arm_test_common.cpp +++ b/src/tests/core/arm/arm_test_common.cpp @@ -15,7 +15,7 @@ static Memory::PageTable* page_table = nullptr; TestEnvironment::TestEnvironment(bool mutable_memory_) : mutable_memory(mutable_memory_), test_memory(std::make_shared(this)) { - Kernel::g_current_process = Kernel::Process::Create(""); + Kernel::g_current_process = Kernel::Process::Create("", 0); page_table = &Kernel::g_current_process->vm_manager.page_table; page_table->pointers.fill(nullptr); diff --git a/src/tests/core/memory/memory.cpp b/src/tests/core/memory/memory.cpp index 165496a54..0e0a43dcb 100644 --- a/src/tests/core/memory/memory.cpp +++ b/src/tests/core/memory/memory.cpp @@ -9,7 +9,7 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory][!hide]") { SECTION("these regions should not be mapped on an empty process") { - auto process = Kernel::Process::Create(""); + auto process = Kernel::Process::Create("", 0); CHECK(Memory::IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false); CHECK(Memory::IsValidVirtualAddress(*process, Memory::HEAP_VADDR) == false); CHECK(Memory::IsValidVirtualAddress(*process, Memory::LINEAR_HEAP_VADDR) == false); @@ -20,14 +20,14 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory][!hide]") { } SECTION("CONFIG_MEMORY_VADDR and SHARED_PAGE_VADDR should be valid after mapping them") { - auto process = Kernel::Process::Create(""); + auto process = Kernel::Process::Create("", 0); Kernel::MapSharedPages(process->vm_manager); CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == true); CHECK(Memory::IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == true); } SECTION("special regions should be valid after mapping them") { - auto process = Kernel::Process::Create(""); + auto process = Kernel::Process::Create("", 0); SECTION("VRAM") { Kernel::HandleSpecialMapping(process->vm_manager, {Memory::VRAM_VADDR, Memory::VRAM_SIZE, false, false}); @@ -48,7 +48,7 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory][!hide]") { } SECTION("Unmapping a VAddr should make it invalid") { - auto process = Kernel::Process::Create(""); + auto process = Kernel::Process::Create("", 0); Kernel::MapSharedPages(process->vm_manager); process->vm_manager.UnmapRange(Memory::CONFIG_MEMORY_VADDR, Memory::CONFIG_MEMORY_SIZE); CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false); From 3209cff5307ab16044ccc22e6b922545aae8215d Mon Sep 17 00:00:00 2001 From: Subv Date: Tue, 27 Feb 2018 10:23:35 -0500 Subject: [PATCH 5/5] SaveData: Use the current titleid when opening the savedata archive. --- src/core/file_sys/savedata_factory.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index 0df754e7c..4d83e100f 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -9,6 +9,7 @@ #include "common/string_util.h" #include "core/file_sys/disk_filesystem.h" #include "core/file_sys/savedata_factory.h" +#include "core/hle/kernel/process.h" namespace FileSys { @@ -16,8 +17,8 @@ SaveData_Factory::SaveData_Factory(std::string nand_directory) : nand_directory(std::move(nand_directory)) {} ResultVal> SaveData_Factory::Open(const Path& path) { - // TODO(Subv): Somehow obtain these values. - u64 title_id = 0; + u64 title_id = Kernel::g_current_process->program_id; + // TODO(Subv): Somehow obtain this value. u32 user = 0; std::string save_directory = Common::StringFromFormat("%ssave/%016" PRIX64 "/%08X", nand_directory.c_str(), title_id, user);