diff options
38 files changed, 607 insertions, 533 deletions
| diff --git a/.travis-build.sh b/.travis-build.sh index 78e7583a8..b869b8b8f 100644 --- a/.travis-build.sh +++ b/.travis-build.sh @@ -1,6 +1,7 @@  #!/bin/sh  set -e +set -x  #if OS is linux or is not set  if [ "$TRAVIS_OS_NAME" = linux -o -z "$TRAVIS_OS_NAME" ]; then  diff --git a/.travis-deps.sh b/.travis-deps.sh index b8e8417b2..8e22a6358 100644 --- a/.travis-deps.sh +++ b/.travis-deps.sh @@ -1,13 +1,14 @@  #!/bin/sh  set -e +set -x  #if OS is linux or is not set  if [ "$TRAVIS_OS_NAME" = linux -o -z "$TRAVIS_OS_NAME" ]; then      sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y      sudo apt-get -qq update -    sudo apt-get -qq install g++-4.8 xorg-dev libglu1-mesa-dev libxcursor-dev -    sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 90 +    sudo apt-get -qq install g++-4.9 xorg-dev libglu1-mesa-dev libxcursor-dev +    sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.9 90      (          git clone https://github.com/glfw/glfw.git --branch 3.0.4 --depth 1          mkdir glfw/build && cd glfw/build diff --git a/CMakeLists.txt b/CMakeLists.txt index 61d5d524a..63738b5ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,8 @@ cmake_minimum_required(VERSION 2.8.11)  project(citra)  if (NOT MSVC) -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-attributes") +    # -std=c++14 is only supported on very new compilers, so use the old c++1y alias instead. +    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -Wno-attributes")  else()      # Silence deprecation warnings      add_definitions(/D_CRT_SECURE_NO_WARNINGS) @@ -1,10 +1,12 @@ -citra emulator +Citra Emulator  ==============  [](https://travis-ci.org/citra-emu/citra) -An experimental open-source Nintendo 3DS emulator/debugger written in C++. Citra is written with portability in mind, with builds actively maintained for Windows, Linux and OS X. At this time, it only emulates a subset of 3DS hardware, and therefore is generally only useful for booting/debugging very simple homebrew demos. Citra is licensed under the GPLv2. Refer to the license.txt file included. Please read the [FAQ](https://github.com/citra-emu/citra/wiki/FAQ) before getting started with the project. +Citra is an experimental open-source Nintendo 3DS emulator/debugger written in C++. It is written with portability in mind, with builds actively maintained for Windows, Linux and OS X. At this time, it only emulates a subset of 3DS hardware, and therefore is generally only useful for booting/debugging very simple homebrew demos. However, this is changing as more and more progress is being made on running commercial titles, too. -For development discussion, please join us @ #citra on [freenode](http://webchat.freenode.net/). +Citra is licensed under the GPLv2. Refer to the license.txt file included. Please read the [FAQ](https://github.com/citra-emu/citra/wiki/FAQ) before getting started with the project. + +For development discussion, please join us @ #citra on [freenode](http://webchat.freenode.net/?channels=citra).  ### Development @@ -15,3 +17,15 @@ If you want to contribute please take a took at the [Contributor's Guide](CONTRI  * __Windows__: [Windows Build](https://github.com/citra-emu/citra/wiki/Windows-Build)  * __Linux__: [Linux Build](https://github.com/citra-emu/citra/wiki/Linux-Build)  * __OSX__: [OS X Build](https://github.com/citra-emu/citra/wiki/OS-X-Build) + + +### Support +If you like, you can [donate by PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=K899FANUJ2ZXW) - any donation received will go towards things like: +* 3DS consoles for developers to explore the hardware +* 3DS games for testing +* Any equipment required for homebrew +* Infrastructure setup +* Eventually 3D displays to get proper 3D output working +* ... etc ... +  +We also more than gladly accept used 3DS consoles, preferrably ones with firmware 4.5 or lower! If you would like to give yours away, don't hesitate to join our IRC channel #citra on [Freenode](http://webchat.freenode.net/?channels=citra) and talk to neobrain or bunnei. Mind you, IRC is slow-paced, so it might be a while until people reply. If you're in a hurry you can just leave contact details in the channel or via private message and we'll get back to you. diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 1299338ac..23d4925b8 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -157,12 +157,6 @@ void GMainWindow::BootGame(std::string filename)      LOG_INFO(Frontend, "Citra starting...\n");      System::Init(render_window); -    if (Core::Init()) { -        LOG_CRITICAL(Frontend, "Core initialization failed, exiting..."); -        Core::Stop(); -        exit(1); -    } -      // Load a game or die...      if (Loader::ResultStatus::Success != Loader::LoadFile(filename)) {          LOG_CRITICAL(Frontend, "Failed to load ROM!"); diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ab63f54de..198e4afd3 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -24,7 +24,6 @@ set(SRCS              file_sys/directory_romfs.cpp              file_sys/directory_sdmc.cpp              hle/kernel/address_arbiter.cpp -            hle/kernel/archive.cpp              hle/kernel/event.cpp              hle/kernel/kernel.cpp              hle/kernel/mutex.cpp @@ -32,21 +31,26 @@ set(SRCS              hle/kernel/shared_memory.cpp              hle/kernel/thread.cpp              hle/service/ac_u.cpp +            hle/service/am_app.cpp              hle/service/am_net.cpp              hle/service/apt_u.cpp              hle/service/boss_u.cpp +            hle/service/cecd_u.cpp              hle/service/cfg_i.cpp              hle/service/cfg_u.cpp              hle/service/csnd_snd.cpp              hle/service/dsp_dsp.cpp              hle/service/err_f.cpp -            hle/service/fs_user.cpp +            hle/service/fs/archive.cpp +            hle/service/fs/fs_user.cpp              hle/service/frd_u.cpp              hle/service/gsp_gpu.cpp              hle/service/hid_user.cpp              hle/service/ir_rst.cpp              hle/service/ir_u.cpp +            hle/service/ldr_ro.cpp              hle/service/mic_u.cpp +            hle/service/nim_aoc.cpp              hle/service/ndm_u.cpp              hle/service/nwm_uds.cpp              hle/service/pm_app.cpp @@ -93,17 +97,16 @@ set(HEADERS              arm/skyeye_common/vfp/vfp.h              arm/skyeye_common/vfp/vfp_helper.h              arm/arm_interface.h -            file_sys/archive.h +            file_sys/archive_backend.h              file_sys/archive_romfs.h              file_sys/archive_sdmc.h -            file_sys/file.h +            file_sys/file_backend.h              file_sys/file_romfs.h              file_sys/file_sdmc.h -            file_sys/directory.h +            file_sys/directory_backend.h              file_sys/directory_romfs.h              file_sys/directory_sdmc.h              hle/kernel/address_arbiter.h -            hle/kernel/archive.h              hle/kernel/event.h              hle/kernel/kernel.h              hle/kernel/mutex.h @@ -112,21 +115,26 @@ set(HEADERS              hle/kernel/shared_memory.h              hle/kernel/thread.h              hle/service/ac_u.h +            hle/service/am_app.h              hle/service/am_net.h              hle/service/apt_u.h              hle/service/boss_u.h +            hle/service/cecd_u.h              hle/service/cfg_i.h              hle/service/cfg_u.h              hle/service/csnd_snd.h              hle/service/dsp_dsp.h              hle/service/err_f.h -            hle/service/fs_user.h +            hle/service/fs/archive.h +            hle/service/fs/fs_user.h              hle/service/frd_u.h              hle/service/gsp_gpu.h              hle/service/hid_user.h              hle/service/ir_rst.h              hle/service/ir_u.h +            hle/service/ldr_ro.h              hle/service/mic_u.h +            hle/service/nim_aoc.h              hle/service/ndm_u.h              hle/service/nwm_uds.h              hle/service/pm_app.h diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index e4159ceb0..5752d116f 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -6101,17 +6101,32 @@ L_stm_s_takeabort:  			return 1;  		} -		case 0x6c: -			if ((instr & 0xf03f0) == 0xf0070) { //uxtb16 -				u8 rm_idx = BITS(0, 3); -				u8 rd_idx = BITS(12, 15); -				u32 rm_val = state->Reg[rm_idx]; -				u32 rotation = BITS(10, 11) * 8; -				u32 in = ((rm_val << (32 - rotation)) | (rm_val >> rotation)); -				state->Reg[rd_idx] = in & 0x00FF00FF; +		case 0x6c: // UXTB16 and UXTAB16 +			{ +				const u8 rm_idx = BITS(0, 3); +				const u8 rn_idx = BITS(16, 19); +				const u8 rd_idx = BITS(12, 15); +				const u32 rm_val = state->Reg[rm_idx]; +				const u32 rn_val = state->Reg[rn_idx]; +				const u32 rotation = BITS(10, 11) * 8; +				const u32 rotated_rm = ((rm_val << (32 - rotation)) | (rm_val >> rotation)); + +				// UXTB16 +				if ((instr & 0xf03f0) == 0xf0070) { +					state->Reg[rd_idx] = rotated_rm & 0x00FF00FF; +				} +				else { // UXTAB16 +					const u8 lo_rotated = (rotated_rm & 0xFF); +					const u16 lo_result = (rn_val & 0xFFFF) + (u16)lo_rotated; + +					const u8 hi_rotated = (rotated_rm >> 16) & 0xFF; +					const u16 hi_result = (rn_val >> 16) + (u16)hi_rotated; + +					state->Reg[rd_idx] = ((hi_result << 16) | (lo_result & 0xFFFF)); +				} +  				return 1; -			} else -				printf ("Unhandled v6 insn: uxtab16\n"); +			}  			break;  		case 0x6e: {  			ARMword Rm; diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp index 871900497..6c33d8b78 100644 --- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp @@ -614,7 +614,7 @@ static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 f          exceptions |= FPSCR_IDC;      if (tm & VFP_NAN) -        vsm.sign = 0; +        vsm.sign = 1;      if (vsm.exponent >= 127 + 32) {          d = vsm.sign ? 0 : 0xffffffff; @@ -1148,7 +1148,10 @@ static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)      /*       * Subtraction is addition with one sign inverted.       */ -    return vfp_single_fadd(state, sd, sn, vfp_single_packed_negate(m), fpscr); +    if (m != 0x7FC00000) // Only negate if m isn't NaN. +        m = vfp_single_packed_negate(m); + +    return vfp_single_fadd(state, sd, sn, m, fpscr);  }  /* diff --git a/src/core/file_sys/archive.h b/src/core/file_sys/archive_backend.h index 27ed23cd0..18c314884 100644 --- a/src/core/file_sys/archive.h +++ b/src/core/file_sys/archive_backend.h @@ -10,8 +10,8 @@  #include "common/string_util.h"  #include "common/bit_field.h" -#include "core/file_sys/file.h" -#include "core/file_sys/directory.h" +#include "core/file_sys/file_backend.h" +#include "core/file_sys/directory_backend.h"  #include "core/mem_map.h"  #include "core/hle/kernel/kernel.h" @@ -160,27 +160,14 @@ private:      std::u16string u16str;  }; -class Archive : NonCopyable { +class ArchiveBackend : NonCopyable {  public: -    /// Supported archive types -    enum class IdCode : u32 { -        RomFS               = 0x00000003, -        SaveData            = 0x00000004, -        ExtSaveData         = 0x00000006, -        SharedExtSaveData   = 0x00000007, -        SystemSaveData      = 0x00000008, -        SDMC                = 0x00000009, -        SDMCWriteOnly       = 0x0000000A, -    }; - -    Archive() { } -    virtual ~Archive() { } +    virtual ~ArchiveBackend() { }      /** -     * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.) -     * @return IdCode of the archive +     * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.)       */ -    virtual IdCode GetIdCode() const = 0; +    virtual std::string GetName() const = 0;      /**       * Open a file specified by its path, using the specified mode @@ -188,7 +175,7 @@ public:       * @param mode Mode to open the file with       * @return Opened file, or nullptr       */ -    virtual std::unique_ptr<File> OpenFile(const Path& path, const Mode mode) const = 0; +    virtual std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const = 0;      /**       * Delete a file specified by its path @@ -232,37 +219,7 @@ public:       * @param path Path relative to the archive       * @return Opened directory, or nullptr       */ -    virtual std::unique_ptr<Directory> OpenDirectory(const Path& path) const = 0; - -    /** -     * Read data from the archive -     * @param offset Offset in bytes to start reading data from -     * @param length Length in bytes of data to read from archive -     * @param buffer Buffer to read data into -     * @return Number of bytes read -     */ -    virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0; - -    /** -     * Write data to the archive -     * @param offset Offset in bytes to start writing data to -     * @param length Length in bytes of data to write to archive -     * @param buffer Buffer to write data from -     * @param flush  The flush parameters (0 == do not flush) -     * @return Number of bytes written -     */ -    virtual size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) = 0; - -    /** -     * Get the size of the archive in bytes -     * @return Size of the archive in bytes -     */ -    virtual size_t GetSize() const = 0; - -    /** -     * Set the size of the archive in bytes -     */ -    virtual void SetSize(const u64 size) = 0; +    virtual std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const = 0;  };  } // namespace FileSys diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp index 74974c2df..0709b62a1 100644 --- a/src/core/file_sys/archive_romfs.cpp +++ b/src/core/file_sys/archive_romfs.cpp @@ -2,6 +2,8 @@  // Licensed under GPLv2  // Refer to the license.txt file included. +#include <memory> +  #include "common/common_types.h"  #include "core/file_sys/archive_romfs.h" @@ -20,17 +22,14 @@ Archive_RomFS::Archive_RomFS(const Loader::AppLoader& app_loader) {      }  } -Archive_RomFS::~Archive_RomFS() { -} -  /**   * Open a file specified by its path, using the specified mode   * @param path Path relative to the archive   * @param mode Mode to open the file with   * @return Opened file, or nullptr   */ -std::unique_ptr<File> Archive_RomFS::OpenFile(const Path& path, const Mode mode) const { -    return std::unique_ptr<File>(new File_RomFS); +std::unique_ptr<FileBackend> Archive_RomFS::OpenFile(const Path& path, const Mode mode) const { +    return std::make_unique<File_RomFS>(this);  }  /** @@ -78,49 +77,8 @@ bool Archive_RomFS::RenameDirectory(const FileSys::Path& src_path, const FileSys   * @param path Path relative to the archive   * @return Opened directory, or nullptr   */ -std::unique_ptr<Directory> Archive_RomFS::OpenDirectory(const Path& path) const { -    return std::unique_ptr<Directory>(new Directory_RomFS); -} - -/** - * Read data from the archive - * @param offset Offset in bytes to start reading data from - * @param length Length in bytes of data to read from archive - * @param buffer Buffer to read data into - * @return Number of bytes read - */ -size_t Archive_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { -    LOG_TRACE(Service_FS, "called offset=%llu, length=%d", offset, length); -    memcpy(buffer, &raw_data[(u32)offset], length); -    return length; -} - -/** - * Write data to the archive - * @param offset Offset in bytes to start writing data to - * @param length Length in bytes of data to write to archive - * @param buffer Buffer to write data from - * @param flush  The flush parameters (0 == do not flush) - * @return Number of bytes written - */ -size_t Archive_RomFS::Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) { -    LOG_WARNING(Service_FS, "Attempted to write to ROMFS."); -    return 0; -} - -/** - * Get the size of the archive in bytes - * @return Size of the archive in bytes - */ -size_t Archive_RomFS::GetSize() const { -    return sizeof(u8) * raw_data.size(); -} - -/** - * Set the size of the archive in bytes - */ -void Archive_RomFS::SetSize(const u64 size) { -    LOG_WARNING(Service_FS, "Attempted to set the size of ROMFS"); +std::unique_ptr<DirectoryBackend> Archive_RomFS::OpenDirectory(const Path& path) const { +    return std::make_unique<Directory_RomFS>();  }  } // namespace FileSys diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index 222bdc356..5b1ee6332 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h @@ -8,7 +8,7 @@  #include "common/common_types.h" -#include "core/file_sys/archive.h" +#include "core/file_sys/archive_backend.h"  #include "core/loader/loader.h"  //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -17,16 +17,11 @@  namespace FileSys {  /// File system interface to the RomFS archive -class Archive_RomFS final : public Archive { +class Archive_RomFS final : public ArchiveBackend {  public:      Archive_RomFS(const Loader::AppLoader& app_loader); -    ~Archive_RomFS() override; -    /** -     * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.) -     * @return IdCode of the archive -     */ -    IdCode GetIdCode() const override { return IdCode::RomFS; } +    std::string GetName() const override { return "RomFS"; }      /**       * Open a file specified by its path, using the specified mode @@ -34,7 +29,7 @@ public:       * @param mode Mode to open the file with       * @return Opened file, or nullptr       */ -    std::unique_ptr<File> OpenFile(const Path& path, const Mode mode) const override; +    std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override;      /**       * Delete a file specified by its path @@ -78,39 +73,11 @@ public:       * @param path Path relative to the archive       * @return Opened directory, or nullptr       */ -    std::unique_ptr<Directory> OpenDirectory(const Path& path) const override; - -    /** -     * Read data from the archive -     * @param offset Offset in bytes to start reading data from -     * @param length Length in bytes of data to read from archive -     * @param buffer Buffer to read data into -     * @return Number of bytes read -     */ -    size_t Read(const u64 offset, const u32 length, u8* buffer) const override; - -    /** -     * Write data to the archive -     * @param offset Offset in bytes to start writing data to -     * @param length Length in bytes of data to write to archive -     * @param buffer Buffer to write data from -     * @param flush  The flush parameters (0 == do not flush) -     * @return Number of bytes written -     */ -    size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) override; - -    /** -     * Get the size of the archive in bytes -     * @return Size of the archive in bytes -     */ -    size_t GetSize() const override; - -    /** -     * Set the size of the archive in bytes -     */ -    void SetSize(const u64 size) override; +    std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;  private: +    friend class File_RomFS; +      std::vector<u8> raw_data;  }; diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp index 9e524b60e..9d58668e0 100644 --- a/src/core/file_sys/archive_sdmc.cpp +++ b/src/core/file_sys/archive_sdmc.cpp @@ -49,12 +49,12 @@ bool Archive_SDMC::Initialize() {   * @param mode Mode to open the file with   * @return Opened file, or nullptr   */ -std::unique_ptr<File> Archive_SDMC::OpenFile(const Path& path, const Mode mode) const { +std::unique_ptr<FileBackend> Archive_SDMC::OpenFile(const Path& path, const Mode mode) const {      LOG_DEBUG(Service_FS, "called path=%s mode=%u", path.DebugStr().c_str(), mode.hex);      File_SDMC* file = new File_SDMC(this, path, mode);      if (!file->Open())          return nullptr; -    return std::unique_ptr<File>(file); +    return std::unique_ptr<FileBackend>(file);  }  /** @@ -97,53 +97,12 @@ bool Archive_SDMC::RenameDirectory(const FileSys::Path& src_path, const FileSys:   * @param path Path relative to the archive   * @return Opened directory, or nullptr   */ -std::unique_ptr<Directory> Archive_SDMC::OpenDirectory(const Path& path) const { +std::unique_ptr<DirectoryBackend> Archive_SDMC::OpenDirectory(const Path& path) const {      LOG_DEBUG(Service_FS, "called path=%s", path.DebugStr().c_str());      Directory_SDMC* directory = new Directory_SDMC(this, path);      if (!directory->Open())          return nullptr; -    return std::unique_ptr<Directory>(directory); -} - -/** - * Read data from the archive - * @param offset Offset in bytes to start reading archive from - * @param length Length in bytes to read data from archive - * @param buffer Buffer to read data into - * @return Number of bytes read - */ -size_t Archive_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const { -    LOG_ERROR(Service_FS, "(UNIMPLEMENTED)"); -    return -1; -} - -/** - * Write data to the archive - * @param offset Offset in bytes to start writing data to - * @param length Length in bytes of data to write to archive - * @param buffer Buffer to write data from - * @param flush  The flush parameters (0 == do not flush) - * @return Number of bytes written - */ -size_t Archive_SDMC::Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) { -    LOG_ERROR(Service_FS, "(UNIMPLEMENTED)"); -    return -1; -} - -/** - * Get the size of the archive in bytes - * @return Size of the archive in bytes - */ -size_t Archive_SDMC::GetSize() const { -    LOG_ERROR(Service_FS, "(UNIMPLEMENTED)"); -    return 0; -} - -/** - * Set the size of the archive in bytes - */ -void Archive_SDMC::SetSize(const u64 size) { -    LOG_ERROR(Service_FS, "(UNIMPLEMENTED)"); +    return std::unique_ptr<DirectoryBackend>(directory);  }  /** diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h index 19f563a62..059045245 100644 --- a/src/core/file_sys/archive_sdmc.h +++ b/src/core/file_sys/archive_sdmc.h @@ -6,7 +6,7 @@  #include "common/common_types.h" -#include "core/file_sys/archive.h" +#include "core/file_sys/archive_backend.h"  #include "core/loader/loader.h"  //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -15,7 +15,7 @@  namespace FileSys {  /// File system interface to the SDMC archive -class Archive_SDMC final : public Archive { +class Archive_SDMC final : public ArchiveBackend {  public:      Archive_SDMC(const std::string& mount_point);      ~Archive_SDMC() override; @@ -26,11 +26,7 @@ public:       */      bool Initialize(); -    /** -     * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.) -     * @return IdCode of the archive -     */ -    IdCode GetIdCode() const override { return IdCode::SDMC; } +    std::string GetName() const override { return "SDMC"; }      /**       * Open a file specified by its path, using the specified mode @@ -38,7 +34,7 @@ public:       * @param mode Mode to open the file with       * @return Opened file, or nullptr       */ -    std::unique_ptr<File> OpenFile(const Path& path, const Mode mode) const override; +    std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override;      /**       * Delete a file specified by its path @@ -82,37 +78,7 @@ public:       * @param path Path relative to the archive       * @return Opened directory, or nullptr       */ -    std::unique_ptr<Directory> OpenDirectory(const Path& path) const override; - -    /** -     * Read data from the archive -     * @param offset Offset in bytes to start reading archive from -     * @param length Length in bytes to read data from archive -     * @param buffer Buffer to read data into -     * @return Number of bytes read -     */ -    size_t Read(const u64 offset, const u32 length, u8* buffer) const override; - -    /** -     * Write data to the archive -     * @param offset Offset in bytes to start writing data to -     * @param length Length in bytes of data to write to archive -     * @param buffer Buffer to write data from -     * @param flush  The flush parameters (0 == do not flush) -     * @return Number of bytes written -     */ -    size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) override; - -    /** -     * Get the size of the archive in bytes -     * @return Size of the archive in bytes -     */ -    size_t GetSize() const override; - -    /** -     * Set the size of the archive in bytes -     */ -    void SetSize(const u64 size) override; +    std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;      /**       * Getter for the path used for this Archive diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory_backend.h index 1bb4101d6..188746a6f 100644 --- a/src/core/file_sys/directory.h +++ b/src/core/file_sys/directory_backend.h @@ -36,10 +36,10 @@ static_assert(offsetof(Entry, extension) == 0x216, "Wrong offset for extension i  static_assert(offsetof(Entry, is_archive) == 0x21E, "Wrong offset for is_archive in Entry.");  static_assert(offsetof(Entry, file_size) == 0x220, "Wrong offset for file_size in Entry."); -class Directory : NonCopyable { +class DirectoryBackend : NonCopyable {  public: -    Directory() { } -    virtual ~Directory() { } +    DirectoryBackend() { } +    virtual ~DirectoryBackend() { }      /**      * Open the directory diff --git a/src/core/file_sys/directory_romfs.h b/src/core/file_sys/directory_romfs.h index e2944099e..b775f014d 100644 --- a/src/core/file_sys/directory_romfs.h +++ b/src/core/file_sys/directory_romfs.h @@ -6,7 +6,7 @@  #include "common/common_types.h" -#include "core/file_sys/directory.h" +#include "core/file_sys/directory_backend.h"  #include "core/loader/loader.h"  //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -14,7 +14,7 @@  namespace FileSys { -class Directory_RomFS final : public Directory { +class Directory_RomFS final : public DirectoryBackend {  public:      Directory_RomFS();      ~Directory_RomFS() override; diff --git a/src/core/file_sys/directory_sdmc.h b/src/core/file_sys/directory_sdmc.h index 4c08b0d61..407a256ef 100644 --- a/src/core/file_sys/directory_sdmc.h +++ b/src/core/file_sys/directory_sdmc.h @@ -7,7 +7,7 @@  #include "common/common_types.h"  #include "common/file_util.h" -#include "core/file_sys/directory.h" +#include "core/file_sys/directory_backend.h"  #include "core/file_sys/archive_sdmc.h"  #include "core/loader/loader.h" @@ -16,7 +16,7 @@  namespace FileSys { -class Directory_SDMC final : public Directory { +class Directory_SDMC final : public DirectoryBackend {  public:      Directory_SDMC();      Directory_SDMC(const Archive_SDMC* archive, const Path& path); diff --git a/src/core/file_sys/file.h b/src/core/file_sys/file_backend.h index 4013b6c3e..1b81d5fe9 100644 --- a/src/core/file_sys/file.h +++ b/src/core/file_sys/file_backend.h @@ -13,10 +13,10 @@  namespace FileSys { -class File : NonCopyable { +class FileBackend : NonCopyable {  public: -    File() { } -    virtual ~File() { } +    FileBackend() { } +    virtual ~FileBackend() { }      /**       * Open the file diff --git a/src/core/file_sys/file_romfs.cpp b/src/core/file_sys/file_romfs.cpp index b55708df4..5f38c2704 100644 --- a/src/core/file_sys/file_romfs.cpp +++ b/src/core/file_sys/file_romfs.cpp @@ -5,24 +5,19 @@  #include "common/common_types.h"  #include "core/file_sys/file_romfs.h" +#include "core/file_sys/archive_romfs.h"  ////////////////////////////////////////////////////////////////////////////////////////////////////  // FileSys namespace  namespace FileSys { -File_RomFS::File_RomFS() { -} - -File_RomFS::~File_RomFS() { -} -  /**   * Open the file   * @return true if the file opened correctly   */  bool File_RomFS::Open() { -    return false; +    return true;  }  /** @@ -33,7 +28,9 @@ bool File_RomFS::Open() {   * @return Number of bytes read   */  size_t File_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { -    return -1; +    LOG_TRACE(Service_FS, "called offset=%llu, length=%d", offset, length); +    memcpy(buffer, &archive->raw_data[(u32)offset], length); +    return length;  }  /** @@ -45,7 +42,8 @@ size_t File_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const {   * @return Number of bytes written   */  size_t File_RomFS::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { -    return -1; +    LOG_WARNING(Service_FS, "Attempted to write to ROMFS."); +    return 0;  }  /** @@ -53,7 +51,7 @@ size_t File_RomFS::Write(const u64 offset, const u32 length, const u32 flush, co   * @return Size of the file in bytes   */  size_t File_RomFS::GetSize() const { -    return -1; +    return sizeof(u8) * archive->raw_data.size();  }  /** @@ -62,6 +60,7 @@ size_t File_RomFS::GetSize() const {   * @return true if successful   */  bool File_RomFS::SetSize(const u64 size) const { +    LOG_WARNING(Service_FS, "Attempted to set the size of ROMFS");      return false;  } diff --git a/src/core/file_sys/file_romfs.h b/src/core/file_sys/file_romfs.h index 5196701d3..09fa2e7e3 100644 --- a/src/core/file_sys/file_romfs.h +++ b/src/core/file_sys/file_romfs.h @@ -6,7 +6,7 @@  #include "common/common_types.h" -#include "core/file_sys/file.h" +#include "core/file_sys/file_backend.h"  #include "core/loader/loader.h"  //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -14,10 +14,11 @@  namespace FileSys { -class File_RomFS final : public File { +class Archive_RomFS; + +class File_RomFS final : public FileBackend {  public: -    File_RomFS(); -    ~File_RomFS() override; +    File_RomFS(const Archive_RomFS* archive) : archive(archive) {}      /**       * Open the file @@ -62,6 +63,9 @@ public:       * @return true if the file closed correctly       */      bool Close() const override; + +private: +    const Archive_RomFS* archive;  };  } // namespace FileSys diff --git a/src/core/file_sys/file_sdmc.h b/src/core/file_sys/file_sdmc.h index 80b445968..e01548598 100644 --- a/src/core/file_sys/file_sdmc.h +++ b/src/core/file_sys/file_sdmc.h @@ -7,7 +7,7 @@  #include "common/common_types.h"  #include "common/file_util.h" -#include "core/file_sys/file.h" +#include "core/file_sys/file_backend.h"  #include "core/file_sys/archive_sdmc.h"  #include "core/loader/loader.h" @@ -16,7 +16,7 @@  namespace FileSys { -class File_SDMC final : public File { +class File_SDMC final : public FileBackend {  public:      File_SDMC();      File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode); diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp index 3f73b5538..cc3d5255a 100644 --- a/src/core/hle/hle.cpp +++ b/src/core/hle/hle.cpp @@ -8,6 +8,7 @@  #include "core/hle/hle.h"  #include "core/hle/kernel/thread.h"  #include "core/hle/service/service.h" +#include "core/hle/service/fs/archive.h"  //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -56,6 +57,7 @@ void RegisterAllModules() {  void Init() {      Service::Init(); +    Service::FS::ArchiveInit();      RegisterAllModules(); @@ -63,6 +65,7 @@ void Init() {  }  void Shutdown() { +    Service::FS::ArchiveShutdown();      Service::Shutdown();      g_module_db.clear(); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b38be0a49..929422b36 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -9,7 +9,6 @@  #include "core/core.h"  #include "core/hle/kernel/kernel.h"  #include "core/hle/kernel/thread.h" -#include "core/hle/kernel/archive.h"  namespace Kernel { @@ -89,13 +88,11 @@ Object* ObjectPool::CreateByIDType(int type) {  /// Initialize the kernel  void Init() {      Kernel::ThreadingInit(); -    Kernel::ArchiveInit();  }  /// Shutdown the kernel  void Shutdown() {      Kernel::ThreadingShutdown(); -    Kernel::ArchiveShutdown();      g_object_pool.Clear(); // Free all kernel objects  } @@ -106,8 +103,6 @@ void Shutdown() {   * @return True on success, otherwise false   */  bool LoadExec(u32 entry_point) { -    Init(); -      Core::g_app_core->SetPC(entry_point);      // 0x30 is the typical main thread priority I've seen used so far diff --git a/src/core/hle/service/am_app.cpp b/src/core/hle/service/am_app.cpp new file mode 100644 index 000000000..b8b06418c --- /dev/null +++ b/src/core/hle/service/am_app.cpp @@ -0,0 +1,24 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/am_app.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace AM_APP + +namespace AM_APP { + +// Empty arrays are illegal -- commented out until an entry is added. +//const Interface::FunctionInfo FunctionTable[] = { }; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { +    //Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +} // namespace diff --git a/src/core/hle/service/fs_user.h b/src/core/hle/service/am_app.h index 005382540..86a5f5b74 100644 --- a/src/core/hle/service/fs_user.h +++ b/src/core/hle/service/am_app.h @@ -1,5 +1,5 @@  // Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 +// Licensed under GPLv2+  // Refer to the license.txt file included.  #pragma once @@ -7,24 +7,20 @@  #include "core/hle/service/service.h"  //////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace FS_User +// Namespace AM_APP -namespace FS_User { +namespace AM_APP { -/// Interface to "fs:USER" service  class Interface : public Service::Interface {  public: -      Interface(); -    ~Interface(); -      /**       * Gets the string port name used by CTROS for the service       * @return Port name of service       */      std::string GetPortName() const override { -        return "fs:USER"; +        return "am:app";      }  }; diff --git a/src/core/hle/service/cecd_u.cpp b/src/core/hle/service/cecd_u.cpp new file mode 100644 index 000000000..25d903516 --- /dev/null +++ b/src/core/hle/service/cecd_u.cpp @@ -0,0 +1,24 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/cecd_u.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace CECD_U + +namespace CECD_U { + +// Empty arrays are illegal -- commented out until an entry is added. +//const Interface::FunctionInfo FunctionTable[] = { }; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { +    //Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +} // namespace diff --git a/src/core/hle/service/cecd_u.h b/src/core/hle/service/cecd_u.h new file mode 100644 index 000000000..969e1ed1b --- /dev/null +++ b/src/core/hle/service/cecd_u.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace CECD_U + +namespace CECD_U { + +class Interface : public Service::Interface { +public: +    Interface(); + +    /** +     * Gets the string port name used by CTROS for the service +     * @return Port name of service +     */ +    std::string GetPortName() const override { +        return "cecd:u"; +    } +}; + +} // namespace diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/service/fs/archive.cpp index 0e3eb4564..caf82d556 100644 --- a/src/core/hle/kernel/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -2,23 +2,37 @@  // Licensed under GPLv2  // Refer to the license.txt file included. -#include <map> +#include <memory> +#include <unordered_map>  #include "common/common_types.h"  #include "common/file_util.h"  #include "common/math_util.h" -#include "core/file_sys/archive.h" +#include "core/file_sys/archive_backend.h"  #include "core/file_sys/archive_sdmc.h" -#include "core/file_sys/directory.h" -#include "core/hle/kernel/archive.h" +#include "core/file_sys/directory_backend.h" +#include "core/hle/service/fs/archive.h"  #include "core/hle/kernel/session.h"  #include "core/hle/result.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Kernel namespace +// Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map. +// Workaroung for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970 +namespace std { +    template <> +    struct hash<Service::FS::ArchiveIdCode> { +        typedef Service::FS::ArchiveIdCode argument_type; +        typedef std::size_t result_type; + +        result_type operator()(const argument_type& id_code) const { +            typedef std::underlying_type<argument_type>::type Type; +            return std::hash<Type>()(static_cast<Type>(id_code)); +        } +    }; +} -namespace Kernel { +namespace Service { +namespace FS {  // Command to access archive file  enum class FileCommand : u32 { @@ -43,78 +57,28 @@ enum class DirectoryCommand : u32 {      Close           = 0x08020000,  }; -class Archive : public Kernel::Session { +class Archive {  public: -    std::string GetName() const override { return "Archive: " + name; } - -    std::string name;           ///< Name of archive (optional) -    FileSys::Archive* backend;  ///< Archive backend interface - -    ResultVal<bool> SyncRequest() override { -        u32* cmd_buff = Kernel::GetCommandBuffer(); -        FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); +    Archive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code) +            : backend(std::move(backend)), id_code(id_code) { +    } -        switch (cmd) { -        // Read from archive... -        case FileCommand::Read: -        { -            u64 offset  = cmd_buff[1] | ((u64)cmd_buff[2] << 32); -            u32 length  = cmd_buff[3]; -            u32 address = cmd_buff[5]; +    std::string GetName() const { return "Archive: " + backend->GetName(); } -            // Number of bytes read -            cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address)); -            break; -        } -        // Write to archive... -        case FileCommand::Write: -        { -            u64 offset  = cmd_buff[1] | ((u64)cmd_buff[2] << 32); -            u32 length  = cmd_buff[3]; -            u32 flush   = cmd_buff[4]; -            u32 address = cmd_buff[6]; - -            // Number of bytes written -            cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address)); -            break; -        } -        case FileCommand::GetSize: -        { -            u64 filesize = (u64) backend->GetSize(); -            cmd_buff[2]  = (u32) filesize;         // Lower word -            cmd_buff[3]  = (u32) (filesize >> 32); // Upper word -            break; -        } -        case FileCommand::SetSize: -        { -            backend->SetSize(cmd_buff[1] | ((u64)cmd_buff[2] << 32)); -            break; -        } -        case FileCommand::Close: -        { -            LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); -            CloseArchive(backend->GetIdCode()); -            break; -        } -        // Unknown command... -        default: -        { -            LOG_ERROR(Service_FS, "Unknown command=0x%08X", cmd); -            cmd_buff[0] = UnimplementedFunction(ErrorModule::FS).raw; -            return MakeResult<bool>(false); -        } -        } -        cmd_buff[1] = 0; // No error -        return MakeResult<bool>(false); -    } +    ArchiveIdCode id_code; ///< Id code of the archive +    std::unique_ptr<FileSys::ArchiveBackend> backend; ///< Archive backend interface  };  class File : public Kernel::Session {  public: +    File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path) +            : backend(std::move(backend)), path(path) { +    } +      std::string GetName() const override { return "Path: " + path.DebugStr(); }      FileSys::Path path; ///< Path of the file -    std::unique_ptr<FileSys::File> backend; ///< File backend interface +    std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface      ResultVal<bool> SyncRequest() override {          u32* cmd_buff = Kernel::GetCommandBuffer(); @@ -185,10 +149,14 @@ public:  class Directory : public Kernel::Session {  public: +    Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path) +            : backend(std::move(backend)), path(path) { +    } +      std::string GetName() const override { return "Directory: " + path.DebugStr(); }      FileSys::Path path; ///< Path of the directory -    std::unique_ptr<FileSys::Directory> backend; ///< File backend interface +    std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface      ResultVal<bool> SyncRequest() override {          u32* cmd_buff = Kernel::GetCommandBuffer(); @@ -230,105 +198,95 @@ public:  //////////////////////////////////////////////////////////////////////////////////////////////////// -std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode +/** + * Map of registered archives, identified by id code. Once an archive is registered here, it is + * never removed until the FS service is shut down. + */ +static std::unordered_map<ArchiveIdCode, std::unique_ptr<Archive>> id_code_map; + +/** + * Map of active archive handles. Values are pointers to the archives in `idcode_map`. + */ +static std::unordered_map<ArchiveHandle, Archive*> handle_map; +static ArchiveHandle next_handle; + +static Archive* GetArchive(ArchiveHandle handle) { +    auto itr = handle_map.find(handle); +    return (itr == handle_map.end()) ? nullptr : itr->second; +} + +ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code) { +    LOG_TRACE(Service_FS, "Opening archive with id code 0x%08X", id_code); -ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code) { -    auto itr = g_archive_map.find(id_code); -    if (itr == g_archive_map.end()) { +    auto itr = id_code_map.find(id_code); +    if (itr == id_code_map.end()) { +        // TODO: Verify error against hardware          return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,                  ErrorSummary::NotFound, ErrorLevel::Permanent);      } -    return MakeResult<Handle>(itr->second); +    // This should never even happen in the first place with 64-bit handles,  +    while (handle_map.count(next_handle) != 0) { +        ++next_handle; +    } +    handle_map.emplace(next_handle, itr->second.get()); +    return MakeResult<ArchiveHandle>(next_handle++);  } -ResultCode CloseArchive(FileSys::Archive::IdCode id_code) { -    auto itr = g_archive_map.find(id_code); -    if (itr == g_archive_map.end()) { -        LOG_ERROR(Service_FS, "Cannot close archive %d, does not exist!", (int)id_code); +ResultCode CloseArchive(ArchiveHandle handle) { +    if (handle_map.erase(handle) == 0)          return InvalidHandle(ErrorModule::FS); -    } - -    LOG_TRACE(Service_FS, "Closed archive %d", (int) id_code); -    return RESULT_SUCCESS; +    else +        return RESULT_SUCCESS;  } -/** - * Mounts an archive - * @param archive Pointer to the archive to mount - */ -ResultCode MountArchive(Archive* archive) { -    FileSys::Archive::IdCode id_code = archive->backend->GetIdCode(); -    ResultVal<Handle> archive_handle = OpenArchive(id_code); -    if (archive_handle.Succeeded()) { -        LOG_ERROR(Service_FS, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); -        return archive_handle.Code(); -    } -    g_archive_map[id_code] = archive->GetHandle(); -    LOG_TRACE(Service_FS, "Mounted archive %s", archive->GetName().c_str()); -    return RESULT_SUCCESS; -} +// TODO(yuriks): This might be what the fs:REG service is for. See the Register/Unregister calls in +// http://3dbrew.org/wiki/Filesystem_services#ProgramRegistry_service_.22fs:REG.22 +ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code) { +    auto result = id_code_map.emplace(id_code, std::make_unique<Archive>(std::move(backend), id_code)); -ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name) { -    Archive* archive = new Archive; -    Handle handle = Kernel::g_object_pool.Create(archive); -    archive->name = name; -    archive->backend = backend; +    bool inserted = result.second; +    _dbg_assert_msg_(Service_FS, inserted, "Tried to register more than one archive with same id code"); -    ResultCode result = MountArchive(archive); -    if (result.IsError()) { -        return result; -    } -     +    auto& archive = result.first->second; +    LOG_DEBUG(Service_FS, "Registered archive %s with id code 0x%08X", archive->GetName().c_str(), id_code);      return RESULT_SUCCESS;  } -ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { -    // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create -    // the archive file handles at app loading, and then keep them persistent throughout execution. -    // Archives file handles are just reused and not actually freed until emulation shut down. -    // Verify if real hardware works this way, or if new handles are created each time -    if (path.GetType() == FileSys::Binary) -        // TODO(bunnei): FixMe - this is a hack to compensate for an incorrect FileSys backend -        // design. While the functionally of this is OK, our implementation decision to separate -        // normal files from archive file pointers is very likely wrong. -        // See https://github.com/citra-emu/citra/issues/205 -        return MakeResult<Handle>(archive_handle); - -    File* file = new File; -    Handle handle = Kernel::g_object_pool.Create(file); - -    Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle); -    if (archive == nullptr) { +ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { +    Archive* archive = GetArchive(archive_handle); +    if (archive == nullptr)          return InvalidHandle(ErrorModule::FS); -    } -    file->path = path; -    file->backend = archive->backend->OpenFile(path, mode); -    if (!file->backend) { +    std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode); +    if (backend == nullptr) {          return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, -                ErrorSummary::NotFound, ErrorLevel::Permanent); +                          ErrorSummary::NotFound, ErrorLevel::Permanent);      } +    auto file = std::make_unique<File>(std::move(backend), path); +    Handle handle = Kernel::g_object_pool.Create(file.release());      return MakeResult<Handle>(handle);  } -ResultCode DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path) { -    Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); +ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { +    Archive* archive = GetArchive(archive_handle);      if (archive == nullptr)          return InvalidHandle(ErrorModule::FS); +      if (archive->backend->DeleteFile(path))          return RESULT_SUCCESS;      return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description                        ErrorSummary::Canceled, ErrorLevel::Status);  } -ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, -                                     Handle dest_archive_handle, const FileSys::Path& dest_path) { -    Archive* src_archive = Kernel::g_object_pool.GetFast<Archive>(src_archive_handle); -    Archive* dest_archive = Kernel::g_object_pool.GetFast<Archive>(dest_archive_handle); +ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, +                                     ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) { +    Archive* src_archive = GetArchive(src_archive_handle); +    Archive* dest_archive = GetArchive(dest_archive_handle);      if (src_archive == nullptr || dest_archive == nullptr)          return InvalidHandle(ErrorModule::FS); +      if (src_archive == dest_archive) {          if (src_archive->backend->RenameFile(src_path, dest_path))              return RESULT_SUCCESS; @@ -336,36 +294,42 @@ ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::P          // TODO: Implement renaming across archives          return UnimplementedFunction(ErrorModule::FS);      } + +    // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't +    // exist or similar. Verify.      return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description                        ErrorSummary::NothingHappened, ErrorLevel::Status);  } -ResultCode DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { -    Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); +ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { +    Archive* archive = GetArchive(archive_handle);      if (archive == nullptr)          return InvalidHandle(ErrorModule::FS); +      if (archive->backend->DeleteDirectory(path))          return RESULT_SUCCESS;      return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description                        ErrorSummary::Canceled, ErrorLevel::Status);  } -ResultCode CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { -    Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); +ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { +    Archive* archive = GetArchive(archive_handle);      if (archive == nullptr)          return InvalidHandle(ErrorModule::FS); +      if (archive->backend->CreateDirectory(path))          return RESULT_SUCCESS;      return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description                        ErrorSummary::Canceled, ErrorLevel::Status);  } -ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, -                                          Handle dest_archive_handle, const FileSys::Path& dest_path) { -    Archive* src_archive = Kernel::g_object_pool.GetFast<Archive>(src_archive_handle); -    Archive* dest_archive = Kernel::g_object_pool.GetFast<Archive>(dest_archive_handle); +ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, +                                          ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) { +    Archive* src_archive = GetArchive(src_archive_handle); +    Archive* dest_archive = GetArchive(dest_archive_handle);      if (src_archive == nullptr || dest_archive == nullptr)          return InvalidHandle(ErrorModule::FS); +      if (src_archive == dest_archive) {          if (src_archive->backend->RenameDirectory(src_path, dest_path))              return RESULT_SUCCESS; @@ -373,6 +337,9 @@ ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileS          // TODO: Implement renaming across archives          return UnimplementedFunction(ErrorModule::FS);      } + +    // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't +    // exist or similar. Verify.      return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description                        ErrorSummary::NothingHappened, ErrorLevel::Status);  } @@ -383,44 +350,43 @@ ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileS   * @param path Path to the Directory inside of the Archive   * @return Opened Directory object   */ -ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { -    Directory* directory = new Directory; -    Handle handle = Kernel::g_object_pool.Create(directory); - -    Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle); -    if (archive == nullptr) { +ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { +    Archive* archive = GetArchive(archive_handle); +    if (archive == nullptr)          return InvalidHandle(ErrorModule::FS); -    } -    directory->path = path; -    directory->backend = archive->backend->OpenDirectory(path); -    if (!directory->backend) { +    std::unique_ptr<FileSys::DirectoryBackend> backend = archive->backend->OpenDirectory(path); +    if (backend == nullptr) {          return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,                            ErrorSummary::NotFound, ErrorLevel::Permanent);      } +    auto directory = std::make_unique<Directory>(std::move(backend), path); +    Handle handle = Kernel::g_object_pool.Create(directory.release());      return MakeResult<Handle>(handle);  }  /// Initialize archives  void ArchiveInit() { -    g_archive_map.clear(); +    next_handle = 1;      // TODO(Link Mauve): Add the other archive types (see here for the known types:      // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes).  Currently the only half-finished      // archive type is SDMC, so it is the only one getting exposed.      std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); -    auto archive = new FileSys::Archive_SDMC(sdmc_directory); +    auto archive = std::make_unique<FileSys::Archive_SDMC>(sdmc_directory);      if (archive->Initialize()) -        CreateArchive(archive, "SDMC"); +        CreateArchive(std::move(archive), ArchiveIdCode::SDMC);      else          LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());  }  /// Shutdown archives  void ArchiveShutdown() { -    g_archive_map.clear(); +    handle_map.clear(); +    id_code_map.clear();  } -} // namespace Kernel +} // namespace FS +} // namespace Service diff --git a/src/core/hle/kernel/archive.h b/src/core/hle/service/fs/archive.h index b50833a2b..a38de92e3 100644 --- a/src/core/hle/kernel/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -6,34 +6,45 @@  #include "common/common_types.h" -#include "core/file_sys/archive.h" +#include "core/file_sys/archive_backend.h"  #include "core/hle/kernel/kernel.h"  #include "core/hle/result.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Kernel namespace +namespace Service { +namespace FS { -namespace Kernel { +/// Supported archive types +enum class ArchiveIdCode : u32 { +    RomFS               = 0x00000003, +    SaveData            = 0x00000004, +    ExtSaveData         = 0x00000006, +    SharedExtSaveData   = 0x00000007, +    SystemSaveData      = 0x00000008, +    SDMC                = 0x00000009, +    SDMCWriteOnly       = 0x0000000A, +}; + +typedef u64 ArchiveHandle;  /**   * Opens an archive   * @param id_code IdCode of the archive to open   * @return Handle to the opened archive   */ -ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code); +ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code);  /**   * Closes an archive   * @param id_code IdCode of the archive to open   */ -ResultCode CloseArchive(FileSys::Archive::IdCode id_code); +ResultCode CloseArchive(ArchiveHandle handle);  /**   * Creates an Archive   * @param backend File system backend interface to the archive - * @param name Name of Archive + * @param id_code Id code used to access this type of archive   */ -ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name); +ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code);  /**   * Open a File from an Archive @@ -42,7 +53,7 @@ ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name);   * @param mode Mode under which to open the File   * @return Handle to the opened File object   */ -ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode); +ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode);  /**   * Delete a File from an Archive @@ -50,7 +61,7 @@ ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path   * @param path Path to the File inside of the Archive   * @return Whether deletion succeeded   */ -ResultCode DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path); +ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path);  /**   * Rename a File between two Archives @@ -60,8 +71,8 @@ ResultCode DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& pat   * @param dest_path Path to the File inside of the destination Archive   * @return Whether rename succeeded   */ -ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, -                                     Handle dest_archive_handle, const FileSys::Path& dest_path); +ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, +                                     ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path);  /**   * Delete a Directory from an Archive @@ -69,7 +80,7 @@ ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::P   * @param path Path to the Directory inside of the Archive   * @return Whether deletion succeeded   */ -ResultCode DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); +ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path);  /**   * Create a Directory from an Archive @@ -77,7 +88,7 @@ ResultCode DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path   * @param path Path to the Directory inside of the Archive   * @return Whether creation of directory succeeded   */ -ResultCode CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); +ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path);  /**   * Rename a Directory between two Archives @@ -87,8 +98,8 @@ ResultCode CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path   * @param dest_path Path to the Directory inside of the destination Archive   * @return Whether rename succeeded   */ -ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, -                                          Handle dest_archive_handle, const FileSys::Path& dest_path); +ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, +                                          ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path);  /**   * Open a Directory from an Archive @@ -96,7 +107,7 @@ ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileS   * @param path Path to the Directory inside of the Archive   * @return Handle to the opened File object   */ -ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); +ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path);  /// Initialize archives  void ArchiveInit(); @@ -104,4 +115,5 @@ void ArchiveInit();  /// Shutdown archives  void ArchiveShutdown(); -} // namespace FileSys +} // namespace FS +} // namespace Service diff --git a/src/core/hle/service/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 672ba2475..0f75d5e3a 100644 --- a/src/core/hle/service/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -3,18 +3,23 @@  // Refer to the license.txt file included.  #include "common/common.h" +#include "common/scope_exit.h"  #include "common/string_util.h" -#include "core/hle/kernel/archive.h" -#include "core/hle/kernel/archive.h" +#include "core/hle/service/fs/archive.h"  #include "core/hle/result.h" -#include "core/hle/service/fs_user.h" +#include "core/hle/service/fs/fs_user.h"  #include "core/settings.h"  ////////////////////////////////////////////////////////////////////////////////////////////////////  // Namespace FS_User -namespace FS_User { +namespace Service { +namespace FS { + +static ArchiveHandle MakeArchiveHandle(u32 low_word, u32 high_word) { +    return (u64)low_word | ((u64)high_word << 32); +}  static void Initialize(Service::Interface* self) {      u32* cmd_buff = Kernel::GetCommandBuffer(); @@ -57,11 +62,12 @@ static void OpenFile(Service::Interface* self) {      LOG_DEBUG(Service_FS, "path=%s, mode=%d attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes); -    ResultVal<Handle> handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode); +    ResultVal<Handle> handle = OpenFileFromArchive(archive_handle, file_path, mode);      cmd_buff[1] = handle.Code().raw;      if (handle.Succeeded()) {          cmd_buff[3] = *handle;      } else { +        cmd_buff[3] = 0;          LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str());      }  } @@ -88,7 +94,7 @@ static void OpenFile(Service::Interface* self) {  static void OpenFileDirectly(Service::Interface* self) {      u32* cmd_buff = Kernel::GetCommandBuffer(); -    auto archive_id       = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]); +    auto archive_id       = static_cast<FS::ArchiveIdCode>(cmd_buff[2]);      auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[3]);      u32 archivename_size  = cmd_buff[4];      auto filename_type    = static_cast<FileSys::LowPathType>(cmd_buff[5]); @@ -106,25 +112,25 @@ static void OpenFileDirectly(Service::Interface* self) {      if (archive_path.GetType() != FileSys::Empty) {          LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported");          cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; +        cmd_buff[3] = 0;          return;      } -    // TODO(Link Mauve): Check if we should even get a handle for the archive, and don't leak it -    // TODO(yuriks): Why is there all this duplicate (and seemingly useless) code up here? -    ResultVal<Handle> archive_handle = Kernel::OpenArchive(archive_id); -    cmd_buff[1] = archive_handle.Code().raw; +    ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id);      if (archive_handle.Failed()) {          LOG_ERROR(Service_FS, "failed to get a handle for archive"); +        cmd_buff[1] = archive_handle.Code().raw; +        cmd_buff[3] = 0;          return;      } -    // cmd_buff[2] isn't used according to 3dmoo's implementation. -    cmd_buff[3] = *archive_handle; +    SCOPE_EXIT({ CloseArchive(*archive_handle); }); -    ResultVal<Handle> handle = Kernel::OpenFileFromArchive(*archive_handle, file_path, mode); +    ResultVal<Handle> handle = OpenFileFromArchive(*archive_handle, file_path, mode);      cmd_buff[1] = handle.Code().raw;      if (handle.Succeeded()) {          cmd_buff[3] = *handle;      } else { +        cmd_buff[3] = 0;          LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str());      }  } @@ -140,12 +146,10 @@ static void OpenFileDirectly(Service::Interface* self) {   *  Outputs:   *      1 : Result of function, 0 on success, otherwise error code   */ -void DeleteFile(Service::Interface* self) { +static void DeleteFile(Service::Interface* self) {      u32* cmd_buff = Kernel::GetCommandBuffer(); -    // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to -    // 3dmoo's or ctrulib's implementations.  Triple check if it's really the case. -    Handle archive_handle = static_cast<Handle>(cmd_buff[3]); +    ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);      auto filename_type    = static_cast<FileSys::LowPathType>(cmd_buff[4]);      u32 filename_size     = cmd_buff[5];      u32 filename_ptr      = cmd_buff[7]; @@ -155,7 +159,7 @@ void DeleteFile(Service::Interface* self) {      LOG_DEBUG(Service_FS, "type=%d size=%d data=%s",                filename_type, filename_size, file_path.DebugStr().c_str()); -    cmd_buff[1] = Kernel::DeleteFileFromArchive(archive_handle, file_path).raw; +    cmd_buff[1] = DeleteFileFromArchive(archive_handle, file_path).raw;  }  /* @@ -174,15 +178,13 @@ void DeleteFile(Service::Interface* self) {   *  Outputs:   *      1 : Result of function, 0 on success, otherwise error code   */ -void RenameFile(Service::Interface* self) { +static void RenameFile(Service::Interface* self) {      u32* cmd_buff = Kernel::GetCommandBuffer(); -    // TODO(Link Mauve): cmd_buff[2] and cmd_buff[6], aka archive handle lower word, aren't used according to -    // 3dmoo's or ctrulib's implementations.  Triple check if it's really the case. -    Handle src_archive_handle  = static_cast<Handle>(cmd_buff[3]); +    ArchiveHandle src_archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);      auto src_filename_type     = static_cast<FileSys::LowPathType>(cmd_buff[4]);      u32 src_filename_size      = cmd_buff[5]; -    Handle dest_archive_handle = static_cast<Handle>(cmd_buff[7]); +    ArchiveHandle dest_archive_handle = MakeArchiveHandle(cmd_buff[6], cmd_buff[7]);;      auto dest_filename_type    = static_cast<FileSys::LowPathType>(cmd_buff[8]);      u32 dest_filename_size     = cmd_buff[9];      u32 src_filename_ptr       = cmd_buff[11]; @@ -195,7 +197,7 @@ void RenameFile(Service::Interface* self) {                src_filename_type, src_filename_size, src_file_path.DebugStr().c_str(),                dest_filename_type, dest_filename_size, dest_file_path.DebugStr().c_str()); -    cmd_buff[1] = Kernel::RenameFileBetweenArchives(src_archive_handle, src_file_path, dest_archive_handle, dest_file_path).raw; +    cmd_buff[1] = RenameFileBetweenArchives(src_archive_handle, src_file_path, dest_archive_handle, dest_file_path).raw;  }  /* @@ -209,12 +211,10 @@ void RenameFile(Service::Interface* self) {   *  Outputs:   *      1 : Result of function, 0 on success, otherwise error code   */ -void DeleteDirectory(Service::Interface* self) { +static void DeleteDirectory(Service::Interface* self) {      u32* cmd_buff = Kernel::GetCommandBuffer(); -    // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to -    // 3dmoo's or ctrulib's implementations.  Triple check if it's really the case. -    Handle archive_handle = static_cast<Handle>(cmd_buff[3]); +    ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);      auto dirname_type     = static_cast<FileSys::LowPathType>(cmd_buff[4]);      u32 dirname_size      = cmd_buff[5];      u32 dirname_ptr       = cmd_buff[7]; @@ -224,7 +224,7 @@ void DeleteDirectory(Service::Interface* self) {      LOG_DEBUG(Service_FS, "type=%d size=%d data=%s",                dirname_type, dirname_size, dir_path.DebugStr().c_str()); -    cmd_buff[1] = Kernel::DeleteDirectoryFromArchive(archive_handle, dir_path).raw; +    cmd_buff[1] = DeleteDirectoryFromArchive(archive_handle, dir_path).raw;  }  /* @@ -241,9 +241,7 @@ void DeleteDirectory(Service::Interface* self) {  static void CreateDirectory(Service::Interface* self) {      u32* cmd_buff = Kernel::GetCommandBuffer(); -    // TODO: cmd_buff[2], aka archive handle lower word, isn't used according to -    // 3dmoo's or ctrulib's implementations.  Triple check if it's really the case. -    Handle archive_handle = static_cast<Handle>(cmd_buff[3]); +    ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);      auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);      u32 dirname_size = cmd_buff[5];      u32 dirname_ptr = cmd_buff[8]; @@ -252,7 +250,7 @@ static void CreateDirectory(Service::Interface* self) {      LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); -    cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_path).raw; +    cmd_buff[1] = CreateDirectoryFromArchive(archive_handle, dir_path).raw;  }  /* @@ -271,15 +269,13 @@ static void CreateDirectory(Service::Interface* self) {   *  Outputs:   *      1 : Result of function, 0 on success, otherwise error code   */ -void RenameDirectory(Service::Interface* self) { +static void RenameDirectory(Service::Interface* self) {      u32* cmd_buff = Kernel::GetCommandBuffer(); -    // TODO(Link Mauve): cmd_buff[2] and cmd_buff[6], aka archive handle lower word, aren't used according to -    // 3dmoo's or ctrulib's implementations.  Triple check if it's really the case. -    Handle src_archive_handle  = static_cast<Handle>(cmd_buff[3]); +    ArchiveHandle src_archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);      auto src_dirname_type      = static_cast<FileSys::LowPathType>(cmd_buff[4]);      u32 src_dirname_size       = cmd_buff[5]; -    Handle dest_archive_handle = static_cast<Handle>(cmd_buff[7]); +    ArchiveHandle dest_archive_handle = MakeArchiveHandle(cmd_buff[6], cmd_buff[7]);      auto dest_dirname_type     = static_cast<FileSys::LowPathType>(cmd_buff[8]);      u32 dest_dirname_size      = cmd_buff[9];      u32 src_dirname_ptr        = cmd_buff[11]; @@ -292,15 +288,26 @@ void RenameDirectory(Service::Interface* self) {                src_dirname_type, src_dirname_size, src_dir_path.DebugStr().c_str(),                dest_dirname_type, dest_dirname_size, dest_dir_path.DebugStr().c_str()); -    cmd_buff[1] = Kernel::RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle, dest_dir_path).raw; +    cmd_buff[1] = RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle, dest_dir_path).raw;  } +/** + * FS_User::OpenDirectory service function + *  Inputs: + *      1 : Archive handle low word + *      2 : Archive handle high word + *      3 : Low path type + *      4 : Low path size + *      7 : (LowPathSize << 14) | 2 + *      8 : Low path data pointer + *  Outputs: + *      1 : Result of function, 0 on success, otherwise error code + *      3 : Directory handle + */  static void OpenDirectory(Service::Interface* self) {      u32* cmd_buff = Kernel::GetCommandBuffer(); -    // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to -    // 3dmoo's or ctrulib's implementations.  Triple check if it's really the case. -    Handle archive_handle = static_cast<Handle>(cmd_buff[2]); +    ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]);      auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[3]);      u32 dirname_size = cmd_buff[4];      u32 dirname_ptr = cmd_buff[6]; @@ -309,7 +316,7 @@ static void OpenDirectory(Service::Interface* self) {      LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); -    ResultVal<Handle> handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_path); +    ResultVal<Handle> handle = OpenDirectoryFromArchive(archive_handle, dir_path);      cmd_buff[1] = handle.Code().raw;      if (handle.Succeeded()) {          cmd_buff[3] = *handle; @@ -334,7 +341,7 @@ static void OpenDirectory(Service::Interface* self) {  static void OpenArchive(Service::Interface* self) {      u32* cmd_buff = Kernel::GetCommandBuffer(); -    auto archive_id       = static_cast<FileSys::Archive::IdCode>(cmd_buff[1]); +    auto archive_id       = static_cast<FS::ArchiveIdCode>(cmd_buff[1]);      auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]);      u32 archivename_size  = cmd_buff[3];      u32 archivename_ptr   = cmd_buff[5]; @@ -348,16 +355,34 @@ static void OpenArchive(Service::Interface* self) {          return;      } -    ResultVal<Handle> handle = Kernel::OpenArchive(archive_id); +    ResultVal<ArchiveHandle> handle = OpenArchive(archive_id);      cmd_buff[1] = handle.Code().raw;      if (handle.Succeeded()) { -        // cmd_buff[2] isn't used according to 3dmoo's implementation. -        cmd_buff[3] = *handle; +        cmd_buff[2] = *handle & 0xFFFFFFFF; +        cmd_buff[3] = (*handle >> 32) & 0xFFFFFFFF;      } else { +        cmd_buff[2] = cmd_buff[3] = 0;          LOG_ERROR(Service_FS, "failed to get a handle for archive");      }  } +/** + * FS_User::CloseArchive service function + *  Inputs: + *      0 : 0x080E0080 + *      1 : Archive handle low word + *      2 : Archive handle high word + *  Outputs: + *      0 : ??? TODO(yuriks): Verify return header + *      1 : Result of function, 0 on success, otherwise error code + */ +static void CloseArchive(Service::Interface* self) { +    u32* cmd_buff = Kernel::GetCommandBuffer(); + +    ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]); +    cmd_buff[1] = CloseArchive(archive_handle).raw; +} +  /*  * FS_User::IsSdmcDetected service function  *  Outputs: @@ -373,7 +398,7 @@ static void IsSdmcDetected(Service::Interface* self) {      LOG_DEBUG(Service_FS, "called");  } -const Interface::FunctionInfo FunctionTable[] = { +const FSUserInterface::FunctionInfo FunctionTable[] = {      {0x000100C6, nullptr,               "Dummy1"},      {0x040100C4, nullptr,               "Control"},      {0x08010002, Initialize,            "Initialize"}, @@ -389,7 +414,7 @@ const Interface::FunctionInfo FunctionTable[] = {      {0x080B0102, OpenDirectory,         "OpenDirectory"},      {0x080C00C2, OpenArchive,           "OpenArchive"},      {0x080D0144, nullptr,               "ControlArchive"}, -    {0x080E0080, nullptr,               "CloseArchive"}, +    {0x080E0080, CloseArchive,          "CloseArchive"},      {0x080F0180, nullptr,               "FormatThisUserSaveData"},      {0x08100200, nullptr,               "CreateSystemSaveData"},      {0x08110040, nullptr,               "DeleteSystemSaveData"}, @@ -465,11 +490,12 @@ const Interface::FunctionInfo FunctionTable[] = {  ////////////////////////////////////////////////////////////////////////////////////////////////////  // Interface class -Interface::Interface() { +FSUserInterface::FSUserInterface() {      Register(FunctionTable, ARRAY_SIZE(FunctionTable));  } -Interface::~Interface() { +FSUserInterface::~FSUserInterface() {  } -} // namespace +} // namespace FS +} // namespace Service diff --git a/src/core/hle/service/fs/fs_user.h b/src/core/hle/service/fs/fs_user.h new file mode 100644 index 000000000..80e3804e0 --- /dev/null +++ b/src/core/hle/service/fs/fs_user.h @@ -0,0 +1,33 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace FS_User + +namespace Service { +namespace FS { + +/// Interface to "fs:USER" service +class FSUserInterface : public Service::Interface { +public: + +    FSUserInterface(); + +    ~FSUserInterface(); + +    /** +     * Gets the string port name used by CTROS for the service +     * @return Port name of service +     */ +    std::string GetPortName() const override { +        return "fs:USER"; +    } +}; + +} // namespace FS +} // namespace Service diff --git a/src/core/hle/service/ldr_ro.cpp b/src/core/hle/service/ldr_ro.cpp new file mode 100644 index 000000000..91b1a6fc5 --- /dev/null +++ b/src/core/hle/service/ldr_ro.cpp @@ -0,0 +1,28 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/ldr_ro.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace LDR_RO + +namespace LDR_RO { + +const Interface::FunctionInfo FunctionTable[] = { +    {0x000100C2, nullptr,               "Initialize"}, +    {0x00020082, nullptr,               "CRR_Load"}, +    {0x00030042, nullptr,               "CRR_Unload"}, +    {0x000402C2, nullptr,               "CRO_LoadAndFix"}, +    {0x000500C2, nullptr,               "CRO_ApplyRelocationPatchesAndLink"} +}; +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { +    Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +} // namespace diff --git a/src/core/hle/service/ldr_ro.h b/src/core/hle/service/ldr_ro.h new file mode 100644 index 000000000..32d7c29cf --- /dev/null +++ b/src/core/hle/service/ldr_ro.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace LDR_RO + +namespace LDR_RO { + +class Interface : public Service::Interface { +public: +    Interface(); + +    /** +     * Gets the string port name used by CTROS for the service +     * @return Port name of service +     */ +    std::string GetPortName() const override { +        return "ldr:ro"; +    } +}; + +} // namespace diff --git a/src/core/hle/service/nim_aoc.cpp b/src/core/hle/service/nim_aoc.cpp new file mode 100644 index 000000000..04c1e0cf3 --- /dev/null +++ b/src/core/hle/service/nim_aoc.cpp @@ -0,0 +1,31 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/nim_aoc.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace NIM_AOC + +namespace NIM_AOC { + +const Interface::FunctionInfo FunctionTable[] = { +    {0x00030042, nullptr,               "SetApplicationId"}, +    {0x00040042, nullptr,               "SetTin"}, +    {0x000902D0, nullptr,               "ListContentSetsEx"}, +    {0x00180000, nullptr,               "GetBalance"}, +    {0x001D0000, nullptr,               "GetCustomerSupportCode"}, +    {0x00210000, nullptr,               "Initialize"}, +    {0x00240282, nullptr,               "CalculateContentsRequiredSize"}, +    {0x00250000, nullptr,               "RefreshServerTime"}, +}; +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { +    Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +} // namespace diff --git a/src/core/hle/service/nim_aoc.h b/src/core/hle/service/nim_aoc.h new file mode 100644 index 000000000..2cc673118 --- /dev/null +++ b/src/core/hle/service/nim_aoc.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace NIM_AOC + +namespace NIM_AOC { + +class Interface : public Service::Interface { +public: +    Interface(); + +    /** +     * Gets the string port name used by CTROS for the service +     * @return Port name of service +     */ +    std::string GetPortName() const override { +        return "nim:aoc"; +    } +}; + +} // namespace diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index e6973572b..2230045e3 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -7,21 +7,25 @@  #include "core/hle/service/service.h"  #include "core/hle/service/ac_u.h" +#include "core/hle/service/am_app.h"  #include "core/hle/service/am_net.h"  #include "core/hle/service/apt_u.h"  #include "core/hle/service/boss_u.h" +#include "core/hle/service/cecd_u.h"  #include "core/hle/service/cfg_i.h"  #include "core/hle/service/cfg_u.h"  #include "core/hle/service/csnd_snd.h"  #include "core/hle/service/dsp_dsp.h"  #include "core/hle/service/err_f.h" -#include "core/hle/service/fs_user.h" +#include "core/hle/service/fs/fs_user.h"  #include "core/hle/service/frd_u.h"  #include "core/hle/service/gsp_gpu.h"  #include "core/hle/service/hid_user.h"  #include "core/hle/service/ir_rst.h"  #include "core/hle/service/ir_u.h" +#include "core/hle/service/ldr_ro.h"  #include "core/hle/service/mic_u.h" +#include "core/hle/service/nim_aoc.h"  #include "core/hle/service/ndm_u.h"  #include "core/hle/service/nwm_uds.h"  #include "core/hle/service/pm_app.h" @@ -84,21 +88,25 @@ void Init() {      g_manager->AddService(new SRV::Interface);      g_manager->AddService(new AC_U::Interface); +    g_manager->AddService(new AM_APP::Interface);      g_manager->AddService(new AM_NET::Interface);      g_manager->AddService(new APT_U::Interface);      g_manager->AddService(new BOSS_U::Interface); +    g_manager->AddService(new CECD_U::Interface);      g_manager->AddService(new CFG_I::Interface);      g_manager->AddService(new CFG_U::Interface);      g_manager->AddService(new CSND_SND::Interface);      g_manager->AddService(new DSP_DSP::Interface);      g_manager->AddService(new ERR_F::Interface);      g_manager->AddService(new FRD_U::Interface); -    g_manager->AddService(new FS_User::Interface); +    g_manager->AddService(new FS::FSUserInterface);      g_manager->AddService(new GSP_GPU::Interface);      g_manager->AddService(new HID_User::Interface);      g_manager->AddService(new IR_RST::Interface);      g_manager->AddService(new IR_U::Interface); +    g_manager->AddService(new LDR_RO::Interface);      g_manager->AddService(new MIC_U::Interface); +    g_manager->AddService(new NIM_AOC::Interface);      g_manager->AddService(new NDM_U::Interface);      g_manager->AddService(new NWM_UDS::Interface);      g_manager->AddService(new PM_APP::Interface); diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index f48d13530..0437e5374 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp @@ -8,7 +8,7 @@  #include "core/file_sys/archive_romfs.h"  #include "core/loader/elf.h"  #include "core/loader/ncch.h" -#include "core/hle/kernel/archive.h" +#include "core/hle/service/fs/archive.h"  #include "core/mem_map.h"  #include "3dsx.h" diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 3883e1307..463dacca3 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -8,7 +8,7 @@  #include "core/loader/3dsx.h"  #include "core/loader/elf.h"  #include "core/loader/ncch.h" -#include "core/hle/kernel/archive.h" +#include "core/hle/service/fs/archive.h"  #include "core/mem_map.h"  //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -74,7 +74,7 @@ ResultStatus LoadFile(const std::string& filename) {          // Load application and RomFS          if (ResultStatus::Success == app_loader.Load()) { -            Kernel::CreateArchive(new FileSys::Archive_RomFS(app_loader), "RomFS"); +            Service::FS::CreateArchive(std::make_unique<FileSys::Archive_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS);              return ResultStatus::Success;          }          break; diff --git a/src/core/system.cpp b/src/core/system.cpp index 43d0eef2c..2885ff45f 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -23,10 +23,10 @@ void Init(EmuWindow* emu_window) {      Core::Init();      Memory::Init();      HW::Init(); +    Kernel::Init();      HLE::Init();      CoreTiming::Init();      VideoCore::Init(emu_window); -    Kernel::Init();  }  void RunLoopFor(int cycles) { @@ -37,13 +37,13 @@ void RunLoopUntil(u64 global_cycles) {  }  void Shutdown() { -    Core::Shutdown(); -    Memory::Shutdown(); -    HW::Shutdown(); -    HLE::Shutdown(); -    CoreTiming::Shutdown();      VideoCore::Shutdown(); +    CoreTiming::Shutdown(); +    HLE::Shutdown();      Kernel::Shutdown(); +    HW::Shutdown(); +    Memory::Shutdown(); +    Core::Shutdown();  }  } // namespace | 
