diff options
89 files changed, 2210 insertions, 1864 deletions
diff --git a/.travis.yml b/.travis.yml index 4f2b17465..e2742b5fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,3 +42,8 @@ deploy:    skip_cleanup: true    on:      tags: true + +notifications: +  webhooks: +    urls: +      - https://api.yuzu-emu.org/code/travis/notify diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dee41abc..1fcf0874f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,9 @@ option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)  CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF)  option(ENABLE_QT "Enable the Qt frontend" ON) -CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" ON "ENABLE_SDL2;MSVC" OFF) +CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" ON "ENABLE_QT;MSVC" OFF) + +option(YUZU_USE_BUNDLED_UNICORN "Build/Download bundled Unicorn" ON)  if(NOT EXISTS ${CMAKE_SOURCE_DIR}/.git/hooks/pre-commit)      message(STATUS "Copying pre-commit hook") @@ -209,8 +211,7 @@ else()  endif()  # If unicorn isn't found, msvc -> download bundled unicorn; everyone else -> build external -find_package(Unicorn QUIET) -if (NOT UNICORN_FOUND) +if (YUZU_USE_BUNDLED_UNICORN)      if (MSVC)          message(STATUS "unicorn not found, falling back to bundled")          # Detect toolchain and platform @@ -249,7 +250,7 @@ if (NOT UNICORN_FOUND)          find_package(PythonInterp 2.7 REQUIRED)          add_custom_command(OUTPUT ${LIBUNICORN_LIBRARY} -            COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" /bin/sh make.sh +            COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" /bin/sh make.sh macos-universal-no              WORKING_DIRECTORY ${UNICORN_PREFIX}          )          # ALL makes this custom target build every time @@ -259,6 +260,8 @@ if (NOT UNICORN_FOUND)          )          unset(UNICORN_LIB_NAME)      endif() +else() +    find_package(Unicorn REQUIRED)  endif()  if (UNICORN_FOUND) @@ -420,7 +423,7 @@ if(ENABLE_QT AND UNIX AND NOT APPLE)      install(FILES "${CMAKE_SOURCE_DIR}/dist/yuzu.desktop"              DESTINATION "${CMAKE_INSTALL_PREFIX}/share/applications")      install(FILES "${CMAKE_SOURCE_DIR}/dist/yuzu.svg" -            DESTINATION "${CMAKE_INSTALL_PREFIX}/share/pixmaps") +            DESTINATION "${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps")      install(FILES "${CMAKE_SOURCE_DIR}/dist/yuzu.xml"              DESTINATION "${CMAKE_INSTALL_PREFIX}/share/mime/packages")  endif() diff --git a/externals/dynarmic b/externals/dynarmic -Subproject bc73004dd5aaa10bedef031917bc87a5bb8f6fb +Subproject a6d17e6bb0ffd16464b7dae8c1124b0c6a742a1 diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 1af80769a..d132ab969 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -17,7 +17,7 @@ if ($ENV{CI})        string(SUBSTRING ${WORD} 1 -1 REMAINDER)        string(TOUPPER ${FIRST_LETTER} FIRST_LETTER)        # this leaves a trailing space on the last word, but we actually want that -      # because of how its styled in the title bar. +      # because of how it's styled in the title bar.        set(REPO_NAME "${REPO_NAME}${FIRST_LETTER}${REMAINDER} ")      endforeach()    endif() diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index e136482b6..be53be407 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -38,6 +38,8 @@ namespace Log {      SUB(Service, CFG)                                                                              \      SUB(Service, DSP)                                                                              \      SUB(Service, HID)                                                                              \ +    SUB(Service, NVDRV)                                                                            \ +    SUB(Service, Audio)                                                                            \      CLS(HW)                                                                                        \      SUB(HW, Memory)                                                                                \      SUB(HW, LCD)                                                                                   \ diff --git a/src/common/logging/log.h b/src/common/logging/log.h index 57021037a..09ea7a2c7 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h @@ -55,6 +55,8 @@ enum class Class : ClassType {      Service_CFG,       ///< The CFG (Configuration) service      Service_DSP,       ///< The DSP (DSP control) service      Service_HID,       ///< The HID (Human interface device) service +    Service_NVDRV,     ///< The NVDRV (Nvidia driver) service +    Service_Audio,     ///< The Audio (Audio control) service      HW,                ///< Low-level hardware emulation      HW_Memory,         ///< Memory-map and address translation      HW_LCD,            ///< LCD register emulation diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 7153c4f3f..70547c8b2 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -6,21 +6,17 @@ add_library(core STATIC      core.h      core_timing.cpp      core_timing.h -    file_sys/archive_backend.cpp -    file_sys/archive_backend.h -    file_sys/directory_backend.h -    file_sys/disk_archive.cpp -    file_sys/disk_archive.h +    file_sys/directory.h      file_sys/errors.h -    file_sys/file_backend.h -    file_sys/ivfc_archive.cpp -    file_sys/ivfc_archive.h +    file_sys/filesystem.cpp +    file_sys/filesystem.h      file_sys/path_parser.cpp      file_sys/path_parser.h -    file_sys/savedata_archive.cpp -    file_sys/savedata_archive.h -    file_sys/title_metadata.cpp -    file_sys/title_metadata.h +    file_sys/romfs_factory.cpp +    file_sys/romfs_factory.h +    file_sys/romfs_filesystem.cpp +    file_sys/romfs_filesystem.h +    file_sys/storage.h      frontend/emu_window.cpp      frontend/emu_window.h      frontend/framebuffer_layout.cpp @@ -40,8 +36,6 @@ add_library(core STATIC      hle/kernel/client_session.h      hle/kernel/condition_variable.cpp      hle/kernel/condition_variable.h -    hle/kernel/domain.cpp -    hle/kernel/domain.h      hle/kernel/errors.h      hle/kernel/event.cpp      hle/kernel/event.h @@ -71,7 +65,6 @@ add_library(core STATIC      hle/kernel/svc.cpp      hle/kernel/svc.h      hle/kernel/svc_wrap.h -    hle/kernel/sync_object.h      hle/kernel/thread.cpp      hle/kernel/thread.h      hle/kernel/timer.cpp @@ -99,8 +92,22 @@ add_library(core STATIC      hle/service/apm/apm.h      hle/service/audio/audio.cpp      hle/service/audio/audio.h +    hle/service/audio/audin_u.cpp +    hle/service/audio/audin_u.h      hle/service/audio/audout_u.cpp      hle/service/audio/audout_u.h +    hle/service/audio/audrec_u.cpp +    hle/service/audio/audrec_u.h +    hle/service/audio/audren_u.cpp +    hle/service/audio/audren_u.h +    hle/service/audio/audren_u.cpp +    hle/service/audio/audren_u.h +    hle/service/audio/codecctl.cpp +    hle/service/audio/codecctl.h +    hle/service/filesystem/filesystem.cpp +    hle/service/filesystem/filesystem.h +    hle/service/filesystem/fsp_srv.cpp +    hle/service/filesystem/fsp_srv.h      hle/service/hid/hid.cpp      hle/service/hid/hid.h      hle/service/lm/lm.cpp @@ -110,12 +117,20 @@ add_library(core STATIC      hle/service/nvdrv/devices/nvdisp_disp0.h      hle/service/nvdrv/devices/nvhost_as_gpu.cpp      hle/service/nvdrv/devices/nvhost_as_gpu.h +    hle/service/nvdrv/devices/nvhost_ctrl.cpp +    hle/service/nvdrv/devices/nvhost_ctrl.h      hle/service/nvdrv/devices/nvmap.cpp      hle/service/nvdrv/devices/nvmap.h      hle/service/nvdrv/interface.cpp      hle/service/nvdrv/interface.h      hle/service/nvdrv/nvdrv.cpp      hle/service/nvdrv/nvdrv.h +    hle/service/nvdrv/nvmemp.cpp +    hle/service/nvdrv/nvmemp.h +    hle/service/nvflinger/buffer_queue.cpp +    hle/service/nvflinger/buffer_queue.h +    hle/service/nvflinger/nvflinger.cpp +    hle/service/nvflinger/nvflinger.h      hle/service/pctl/pctl.cpp      hle/service/pctl/pctl.h      hle/service/pctl/pctl_a.cpp diff --git a/src/core/core.h b/src/core/core.h index a9a035a1b..06ab4c75f 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -51,13 +51,13 @@ public:       * requested is not guaranteed to run, as this will be interrupted preemptively if a hardware       * update is requested (e.g. on a thread switch).       * @param tight_loop Number of instructions to execute. -     * @return Result status, indicating whethor or not the operation succeeded. +     * @return Result status, indicating whether or not the operation succeeded.       */      ResultStatus RunLoop(int tight_loop = 100000);      /**       * Step the CPU one instruction -     * @return Result status, indicating whethor or not the operation succeeded. +     * @return Result status, indicating whether or not the operation succeeded.       */      ResultStatus SingleStep(); diff --git a/src/core/file_sys/directory_backend.h b/src/core/file_sys/directory.h index 0c93f2074..5a40bf472 100644 --- a/src/core/file_sys/directory_backend.h +++ b/src/core/file_sys/directory.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2018 yuzu emulator team  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp deleted file mode 100644 index 98d80aabc..000000000 --- a/src/core/file_sys/disk_archive.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <algorithm> -#include <cstdio> -#include <memory> -#include "common/common_types.h" -#include "common/file_util.h" -#include "common/logging/log.h" -#include "core/file_sys/disk_archive.h" -#include "core/file_sys/errors.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -ResultVal<size_t> DiskFile::Read(const u64 offset, const size_t length, u8* buffer) const { -    if (!mode.read_flag) -        return ERROR_INVALID_OPEN_FLAGS; - -    file->Seek(offset, SEEK_SET); -    return MakeResult<size_t>(file->ReadBytes(buffer, length)); -} - -ResultVal<size_t> DiskFile::Write(const u64 offset, const size_t length, const bool flush, -                                  const u8* buffer) const { -    if (!mode.write_flag) -        return ERROR_INVALID_OPEN_FLAGS; - -    file->Seek(offset, SEEK_SET); -    size_t written = file->WriteBytes(buffer, length); -    if (flush) -        file->Flush(); -    return MakeResult<size_t>(written); -} - -u64 DiskFile::GetSize() const { -    return file->GetSize(); -} - -bool DiskFile::SetSize(const u64 size) const { -    file->Resize(size); -    file->Flush(); -    return true; -} - -bool DiskFile::Close() const { -    return file->Close(); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -DiskDirectory::DiskDirectory(const std::string& path) : directory() { -    unsigned size = FileUtil::ScanDirectoryTree(path, directory); -    directory.size = size; -    directory.isDirectory = true; -    children_iterator = directory.children.begin(); -} - -u32 DiskDirectory::Read(const u32 count, Entry* entries) { -    u32 entries_read = 0; - -    while (entries_read < count && children_iterator != directory.children.cend()) { -        const FileUtil::FSTEntry& file = *children_iterator; -        const std::string& filename = file.virtualName; -        Entry& entry = entries[entries_read]; - -        LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, -                  file.isDirectory); - -        // TODO(Link Mauve): use a proper conversion to UTF-16. -        for (size_t j = 0; j < FILENAME_LENGTH; ++j) { -            entry.filename[j] = filename[j]; -            if (!filename[j]) -                break; -        } - -        FileUtil::SplitFilename83(filename, entry.short_name, entry.extension); - -        entry.is_directory = file.isDirectory; -        entry.is_hidden = (filename[0] == '.'); -        entry.is_read_only = 0; -        entry.file_size = file.size; - -        // We emulate a SD card where the archive bit has never been cleared, as it would be on -        // most user SD cards. -        // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a -        // file bit. -        entry.is_archive = !file.isDirectory; - -        ++entries_read; -        ++children_iterator; -    } -    return entries_read; -} - -} // namespace FileSys diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h deleted file mode 100644 index eb9166df6..000000000 --- a/src/core/file_sys/disk_archive.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <cstddef> -#include <memory> -#include <string> -#include <vector> -#include "common/common_types.h" -#include "common/file_util.h" -#include "core/file_sys/archive_backend.h" -#include "core/file_sys/directory_backend.h" -#include "core/file_sys/file_backend.h" -#include "core/hle/result.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -class DiskFile : public FileBackend { -public: -    DiskFile(FileUtil::IOFile&& file_, const Mode& mode_) -        : file(new FileUtil::IOFile(std::move(file_))) { -        mode.hex = mode_.hex; -    } - -    ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const override; -    ResultVal<size_t> 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; - -    void Flush() const override { -        file->Flush(); -    } - -protected: -    Mode mode; -    std::unique_ptr<FileUtil::IOFile> file; -}; - -class DiskDirectory : public DirectoryBackend { -public: -    DiskDirectory(const std::string& path); - -    ~DiskDirectory() override { -        Close(); -    } - -    u32 Read(const u32 count, Entry* entries) override; - -    bool Close() const override { -        return true; -    } - -protected: -    u32 total_entries_in_directory; -    FileUtil::FSTEntry directory; - -    // We need to remember the last entry we returned, so a subsequent call to Read will continue -    // from the next one.  This iterator will always point to the next unread entry. -    std::vector<FileUtil::FSTEntry>::iterator children_iterator; -}; - -} // namespace FileSys diff --git a/src/core/file_sys/archive_backend.cpp b/src/core/file_sys/filesystem.cpp index fc472b44f..82fdb3c46 100644 --- a/src/core/file_sys/archive_backend.cpp +++ b/src/core/file_sys/filesystem.cpp @@ -1,4 +1,4 @@ -// Copyright 2015 Citra Emulator Project +// Copyright 2018 yuzu emulator team  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. @@ -7,7 +7,7 @@  #include <sstream>  #include "common/logging/log.h"  #include "common/string_util.h" -#include "core/file_sys/archive_backend.h" +#include "core/file_sys/filesystem.h"  #include "core/memory.h"  namespace FileSys { diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/filesystem.h index 58f6c150c..02705506b 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/filesystem.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2018 yuzu emulator team  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. @@ -15,7 +15,7 @@  namespace FileSys { -class FileBackend; +class StorageBackend;  class DirectoryBackend;  // Path string type @@ -71,9 +71,9 @@ struct ArchiveFormatInfo {  };  static_assert(std::is_pod<ArchiveFormatInfo>::value, "ArchiveFormatInfo is not POD"); -class ArchiveBackend : NonCopyable { +class FileSystemBackend : NonCopyable {  public: -    virtual ~ArchiveBackend() {} +    virtual ~FileSystemBackend() {}      /**       * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) @@ -81,13 +81,12 @@ public:      virtual std::string GetName() const = 0;      /** -     * 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 error code +     * Create a file specified by its path +     * @param path Path relative to the Archive +     * @param size The size of the new file, filled with zeroes +     * @return Result of the operation       */ -    virtual ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, -                                                             const Mode& mode) const = 0; +    virtual ResultCode CreateFile(const Path& path, u64 size) const = 0;      /**       * Delete a file specified by its path @@ -97,12 +96,11 @@ public:      virtual ResultCode DeleteFile(const Path& path) const = 0;      /** -     * Rename a File specified by its path -     * @param src_path Source path relative to the archive -     * @param dest_path Destination path relative to the archive +     * Create a directory specified by its path +     * @param path Path relative to the archive       * @return Result of the operation       */ -    virtual ResultCode RenameFile(const Path& src_path, const Path& dest_path) const = 0; +    virtual ResultCode CreateDirectory(const Path& path) const = 0;      /**       * Delete a directory specified by its path @@ -119,19 +117,12 @@ public:      virtual ResultCode DeleteDirectoryRecursively(const Path& path) const = 0;      /** -     * Create a file specified by its path -     * @param path Path relative to the Archive -     * @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; - -    /** -     * Create a directory specified by its path -     * @param path Path relative to the archive +     * Rename a File specified by its path +     * @param src_path Source path relative to the archive +     * @param dest_path Destination path relative to the archive       * @return Result of the operation       */ -    virtual ResultCode CreateDirectory(const Path& path) const = 0; +    virtual ResultCode RenameFile(const Path& src_path, const Path& dest_path) const = 0;      /**       * Rename a Directory specified by its path @@ -142,6 +133,15 @@ public:      virtual ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const = 0;      /** +     * 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 error code +     */ +    virtual ResultVal<std::unique_ptr<StorageBackend>> OpenFile(const Path& path, +                                                                const Mode& mode) const = 0; + +    /**       * Open a directory specified by its path       * @param path Path relative to the archive       * @return Opened directory, or error code @@ -152,12 +152,12 @@ public:       * Get the free space       * @return The number of free bytes in the archive       */ -    virtual u64 GetFreeBytes() const = 0; +    virtual u64 GetFreeSpaceSize() const = 0;  }; -class ArchiveFactory : NonCopyable { +class FileSystemFactory : NonCopyable {  public: -    virtual ~ArchiveFactory() {} +    virtual ~FileSystemFactory() {}      /**       * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) @@ -169,7 +169,7 @@ public:       * @param path Path to the archive       * @return An ArchiveBackend corresponding operating specified archive path.       */ -    virtual ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) = 0; +    virtual ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) = 0;      /**       * Deletes the archive contents and then re-creates the base folder diff --git a/src/core/file_sys/path_parser.h b/src/core/file_sys/path_parser.h index b9f52f65d..184f59d55 100644 --- a/src/core/file_sys/path_parser.h +++ b/src/core/file_sys/path_parser.h @@ -6,7 +6,7 @@  #include <string>  #include <vector> -#include "core/file_sys/archive_backend.h" +#include "core/file_sys/filesystem.h"  namespace FileSys { diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp new file mode 100644 index 000000000..e0de49f05 --- /dev/null +++ b/src/core/file_sys/romfs_factory.cpp @@ -0,0 +1,38 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include <memory> +#include "common/common_types.h" +#include "common/logging/log.h" +#include "core/file_sys/romfs_factory.h" +#include "core/file_sys/romfs_filesystem.h" + +namespace FileSys { + +RomFS_Factory::RomFS_Factory(Loader::AppLoader& app_loader) { +    // Load the RomFS from the app +    if (Loader::ResultStatus::Success != app_loader.ReadRomFS(romfs_file, data_offset, data_size)) { +        LOG_ERROR(Service_FS, "Unable to read RomFS!"); +    } +} + +ResultVal<std::unique_ptr<FileSystemBackend>> RomFS_Factory::Open(const Path& path) { +    auto archive = std::make_unique<RomFS_FileSystem>(romfs_file, data_offset, data_size); +    return MakeResult<std::unique_ptr<FileSystemBackend>>(std::move(archive)); +} + +ResultCode RomFS_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<ArchiveFormatInfo> RomFS_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/romfs_factory.h b/src/core/file_sys/romfs_factory.h new file mode 100644 index 000000000..10ea13966 --- /dev/null +++ b/src/core/file_sys/romfs_factory.h @@ -0,0 +1,35 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <string> +#include <vector> +#include "common/common_types.h" +#include "core/file_sys/filesystem.h" +#include "core/hle/result.h" +#include "core/loader/loader.h" + +namespace FileSys { + +/// File system interface to the RomFS archive +class RomFS_Factory final : public FileSystemFactory { +public: +    explicit RomFS_Factory(Loader::AppLoader& app_loader); + +    std::string GetName() const override { +        return "ArchiveFactory_RomFS"; +    } +    ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) override; +    ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; +    ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; + +private: +    std::shared_ptr<FileUtil::IOFile> romfs_file; +    u64 data_offset; +    u64 data_size; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/ivfc_archive.cpp b/src/core/file_sys/romfs_filesystem.cpp index b3c3f2c6f..ca1463d7c 100644 --- a/src/core/file_sys/ivfc_archive.cpp +++ b/src/core/file_sys/romfs_filesystem.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2018 yuzu emulator team  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. @@ -6,84 +6,80 @@  #include <memory>  #include "common/common_types.h"  #include "common/logging/log.h" -#include "core/file_sys/ivfc_archive.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace +#include "core/file_sys/romfs_filesystem.h"  namespace FileSys { -std::string IVFCArchive::GetName() const { -    return "IVFC"; +std::string RomFS_FileSystem::GetName() const { +    return "RomFS";  } -ResultVal<std::unique_ptr<FileBackend>> IVFCArchive::OpenFile(const Path& path, -                                                              const Mode& mode) const { -    return MakeResult<std::unique_ptr<FileBackend>>( -        std::make_unique<IVFCFile>(romfs_file, data_offset, data_size)); +ResultVal<std::unique_ptr<StorageBackend>> RomFS_FileSystem::OpenFile(const Path& path, +                                                                      const Mode& mode) const { +    return MakeResult<std::unique_ptr<StorageBackend>>( +        std::make_unique<RomFS_Storage>(romfs_file, data_offset, data_size));  } -ResultCode IVFCArchive::DeleteFile(const Path& path) const { -    LOG_CRITICAL(Service_FS, "Attempted to delete a file from an IVFC archive (%s).", +ResultCode RomFS_FileSystem::DeleteFile(const Path& path) const { +    LOG_CRITICAL(Service_FS, "Attempted to delete a file from an ROMFS archive (%s).",                   GetName().c_str());      // TODO(bunnei): Use correct error code      return ResultCode(-1);  } -ResultCode IVFCArchive::RenameFile(const Path& src_path, const Path& dest_path) const { -    LOG_CRITICAL(Service_FS, "Attempted to rename a file within an IVFC archive (%s).", +ResultCode RomFS_FileSystem::RenameFile(const Path& src_path, const Path& dest_path) const { +    LOG_CRITICAL(Service_FS, "Attempted to rename a file within an ROMFS archive (%s).",                   GetName().c_str());      // TODO(wwylele): Use correct error code      return ResultCode(-1);  } -ResultCode IVFCArchive::DeleteDirectory(const Path& path) const { -    LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an IVFC archive (%s).", +ResultCode RomFS_FileSystem::DeleteDirectory(const Path& path) const { +    LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an ROMFS archive (%s).",                   GetName().c_str());      // TODO(wwylele): Use correct error code      return ResultCode(-1);  } -ResultCode IVFCArchive::DeleteDirectoryRecursively(const Path& path) const { -    LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an IVFC archive (%s).", +ResultCode RomFS_FileSystem::DeleteDirectoryRecursively(const Path& path) const { +    LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an ROMFS archive (%s).",                   GetName().c_str());      // TODO(wwylele): Use correct error code      return ResultCode(-1);  } -ResultCode IVFCArchive::CreateFile(const Path& path, u64 size) const { -    LOG_CRITICAL(Service_FS, "Attempted to create a file in an IVFC archive (%s).", +ResultCode RomFS_FileSystem::CreateFile(const Path& 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      return ResultCode(-1);  } -ResultCode IVFCArchive::CreateDirectory(const Path& path) const { -    LOG_CRITICAL(Service_FS, "Attempted to create a directory in an IVFC archive (%s).", +ResultCode RomFS_FileSystem::CreateDirectory(const Path& path) const { +    LOG_CRITICAL(Service_FS, "Attempted to create a directory in an ROMFS archive (%s).",                   GetName().c_str());      // TODO(wwylele): Use correct error code      return ResultCode(-1);  } -ResultCode IVFCArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const { -    LOG_CRITICAL(Service_FS, "Attempted to rename a file within an IVFC archive (%s).", +ResultCode RomFS_FileSystem::RenameDirectory(const Path& src_path, const Path& dest_path) const { +    LOG_CRITICAL(Service_FS, "Attempted to rename a file within an ROMFS archive (%s).",                   GetName().c_str());      // TODO(wwylele): Use correct error code      return ResultCode(-1);  } -ResultVal<std::unique_ptr<DirectoryBackend>> IVFCArchive::OpenDirectory(const Path& path) const { -    return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<IVFCDirectory>()); +ResultVal<std::unique_ptr<DirectoryBackend>> RomFS_FileSystem::OpenDirectory( +    const Path& path) const { +    return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<ROMFSDirectory>());  } -u64 IVFCArchive::GetFreeBytes() const { -    LOG_WARNING(Service_FS, "Attempted to get the free space in an IVFC archive"); +u64 RomFS_FileSystem::GetFreeSpaceSize() const { +    LOG_WARNING(Service_FS, "Attempted to get the free space in an ROMFS archive");      return 0;  } -//////////////////////////////////////////////////////////////////////////////////////////////////// - -ResultVal<size_t> IVFCFile::Read(const u64 offset, const size_t length, u8* buffer) const { +ResultVal<size_t> 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);      size_t read_length = (size_t)std::min((u64)length, data_size - offset); @@ -91,19 +87,19 @@ ResultVal<size_t> IVFCFile::Read(const u64 offset, const size_t length, u8* buff      return MakeResult<size_t>(romfs_file->ReadBytes(buffer, read_length));  } -ResultVal<size_t> IVFCFile::Write(const u64 offset, const size_t length, const bool flush, -                                  const u8* buffer) const { -    LOG_ERROR(Service_FS, "Attempted to write to IVFC file"); +ResultVal<size_t> RomFS_Storage::Write(const u64 offset, const size_t length, const bool flush, +                                       const u8* buffer) const { +    LOG_ERROR(Service_FS, "Attempted to write to ROMFS file");      // TODO(Subv): Find error code      return MakeResult<size_t>(0);  } -u64 IVFCFile::GetSize() const { +u64 RomFS_Storage::GetSize() const {      return data_size;  } -bool IVFCFile::SetSize(const u64 size) const { -    LOG_ERROR(Service_FS, "Attempted to set the size of an IVFC file"); +bool RomFS_Storage::SetSize(const u64 size) const { +    LOG_ERROR(Service_FS, "Attempted to set the size of an ROMFS file");      return false;  } diff --git a/src/core/file_sys/ivfc_archive.h b/src/core/file_sys/romfs_filesystem.h index e6fbdfb1f..900ea567a 100644 --- a/src/core/file_sys/ivfc_archive.h +++ b/src/core/file_sys/romfs_filesystem.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2018 yuzu emulator team  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. @@ -10,30 +10,27 @@  #include <vector>  #include "common/common_types.h"  #include "common/file_util.h" -#include "core/file_sys/archive_backend.h" -#include "core/file_sys/directory_backend.h" -#include "core/file_sys/file_backend.h" +#include "core/file_sys/directory.h" +#include "core/file_sys/filesystem.h" +#include "core/file_sys/storage.h"  #include "core/hle/result.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace -  namespace FileSys {  /** - * Helper which implements an interface to deal with IVFC images used in some archives - * This should be subclassed by concrete archive types, which will provide the - * input data (load the raw IVFC archive) and override any required methods + * Helper which implements an interface to deal with Switch .istorage ROMFS images used in some + * archives This should be subclassed by concrete archive types, which will provide the input data + * (load the raw ROMFS archive) and override any required methods   */ -class IVFCArchive : public ArchiveBackend { +class RomFS_FileSystem : public FileSystemBackend {  public: -    IVFCArchive(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size) +    RomFS_FileSystem(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size)          : romfs_file(file), data_offset(offset), data_size(size) {}      std::string GetName() const override; -    ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, -                                                     const Mode& mode) const override; +    ResultVal<std::unique_ptr<StorageBackend>> OpenFile(const Path& path, +                                                        const 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; @@ -42,7 +39,7 @@ public:      ResultCode CreateDirectory(const Path& path) const override;      ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override;      ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override; -    u64 GetFreeBytes() const override; +    u64 GetFreeSpaceSize() const override;  protected:      std::shared_ptr<FileUtil::IOFile> romfs_file; @@ -50,9 +47,9 @@ protected:      u64 data_size;  }; -class IVFCFile : public FileBackend { +class RomFS_Storage : public StorageBackend {  public: -    IVFCFile(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size) +    RomFS_Storage(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size)          : romfs_file(file), data_offset(offset), data_size(size) {}      ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const override; @@ -70,7 +67,7 @@ private:      u64 data_size;  }; -class IVFCDirectory : public DirectoryBackend { +class ROMFSDirectory : public DirectoryBackend {  public:      u32 Read(const u32 count, Entry* entries) override {          return 0; diff --git a/src/core/file_sys/savedata_archive.cpp b/src/core/file_sys/savedata_archive.cpp deleted file mode 100644 index d7b012f6e..000000000 --- a/src/core/file_sys/savedata_archive.cpp +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/file_util.h" -#include "core/file_sys/disk_archive.h" -#include "core/file_sys/errors.h" -#include "core/file_sys/path_parser.h" -#include "core/file_sys/savedata_archive.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -ResultVal<std::unique_ptr<FileBackend>> SaveDataArchive::OpenFile(const Path& path, -                                                                  const Mode& mode) const { -    LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex); - -    const PathParser path_parser(path); - -    if (!path_parser.IsValid()) { -        LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); -        return ERROR_INVALID_PATH; -    } - -    if (mode.hex == 0) { -        LOG_ERROR(Service_FS, "Empty open mode"); -        return ERROR_UNSUPPORTED_OPEN_FLAGS; -    } - -    if (mode.create_flag && !mode.write_flag) { -        LOG_ERROR(Service_FS, "Create flag set but write flag not set"); -        return ERROR_UNSUPPORTED_OPEN_FLAGS; -    } - -    const auto full_path = path_parser.BuildHostPath(mount_point); - -    switch (path_parser.GetHostStatus(mount_point)) { -    case PathParser::InvalidMountPoint: -        LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); -        return ERROR_FILE_NOT_FOUND; -    case PathParser::PathNotFound: -        LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); -        return ERROR_PATH_NOT_FOUND; -    case PathParser::FileInPath: -    case PathParser::DirectoryFound: -        LOG_ERROR(Service_FS, "Unexpected file or directory in %s", full_path.c_str()); -        return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; -    case PathParser::NotFound: -        if (!mode.create_flag) { -            LOG_ERROR(Service_FS, "Non-existing file %s can't be open without mode create.", -                      full_path.c_str()); -            return ERROR_FILE_NOT_FOUND; -        } else { -            // Create the file -            FileUtil::CreateEmptyFile(full_path); -        } -        break; -    case PathParser::FileFound: -        break; // Expected 'success' case -    } - -    FileUtil::IOFile file(full_path, mode.write_flag ? "r+b" : "rb"); -    if (!file.IsOpen()) { -        LOG_CRITICAL(Service_FS, "(unreachable) Unknown error opening %s", full_path.c_str()); -        return ERROR_FILE_NOT_FOUND; -    } - -    auto disk_file = std::make_unique<DiskFile>(std::move(file), mode); -    return MakeResult<std::unique_ptr<FileBackend>>(std::move(disk_file)); -} - -ResultCode SaveDataArchive::DeleteFile(const Path& path) const { -    const PathParser path_parser(path); - -    if (!path_parser.IsValid()) { -        LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); -        return ERROR_INVALID_PATH; -    } - -    const auto full_path = path_parser.BuildHostPath(mount_point); - -    switch (path_parser.GetHostStatus(mount_point)) { -    case PathParser::InvalidMountPoint: -        LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); -        return ERROR_FILE_NOT_FOUND; -    case PathParser::PathNotFound: -        LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); -        return ERROR_PATH_NOT_FOUND; -    case PathParser::FileInPath: -    case PathParser::DirectoryFound: -    case PathParser::NotFound: -        LOG_ERROR(Service_FS, "File not found %s", full_path.c_str()); -        return ERROR_FILE_NOT_FOUND; -    case PathParser::FileFound: -        break; // Expected 'success' case -    } - -    if (FileUtil::Delete(full_path)) { -        return RESULT_SUCCESS; -    } - -    LOG_CRITICAL(Service_FS, "(unreachable) Unknown error deleting %s", full_path.c_str()); -    return ERROR_FILE_NOT_FOUND; -} - -ResultCode SaveDataArchive::RenameFile(const Path& src_path, const Path& dest_path) const { -    const PathParser path_parser_src(src_path); - -    // TODO: Verify these return codes with HW -    if (!path_parser_src.IsValid()) { -        LOG_ERROR(Service_FS, "Invalid src path %s", src_path.DebugStr().c_str()); -        return ERROR_INVALID_PATH; -    } - -    const PathParser path_parser_dest(dest_path); - -    if (!path_parser_dest.IsValid()) { -        LOG_ERROR(Service_FS, "Invalid dest path %s", dest_path.DebugStr().c_str()); -        return ERROR_INVALID_PATH; -    } - -    const auto src_path_full = path_parser_src.BuildHostPath(mount_point); -    const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point); - -    if (FileUtil::Rename(src_path_full, dest_path_full)) { -        return RESULT_SUCCESS; -    } - -    // TODO(bunnei): Use correct error code -    return ResultCode(-1); -} - -template <typename T> -static ResultCode DeleteDirectoryHelper(const Path& path, const std::string& mount_point, -                                        T deleter) { -    const PathParser path_parser(path); - -    if (!path_parser.IsValid()) { -        LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); -        return ERROR_INVALID_PATH; -    } - -    if (path_parser.IsRootDirectory()) -        return ERROR_DIRECTORY_NOT_EMPTY; - -    const auto full_path = path_parser.BuildHostPath(mount_point); - -    switch (path_parser.GetHostStatus(mount_point)) { -    case PathParser::InvalidMountPoint: -        LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); -        return ERROR_PATH_NOT_FOUND; -    case PathParser::PathNotFound: -    case PathParser::NotFound: -        LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); -        return ERROR_PATH_NOT_FOUND; -    case PathParser::FileInPath: -    case PathParser::FileFound: -        LOG_ERROR(Service_FS, "Unexpected file or directory %s", full_path.c_str()); -        return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; -    case PathParser::DirectoryFound: -        break; // Expected 'success' case -    } - -    if (deleter(full_path)) { -        return RESULT_SUCCESS; -    } - -    LOG_ERROR(Service_FS, "Directory not empty %s", full_path.c_str()); -    return ERROR_DIRECTORY_NOT_EMPTY; -} - -ResultCode SaveDataArchive::DeleteDirectory(const Path& path) const { -    return DeleteDirectoryHelper(path, mount_point, FileUtil::DeleteDir); -} - -ResultCode SaveDataArchive::DeleteDirectoryRecursively(const Path& path) const { -    return DeleteDirectoryHelper( -        path, mount_point, [](const std::string& p) { return FileUtil::DeleteDirRecursively(p); }); -} - -ResultCode SaveDataArchive::CreateFile(const FileSys::Path& path, u64 size) const { -    const PathParser path_parser(path); - -    if (!path_parser.IsValid()) { -        LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); -        return ERROR_INVALID_PATH; -    } - -    const auto full_path = path_parser.BuildHostPath(mount_point); - -    switch (path_parser.GetHostStatus(mount_point)) { -    case PathParser::InvalidMountPoint: -        LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); -        return ERROR_FILE_NOT_FOUND; -    case PathParser::PathNotFound: -        LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); -        return ERROR_PATH_NOT_FOUND; -    case PathParser::FileInPath: -        LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str()); -        return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; -    case PathParser::DirectoryFound: -    case PathParser::FileFound: -        LOG_ERROR(Service_FS, "%s already exists", full_path.c_str()); -        return ERROR_FILE_ALREADY_EXISTS; -    case PathParser::NotFound: -        break; // Expected 'success' case -    } - -    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(bunnei): Use correct error code -    return ResultCode(-1); -} - -ResultCode SaveDataArchive::CreateDirectory(const Path& path) const { -    const PathParser path_parser(path); - -    if (!path_parser.IsValid()) { -        LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); -        return ERROR_INVALID_PATH; -    } - -    const auto full_path = path_parser.BuildHostPath(mount_point); - -    switch (path_parser.GetHostStatus(mount_point)) { -    case PathParser::InvalidMountPoint: -        LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); -        return ERROR_FILE_NOT_FOUND; -    case PathParser::PathNotFound: -        LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); -        return ERROR_PATH_NOT_FOUND; -    case PathParser::FileInPath: -        LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str()); -        return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; -    case PathParser::DirectoryFound: -    case PathParser::FileFound: -        LOG_ERROR(Service_FS, "%s already exists", full_path.c_str()); -        return ERROR_DIRECTORY_ALREADY_EXISTS; -    case PathParser::NotFound: -        break; // Expected 'success' case -    } - -    if (FileUtil::CreateDir(mount_point + path.AsString())) { -        return RESULT_SUCCESS; -    } - -    LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating %s", mount_point.c_str()); - -    // TODO(bunnei): Use correct error code -    return ResultCode(-1); -} - -ResultCode SaveDataArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const { -    const PathParser path_parser_src(src_path); - -    // TODO: Verify these return codes with HW -    if (!path_parser_src.IsValid()) { -        LOG_ERROR(Service_FS, "Invalid src path %s", src_path.DebugStr().c_str()); -        return ERROR_INVALID_PATH; -    } - -    const PathParser path_parser_dest(dest_path); - -    if (!path_parser_dest.IsValid()) { -        LOG_ERROR(Service_FS, "Invalid dest path %s", dest_path.DebugStr().c_str()); -        return ERROR_INVALID_PATH; -    } - -    const auto src_path_full = path_parser_src.BuildHostPath(mount_point); -    const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point); - -    if (FileUtil::Rename(src_path_full, dest_path_full)) { -        return RESULT_SUCCESS; -    } - -    // TODO(bunnei): Use correct error code -    return ResultCode(-1); -} - -ResultVal<std::unique_ptr<DirectoryBackend>> SaveDataArchive::OpenDirectory( -    const Path& path) const { -    const PathParser path_parser(path); - -    if (!path_parser.IsValid()) { -        LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); -        return ERROR_INVALID_PATH; -    } - -    const auto full_path = path_parser.BuildHostPath(mount_point); - -    switch (path_parser.GetHostStatus(mount_point)) { -    case PathParser::InvalidMountPoint: -        LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); -        return ERROR_FILE_NOT_FOUND; -    case PathParser::PathNotFound: -    case PathParser::NotFound: -        LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); -        return ERROR_PATH_NOT_FOUND; -    case PathParser::FileInPath: -    case PathParser::FileFound: -        LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str()); -        return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; -    case PathParser::DirectoryFound: -        break; // Expected 'success' case -    } - -    auto directory = std::make_unique<DiskDirectory>(full_path); -    return MakeResult<std::unique_ptr<DirectoryBackend>>(std::move(directory)); -} - -u64 SaveDataArchive::GetFreeBytes() const { -    // TODO: Stubbed to return 1GiB -    return 1024 * 1024 * 1024; -} - -} // namespace FileSys diff --git a/src/core/file_sys/savedata_archive.h b/src/core/file_sys/savedata_archive.h deleted file mode 100644 index 176d35710..000000000 --- a/src/core/file_sys/savedata_archive.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <string> -#include "core/file_sys/archive_backend.h" -#include "core/file_sys/directory_backend.h" -#include "core/file_sys/file_backend.h" -#include "core/hle/result.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -/// Archive backend for general save data archive type (SaveData and SystemSaveData) -class SaveDataArchive : public ArchiveBackend { -public: -    explicit SaveDataArchive(const std::string& mount_point_) : mount_point(mount_point_) {} - -    std::string GetName() const override { -        return "SaveDataArchive: " + mount_point; -    } - -    ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, -                                                     const 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 CreateDirectory(const Path& path) const override; -    ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; -    ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override; -    u64 GetFreeBytes() const override; - -protected: -    std::string mount_point; -}; - -} // namespace FileSys diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/storage.h index 5e7c2bab4..2a6811831 100644 --- a/src/core/file_sys/file_backend.h +++ b/src/core/file_sys/storage.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2018 yuzu emulator team  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. @@ -8,15 +8,12 @@  #include "common/common_types.h"  #include "core/hle/result.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace -  namespace FileSys { -class FileBackend : NonCopyable { +class StorageBackend : NonCopyable {  public: -    FileBackend() {} -    virtual ~FileBackend() {} +    StorageBackend() {} +    virtual ~StorageBackend() {}      /**       * Read data from the file @@ -39,10 +36,9 @@ public:                                      const u8* buffer) const = 0;      /** -     * Get the size of the file in bytes -     * @return Size of the file in bytes +     * Flushes the file       */ -    virtual u64 GetSize() const = 0; +    virtual void Flush() const = 0;      /**       * Set the size of the file in bytes @@ -52,15 +48,16 @@ public:      virtual bool SetSize(u64 size) const = 0;      /** -     * Close the file -     * @return true if the file closed correctly +     * Get the size of the file in bytes +     * @return Size of the file in bytes       */ -    virtual bool Close() const = 0; +    virtual u64 GetSize() const = 0;      /** -     * Flushes the file +     * Close the file +     * @return true if the file closed correctly       */ -    virtual void Flush() const = 0; +    virtual bool Close() const = 0;  };  } // namespace FileSys diff --git a/src/core/file_sys/title_metadata.cpp b/src/core/file_sys/title_metadata.cpp deleted file mode 100644 index e29ba6064..000000000 --- a/src/core/file_sys/title_metadata.cpp +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <cinttypes> -#include "common/alignment.h" -#include "common/file_util.h" -#include "common/logging/log.h" -#include "core/file_sys/title_metadata.h" -#include "core/loader/loader.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -static u32 GetSignatureSize(u32 signature_type) { -    switch (signature_type) { -    case Rsa4096Sha1: -    case Rsa4096Sha256: -        return 0x200; - -    case Rsa2048Sha1: -    case Rsa2048Sha256: -        return 0x100; - -    case EllipticSha1: -    case EcdsaSha256: -        return 0x3C; -    } -} - -Loader::ResultStatus TitleMetadata::Load() { -    FileUtil::IOFile file(filepath, "rb"); -    if (!file.IsOpen()) -        return Loader::ResultStatus::Error; - -    if (!file.ReadBytes(&signature_type, sizeof(u32_be))) -        return Loader::ResultStatus::Error; - -    // Signature lengths are variable, and the body follows the signature -    u32 signature_size = GetSignatureSize(signature_type); - -    tmd_signature.resize(signature_size); -    if (!file.ReadBytes(&tmd_signature[0], signature_size)) -        return Loader::ResultStatus::Error; - -    // The TMD body start position is rounded to the nearest 0x40 after the signature -    size_t body_start = Common::AlignUp(signature_size + sizeof(u32), 0x40); -    file.Seek(body_start, SEEK_SET); - -    // Read our TMD body, then load the amount of ContentChunks specified -    if (file.ReadBytes(&tmd_body, sizeof(TitleMetadata::Body)) != sizeof(TitleMetadata::Body)) -        return Loader::ResultStatus::Error; - -    for (u16 i = 0; i < tmd_body.content_count; i++) { -        ContentChunk chunk; -        if (file.ReadBytes(&chunk, sizeof(ContentChunk)) == sizeof(ContentChunk)) { -            tmd_chunks.push_back(chunk); -        } else { -            LOG_ERROR(Service_FS, "Malformed TMD %s, failed to load content chunk index %u!", -                      filepath.c_str(), i); -            return Loader::ResultStatus::ErrorInvalidFormat; -        } -    } - -    return Loader::ResultStatus::Success; -} - -Loader::ResultStatus TitleMetadata::Save() { -    UNIMPLEMENTED(); -    return Loader::ResultStatus::Success; -} - -u64 TitleMetadata::GetTitleID() const { -    return tmd_body.title_id; -} - -u32 TitleMetadata::GetTitleType() const { -    return tmd_body.title_type; -} - -u16 TitleMetadata::GetTitleVersion() const { -    return tmd_body.title_version; -} - -u64 TitleMetadata::GetSystemVersion() const { -    return tmd_body.system_version; -} - -size_t TitleMetadata::GetContentCount() const { -    return tmd_chunks.size(); -} - -u32 TitleMetadata::GetBootContentID() const { -    return tmd_chunks[TMDContentIndex::Main].id; -} - -u32 TitleMetadata::GetManualContentID() const { -    return tmd_chunks[TMDContentIndex::Manual].id; -} - -u32 TitleMetadata::GetDLPContentID() const { -    return tmd_chunks[TMDContentIndex::DLP].id; -} - -void TitleMetadata::SetTitleID(u64 title_id) { -    tmd_body.title_id = title_id; -} - -void TitleMetadata::SetTitleType(u32 type) { -    tmd_body.title_type = type; -} - -void TitleMetadata::SetTitleVersion(u16 version) { -    tmd_body.title_version = version; -} - -void TitleMetadata::SetSystemVersion(u64 version) { -    tmd_body.system_version = version; -} - -void TitleMetadata::AddContentChunk(const ContentChunk& chunk) { -    tmd_chunks.push_back(chunk); -} - -void TitleMetadata::Print() const { -    LOG_DEBUG(Service_FS, "%s - %u chunks", filepath.c_str(), -              static_cast<u32>(tmd_body.content_count)); - -    // Content info describes ranges of content chunks -    LOG_DEBUG(Service_FS, "Content info:"); -    for (size_t i = 0; i < tmd_body.contentinfo.size(); i++) { -        if (tmd_body.contentinfo[i].command_count == 0) -            break; - -        LOG_DEBUG(Service_FS, "    Index %04X, Command Count %04X", -                  static_cast<u32>(tmd_body.contentinfo[i].index), -                  static_cast<u32>(tmd_body.contentinfo[i].command_count)); -    } - -    // For each content info, print their content chunk range -    for (size_t i = 0; i < tmd_body.contentinfo.size(); i++) { -        u16 index = static_cast<u16>(tmd_body.contentinfo[i].index); -        u16 count = static_cast<u16>(tmd_body.contentinfo[i].command_count); - -        if (count == 0) -            continue; - -        LOG_DEBUG(Service_FS, "Content chunks for content info index %zu:", i); -        for (u16 j = index; j < index + count; j++) { -            // Don't attempt to print content we don't have -            if (j > tmd_body.content_count) -                break; - -            const ContentChunk& chunk = tmd_chunks[j]; -            LOG_DEBUG(Service_FS, "    ID %08X, Index %04X, Type %04x, Size %016" PRIX64, -                      static_cast<u32>(chunk.id), static_cast<u32>(chunk.index), -                      static_cast<u32>(chunk.type), static_cast<u64>(chunk.size)); -        } -    } -} -} // namespace FileSys diff --git a/src/core/file_sys/title_metadata.h b/src/core/file_sys/title_metadata.h deleted file mode 100644 index a4c7d1089..000000000 --- a/src/core/file_sys/title_metadata.h +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <array> -#include <string> -#include <vector> -#include "common/common_types.h" -#include "common/swap.h" - -namespace Loader { -enum class ResultStatus; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -enum TMDSignatureType : u32 { -    Rsa4096Sha1 = 0x10000, -    Rsa2048Sha1 = 0x10001, -    EllipticSha1 = 0x10002, -    Rsa4096Sha256 = 0x10003, -    Rsa2048Sha256 = 0x10004, -    EcdsaSha256 = 0x10005 -}; - -enum TMDContentTypeFlag : u16 { -    Encrypted = 1 << 1, -    Disc = 1 << 2, -    CFM = 1 << 3, -    Optional = 1 << 14, -    Shared = 1 << 15 -}; - -/** - * Helper which implements an interface to read and write Title Metadata (TMD) files. - * If a file path is provided and the file exists, it can be parsed and used, otherwise - * it must be created. The TMD file can then be interpreted, modified and/or saved. - */ -class TitleMetadata { -public: -    struct ContentChunk { -        u32_be id; -        u16_be index; -        u16_be type; -        u64_be size; -        std::array<u8, 0x20> hash; -    }; - -    static_assert(sizeof(ContentChunk) == 0x30, "TMD ContentChunk structure size is wrong"); - -    struct ContentInfo { -        u16_be index; -        u16_be command_count; -        std::array<u8, 0x20> hash; -    }; - -    static_assert(sizeof(ContentInfo) == 0x24, "TMD ContentInfo structure size is wrong"); - -#pragma pack(push, 1) - -    struct Body { -        std::array<u8, 0x40> issuer; -        u8 version; -        u8 ca_crl_version; -        u8 signer_crl_version; -        u8 reserved; -        u64_be system_version; -        u64_be title_id; -        u32_be title_type; -        u16_be group_id; -        u32_be savedata_size; -        u32_be srl_private_savedata_size; -        std::array<u8, 4> reserved_2; -        u8 srl_flag; -        std::array<u8, 0x31> reserved_3; -        u32_be access_rights; -        u16_be title_version; -        u16_be content_count; -        u16_be boot_content; -        std::array<u8, 2> reserved_4; -        std::array<u8, 0x20> contentinfo_hash; -        std::array<ContentInfo, 64> contentinfo; -    }; - -    static_assert(sizeof(Body) == 0x9C4, "TMD body structure size is wrong"); - -#pragma pack(pop) - -    explicit TitleMetadata(std::string& path) : filepath(std::move(path)) {} -    Loader::ResultStatus Load(); -    Loader::ResultStatus Save(); - -    u64 GetTitleID() const; -    u32 GetTitleType() const; -    u16 GetTitleVersion() const; -    u64 GetSystemVersion() const; -    size_t GetContentCount() const; -    u32 GetBootContentID() const; -    u32 GetManualContentID() const; -    u32 GetDLPContentID() const; - -    void SetTitleID(u64 title_id); -    void SetTitleType(u32 type); -    void SetTitleVersion(u16 version); -    void SetSystemVersion(u64 version); -    void AddContentChunk(const ContentChunk& chunk); - -    void Print() const; - -private: -    enum TMDContentIndex { Main = 0, Manual = 1, DLP = 2 }; - -    Body tmd_body; -    u32_be signature_type; -    std::vector<u8> tmd_signature; -    std::vector<ContentChunk> tmd_chunks; - -    std::string filepath; -}; - -} // namespace FileSys diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 2f3ccb689..2405da0c6 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -57,9 +57,10 @@ const u32 SIGTERM = 15;  const u32 MSG_WAITALL = 8;  #endif -const u32 R15_REGISTER = 15; -const u32 CPSR_REGISTER = 25; -const u32 FPSCR_REGISTER = 58; +const u32 X30_REGISTER = 30; +const u32 SP_REGISTER = 31; +const u32 PC_REGISTER = 32; +const u32 CPSR_REGISTER = 33;  // For sample XML files see the GDB source /gdb/features  // GDB also wants the l character at the start @@ -68,48 +69,62 @@ static const char* target_xml =      R"(l<?xml version="1.0"?>  <!DOCTYPE target SYSTEM "gdb-target.dtd">  <target version="1.0"> -  <feature name="org.gnu.gdb.arm.core"> -    <reg name="r0" bitsize="32"/> -    <reg name="r1" bitsize="32"/> -    <reg name="r2" bitsize="32"/> -    <reg name="r3" bitsize="32"/> -    <reg name="r4" bitsize="32"/> -    <reg name="r5" bitsize="32"/> -    <reg name="r6" bitsize="32"/> -    <reg name="r7" bitsize="32"/> -    <reg name="r8" bitsize="32"/> -    <reg name="r9" bitsize="32"/> -    <reg name="r10" bitsize="32"/> -    <reg name="r11" bitsize="32"/> -    <reg name="r12" bitsize="32"/> -    <reg name="sp" bitsize="32" type="data_ptr"/> -    <reg name="lr" bitsize="32"/> -    <reg name="pc" bitsize="32" type="code_ptr"/> - -    <!-- The CPSR is register 25, rather than register 16, because -         the FPA registers historically were placed between the PC -         and the CPSR in the "g" packet.  --> - -    <reg name="cpsr" bitsize="32" regnum="25"/> -  </feature> -  <feature name="org.gnu.gdb.arm.vfp"> -    <reg name="d0" bitsize="64" type="float"/> -    <reg name="d1" bitsize="64" type="float"/> -    <reg name="d2" bitsize="64" type="float"/> -    <reg name="d3" bitsize="64" type="float"/> -    <reg name="d4" bitsize="64" type="float"/> -    <reg name="d5" bitsize="64" type="float"/> -    <reg name="d6" bitsize="64" type="float"/> -    <reg name="d7" bitsize="64" type="float"/> -    <reg name="d8" bitsize="64" type="float"/> -    <reg name="d9" bitsize="64" type="float"/> -    <reg name="d10" bitsize="64" type="float"/> -    <reg name="d11" bitsize="64" type="float"/> -    <reg name="d12" bitsize="64" type="float"/> -    <reg name="d13" bitsize="64" type="float"/> -    <reg name="d14" bitsize="64" type="float"/> -    <reg name="d15" bitsize="64" type="float"/> -    <reg name="fpscr" bitsize="32" type="int" group="float"/> +  <feature name="org.gnu.gdb.aarch64.core"> +    <reg name="x0" bitsize="64"/> +    <reg name="x1" bitsize="64"/> +    <reg name="x2" bitsize="64"/> +    <reg name="x3" bitsize="64"/> +    <reg name="x4" bitsize="64"/> +    <reg name="x5" bitsize="64"/> +    <reg name="x6" bitsize="64"/> +    <reg name="x7" bitsize="64"/> +    <reg name="x8" bitsize="64"/> +    <reg name="x9" bitsize="64"/> +    <reg name="x10" bitsize="64"/> +    <reg name="x11" bitsize="64"/> +    <reg name="x12" bitsize="64"/> +    <reg name="x13" bitsize="64"/> +    <reg name="x14" bitsize="64"/> +    <reg name="x15" bitsize="64"/> +    <reg name="x16" bitsize="64"/> +    <reg name="x17" bitsize="64"/> +    <reg name="x18" bitsize="64"/> +    <reg name="x19" bitsize="64"/> +    <reg name="x20" bitsize="64"/> +    <reg name="x21" bitsize="64"/> +    <reg name="x22" bitsize="64"/> +    <reg name="x23" bitsize="64"/> +    <reg name="x24" bitsize="64"/> +    <reg name="x25" bitsize="64"/> +    <reg name="x26" bitsize="64"/> +    <reg name="x27" bitsize="64"/> +    <reg name="x28" bitsize="64"/> +    <reg name="x29" bitsize="64"/> +    <reg name="x30" bitsize="64"/> +    <reg name="sp" bitsize="64" type="data_ptr"/> + +    <reg name="pc" bitsize="64" type="code_ptr"/> + +    <flags id="cpsr_flags" size="4"> +      <field name="SP" start="0" end="0"/> +      <field name="" start="1" end="1"/> +      <field name="EL" start="2" end="3"/> +      <field name="nRW" start="4" end="4"/> +      <field name="" start="5" end="5"/> +      <field name="F" start="6" end="6"/> +      <field name="I" start="7" end="7"/> +      <field name="A" start="8" end="8"/> +      <field name="D" start="9" end="9"/> + +      <field name="IL" start="20" end="20"/> +      <field name="SS" start="21" end="21"/> + +      <field name="V" start="28" end="28"/> +      <field name="C" start="29" end="29"/> +      <field name="Z" start="30" end="30"/> +      <field name="N" start="31" end="31"/> +    </flags> +    <reg name="cpsr" bitsize="32" type="cpsr_flags"/>    </feature>  </target>  )"; @@ -143,12 +158,12 @@ WSADATA InitData;  struct Breakpoint {      bool active;      PAddr addr; -    u32 len; +    u64 len;  }; -static std::map<u32, Breakpoint> breakpoints_execute; -static std::map<u32, Breakpoint> breakpoints_read; -static std::map<u32, Breakpoint> breakpoints_write; +static std::map<u64, Breakpoint> breakpoints_execute; +static std::map<u64, Breakpoint> breakpoints_read; +static std::map<u64, Breakpoint> breakpoints_write;  /**   * Turns hex string character into the equivalent byte. @@ -198,6 +213,21 @@ static u32 HexToInt(const u8* src, size_t len) {  }  /** + * Converts input hex string characters into an array of equivalent of u8 bytes. + * + * @param src Pointer to array of output hex string characters. + * @param len Length of src array. + */ +static u64 HexToLong(const u8* src, size_t len) { +    u64 output = 0; +    while (len-- > 0) { +        output = (output << 4) | HexCharToValue(src[0]); +        src++; +    } +    return output; +} + +/**   * Converts input array of u8 bytes into their equivalent hex string characters.   *   * @param dest Pointer to buffer to store output hex string characters. @@ -234,8 +264,21 @@ static void GdbHexToMem(u8* dest, const u8* src, size_t len) {   */  static void IntToGdbHex(u8* dest, u32 v) {      for (int i = 0; i < 8; i += 2) { -        dest[i + 1] = NibbleToHex(v >> (4 * i)); -        dest[i] = NibbleToHex(v >> (4 * (i + 1))); +        dest[i + 1] = NibbleToHex(static_cast<u8>(v >> (4 * i))); +        dest[i] = NibbleToHex(static_cast<u8>(v >> (4 * (i + 1)))); +    } +} + +/** + * Convert a u64 into a gdb-formatted hex string. + * + * @param dest Pointer to buffer to store output hex string characters. + * @param v    Value to convert. + */ +static void LongToGdbHex(u8* dest, u64 v) { +    for (int i = 0; i < 16; i += 2) { +        dest[i + 1] = NibbleToHex(static_cast<u8>(v >> (4 * i))); +        dest[i] = NibbleToHex(static_cast<u8>(v >> (4 * (i + 1))));      }  } @@ -255,6 +298,22 @@ static u32 GdbHexToInt(const u8* src) {      return output;  } +/** + * Convert a gdb-formatted hex string into a u64. + * + * @param src Pointer to hex string. + */ +static u64 GdbHexToLong(const u8* src) { +    u64 output = 0; + +    for (int i = 0; i < 16; i += 2) { +        output = (output << 4) | HexCharToValue(src[15 - i - 1]); +        output = (output << 4) | HexCharToValue(src[15 - i]); +    } + +    return output; +} +  /// Read a byte from the gdb client.  static u8 ReadByte() {      u8 c; @@ -277,7 +336,7 @@ static u8 CalculateChecksum(const u8* buffer, size_t length) {   *   * @param type Type of breakpoint list.   */ -static std::map<u32, Breakpoint>& GetBreakpointList(BreakpointType type) { +static std::map<u64, Breakpoint>& GetBreakpointList(BreakpointType type) {      switch (type) {      case BreakpointType::Execute:          return breakpoints_execute; @@ -297,19 +356,19 @@ static std::map<u32, Breakpoint>& GetBreakpointList(BreakpointType type) {   * @param addr Address of breakpoint.   */  static void RemoveBreakpoint(BreakpointType type, PAddr addr) { -    std::map<u32, Breakpoint>& p = GetBreakpointList(type); +    std::map<u64, Breakpoint>& p = GetBreakpointList(type); -    auto bp = p.find(static_cast<u32>(addr)); +    auto bp = p.find(static_cast<u64>(addr));      if (bp != p.end()) {          LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: %08x bytes at %08x of type %d\n",                    bp->second.len, bp->second.addr, type); -        p.erase(static_cast<u32>(addr)); +        p.erase(static_cast<u64>(addr));      }  }  BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, BreakpointType type) { -    std::map<u32, Breakpoint>& p = GetBreakpointList(type); -    auto next_breakpoint = p.lower_bound(static_cast<u32>(addr)); +    std::map<u64, Breakpoint>& p = GetBreakpointList(type); +    auto next_breakpoint = p.lower_bound(static_cast<u64>(addr));      BreakpointAddress breakpoint;      if (next_breakpoint != p.end()) { @@ -328,11 +387,11 @@ bool CheckBreakpoint(PAddr addr, BreakpointType type) {          return false;      } -    std::map<u32, Breakpoint>& p = GetBreakpointList(type); +    std::map<u64, Breakpoint>& p = GetBreakpointList(type); -    auto bp = p.find(static_cast<u32>(addr)); +    auto bp = p.find(static_cast<u64>(addr));      if (bp != p.end()) { -        u32 len = bp->second.len; +        u64 len = bp->second.len;          // IDA Pro defaults to 4-byte breakpoints for all non-hardware breakpoints          // no matter if it's a 4-byte or 2-byte instruction. When you execute a @@ -419,7 +478,7 @@ static void HandleQuery() {          SendReply("T0");      } else if (strncmp(query, "Supported", strlen("Supported")) == 0) {          // PacketSize needs to be large enough for target xml -        SendReply("PacketSize=800;qXfer:features:read+"); +        SendReply("PacketSize=2000;qXfer:features:read+");      } else if (strncmp(query, "Xfer:features:read:target.xml:",                         strlen("Xfer:features:read:target.xml:")) == 0) {          SendReply(target_xml); @@ -450,10 +509,7 @@ static void SendSignal(u32 signal) {      latest_signal = signal; -    std::string buffer = -        Common::StringFromFormat("T%02x%02x:%08x;%02x:%08x;", latest_signal, 15, -                                 htonl(static_cast<u_long>(Core::CPU().GetPC())), 13, -                                 htonl(static_cast<u_long>(Core::CPU().GetReg(13)))); +    std::string buffer = Common::StringFromFormat("T%02x", latest_signal);      LOG_DEBUG(Debug_GDBStub, "Response: %s", buffer.c_str());      SendReply(buffer.c_str());  } @@ -539,16 +595,12 @@ static void ReadRegister() {          id |= HexCharToValue(command_buffer[2]);      } -    if (id <= R15_REGISTER) { -        IntToGdbHex(reply, static_cast<u32>(Core::CPU().GetReg(static_cast<u64>(id)))); +    if (id <= SP_REGISTER) { +        LongToGdbHex(reply, Core::CPU().GetReg(static_cast<int>(id))); +    } else if (id == PC_REGISTER) { +        LongToGdbHex(reply, Core::CPU().GetPC());      } else if (id == CPSR_REGISTER) {          IntToGdbHex(reply, Core::CPU().GetCPSR()); -    } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { -        IntToGdbHex(reply, Core::CPU().GetVFPReg( -                               id - CPSR_REGISTER - -                               1)); // VFP registers should start at 26, so one after CSPR_REGISTER -    } else if (id == FPSCR_REGISTER) { -        UNIMPLEMENTED();      } else {          return SendReply("E01");      } @@ -563,21 +615,19 @@ static void ReadRegisters() {      u8* bufptr = buffer; -    for (int reg = 0; reg <= R15_REGISTER; reg++) { -        IntToGdbHex(bufptr + reg * CHAR_BIT, static_cast<u32>(Core::CPU().GetReg(reg))); +    for (int reg = 0; reg <= SP_REGISTER; reg++) { +        LongToGdbHex(bufptr + reg * 16, Core::CPU().GetReg(reg));      } -    bufptr += (16 * CHAR_BIT); +    bufptr += (32 * 16); -    IntToGdbHex(bufptr, Core::CPU().GetCPSR()); +    LongToGdbHex(bufptr, Core::CPU().GetPC()); -    bufptr += CHAR_BIT; +    bufptr += 16; -    for (int reg = 0; reg <= 31; reg++) { -        IntToGdbHex(bufptr + reg * CHAR_BIT, Core::CPU().GetVFPReg(reg)); -    } +    IntToGdbHex(bufptr, Core::CPU().GetCPSR()); -    bufptr += (32 * CHAR_BIT); +    bufptr += 8;      SendReply(reinterpret_cast<char*>(buffer));  } @@ -593,14 +643,12 @@ static void WriteRegister() {          id |= HexCharToValue(command_buffer[2]);      } -    if (id <= R15_REGISTER) { -        Core::CPU().SetReg(id, GdbHexToInt(buffer_ptr)); +    if (id <= SP_REGISTER) { +        Core::CPU().SetReg(id, GdbHexToLong(buffer_ptr)); +    } else if (id == PC_REGISTER) { +        Core::CPU().SetPC(GdbHexToLong(buffer_ptr));      } else if (id == CPSR_REGISTER) {          Core::CPU().SetCPSR(GdbHexToInt(buffer_ptr)); -    } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { -        Core::CPU().SetVFPReg(id - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr)); -    } else if (id == FPSCR_REGISTER) { -        UNIMPLEMENTED();      } else {          return SendReply("E01");      } @@ -615,20 +663,14 @@ static void WriteRegisters() {      if (command_buffer[0] != 'G')          return SendReply("E01"); -    for (int i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) { -        if (reg <= R15_REGISTER) { -            Core::CPU().SetReg(reg, GdbHexToInt(buffer_ptr + i * CHAR_BIT)); +    for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) { +        if (reg <= SP_REGISTER) { +            Core::CPU().SetReg(reg, GdbHexToLong(buffer_ptr + i * 16)); +        } else if (reg == PC_REGISTER) { +            Core::CPU().SetPC(GdbHexToLong(buffer_ptr + i * 16));          } else if (reg == CPSR_REGISTER) { -            Core::CPU().SetCPSR(GdbHexToInt(buffer_ptr + i * CHAR_BIT)); -        } else if (reg == CPSR_REGISTER - 1) { -            // Dummy FPA register, ignore -        } else if (reg < CPSR_REGISTER) { -            // Dummy FPA registers, ignore -            i += 2; -        } else if (reg > CPSR_REGISTER && reg < FPSCR_REGISTER) { -            Core::CPU().SetVFPReg(reg - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr + i * CHAR_BIT)); -            i++; // Skip padding -        } else if (reg == FPSCR_REGISTER) { +            Core::CPU().SetCPSR(GdbHexToInt(buffer_ptr + i * 16)); +        } else {              UNIMPLEMENTED();          }      } @@ -642,13 +684,13 @@ static void ReadMemory() {      auto start_offset = command_buffer + 1;      auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); -    VAddr addr = HexToInt(start_offset, static_cast<u32>(addr_pos - start_offset)); +    VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));      start_offset = addr_pos + 1; -    u32 len = -        HexToInt(start_offset, static_cast<u32>((command_buffer + command_length) - start_offset)); +    u64 len = +        HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset)); -    LOG_DEBUG(Debug_GDBStub, "gdb: addr: %08x len: %08x\n", addr, len); +    LOG_DEBUG(Debug_GDBStub, "gdb: addr: %016llx len: %016llx\n", addr, len);      if (len * 2 > sizeof(reply)) {          SendReply("E01"); @@ -670,11 +712,11 @@ static void ReadMemory() {  static void WriteMemory() {      auto start_offset = command_buffer + 1;      auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); -    VAddr addr = HexToInt(start_offset, static_cast<u32>(addr_pos - start_offset)); +    VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));      start_offset = addr_pos + 1;      auto len_pos = std::find(start_offset, command_buffer + command_length, ':'); -    u32 len = HexToInt(start_offset, static_cast<u32>(len_pos - start_offset)); +    u64 len = HexToLong(start_offset, static_cast<u64>(len_pos - start_offset));      if (!Memory::IsValidVirtualAddress(addr)) {          return SendReply("E00"); @@ -727,8 +769,8 @@ static void Continue() {   * @param addr Address of breakpoint.   * @param len Length of breakpoint.   */ -static bool CommitBreakpoint(BreakpointType type, PAddr addr, u32 len) { -    std::map<u32, Breakpoint>& p = GetBreakpointList(type); +static bool CommitBreakpoint(BreakpointType type, PAddr addr, u64 len) { +    std::map<u64, Breakpoint>& p = GetBreakpointList(type);      Breakpoint breakpoint;      breakpoint.active = true; @@ -767,11 +809,11 @@ static void AddBreakpoint() {      auto start_offset = command_buffer + 3;      auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); -    PAddr addr = HexToInt(start_offset, static_cast<u32>(addr_pos - start_offset)); +    PAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));      start_offset = addr_pos + 1; -    u32 len = -        HexToInt(start_offset, static_cast<u32>((command_buffer + command_length) - start_offset)); +    u64 len = +        HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset));      if (type == BreakpointType::Access) {          // Access is made up of Read and Write types, so add both breakpoints @@ -816,7 +858,7 @@ static void RemoveBreakpoint() {      auto start_offset = command_buffer + 3;      auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); -    PAddr addr = HexToInt(start_offset, static_cast<u32>(addr_pos - start_offset)); +    PAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));      if (type == BreakpointType::Access) {          // Access is made up of Read and Write types, so add both breakpoints diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 4c9b0de28..6066d8a18 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -11,7 +11,6 @@  #include "core/hle/ipc.h"  #include "core/hle/kernel/client_port.h"  #include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/domain.h"  #include "core/hle/kernel/handle_table.h"  #include "core/hle/kernel/hle_ipc.h"  #include "core/hle/kernel/kernel.h" @@ -31,11 +30,6 @@ public:      RequestHelperBase(Kernel::HLERequestContext& context)          : context(&context), cmdbuf(context.CommandBuffer()) {} -    void ValidateHeader() { -        // DEBUG_ASSERT_MSG(index == TotalSize(), "Operations do not match the header (cmd 0x%x)", -        //                 header.raw); -    } -      void Skip(unsigned size_in_words, bool set_to_null) {          if (set_to_null)              memset(cmdbuf + index, 0, size_in_words * sizeof(u32)); @@ -60,14 +54,30 @@ public:      }  }; -class RequestBuilder : public RequestHelperBase { +class ResponseBuilder : public RequestHelperBase {  public: -    RequestBuilder(u32* command_buffer) : RequestHelperBase(command_buffer) {} +    ResponseBuilder(u32* command_buffer) : RequestHelperBase(command_buffer) {} + +    u32 normal_params_size{}; +    u32 num_handles_to_copy{}; +    u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent +    std::ptrdiff_t datapayload_index{}; + +    /// Flags used for customizing the behavior of ResponseBuilder +    enum class Flags : u32 { +        None = 0, +        /// Uses move handles to move objects in the response, even when in a domain. This is +        /// required when PushMoveObjects is used. +        AlwaysMoveHandles = 1, +    }; + +    ResponseBuilder(Kernel::HLERequestContext& context, u32 normal_params_size, +                    u32 num_handles_to_copy = 0, u32 num_objects_to_move = 0, +                    Flags flags = Flags::None) + +        : RequestHelperBase(context), normal_params_size(normal_params_size), +          num_handles_to_copy(num_handles_to_copy), num_objects_to_move(num_objects_to_move) { -    RequestBuilder(Kernel::HLERequestContext& context, unsigned normal_params_size, -                   u32 num_handles_to_copy = 0, u32 num_handles_to_move = 0, -                   u32 num_domain_objects = 0) -        : RequestHelperBase(context) {          memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH);          context.ClearIncomingObjects(); @@ -77,12 +87,19 @@ public:          // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory          // padding.          u32 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size; -        if (context.IsDomain()) { -            raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects; + +        u32 num_handles_to_move{}; +        u32 num_domain_objects{}; +        const bool always_move_handles{ +            (static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0}; +        if (!context.Session()->IsDomain() || always_move_handles) { +            num_handles_to_move = num_objects_to_move;          } else { -            // If we're not in a domain, turn the domain object parameters into move handles. -            num_handles_to_move += num_domain_objects; -            num_domain_objects = 0; +            num_domain_objects = num_objects_to_move; +        } + +        if (context.Session()->IsDomain()) { +            raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects;          }          header.data_size.Assign(raw_data_size); @@ -101,7 +118,7 @@ public:          AlignWithPadding(); -        if (context.IsDomain()) { +        if (context.Session()->IsDomain()) {              IPC::DomainMessageHeader domain_header{};              domain_header.num_objects = num_domain_objects;              PushRaw(domain_header); @@ -110,23 +127,43 @@ public:          IPC::DataPayloadHeader data_payload_header{};          data_payload_header.magic = Common::MakeMagic('S', 'F', 'C', 'O');          PushRaw(data_payload_header); + +        datapayload_index = index;      } -    template <class T, class... Args> -    void PushIpcInterface(Args&&... args) { -        auto iface = std::make_shared<T>(std::forward<Args>(args)...); -        if (context->IsDomain()) { +    template <class T> +    void PushIpcInterface(std::shared_ptr<T> iface) { +        if (context->Session()->IsDomain()) {              context->AddDomainObject(std::move(iface));          } else { -            auto port = iface->CreatePort(); -            auto session = port->Connect(); -            ASSERT(session.Succeeded()); -            context->AddMoveObject(std::move(session).Unwrap()); +            auto sessions = Kernel::ServerSession::CreateSessionPair(iface->GetServiceName()); +            auto server = std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions); +            auto client = std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions); +            iface->ClientConnected(server); +            context->AddMoveObject(std::move(client));          }      } +    template <class T, class... Args> +    void PushIpcInterface(Args&&... args) { +        PushIpcInterface<T>(std::make_shared<T>(std::forward<Args>(args)...)); +    } + +    void ValidateHeader() { +        const size_t num_domain_objects = context->NumDomainObjects(); +        const size_t num_move_objects = context->NumMoveObjects(); +        ASSERT_MSG(!num_domain_objects || !num_move_objects, +                   "cannot move normal handles and domain objects"); +        ASSERT_MSG((index - datapayload_index) == normal_params_size, +                   "normal_params_size value is incorrect"); +        ASSERT_MSG((num_domain_objects + num_move_objects) == num_objects_to_move, +                   "num_objects_to_move value is incorrect"); +        ASSERT_MSG(context->NumCopyObjects() == num_handles_to_copy, +                   "num_handles_to_copy value is incorrect"); +    } +      // Validate on destruction, as there shouldn't be any case where we don't want it -    ~RequestBuilder() { +    ~ResponseBuilder() {          ValidateHeader();      } @@ -154,52 +191,52 @@ public:  /// Push ///  template <> -inline void RequestBuilder::Push(u32 value) { +inline void ResponseBuilder::Push(u32 value) {      cmdbuf[index++] = value;  }  template <typename T> -void RequestBuilder::PushRaw(const T& value) { +void ResponseBuilder::PushRaw(const T& value) {      std::memcpy(cmdbuf + index, &value, sizeof(T));      index += (sizeof(T) + 3) / 4; // round up to word length  }  template <> -inline void RequestBuilder::Push(ResultCode value) { +inline void ResponseBuilder::Push(ResultCode value) {      // Result codes are actually 64-bit in the IPC buffer, but only the high part is discarded.      Push(value.raw);      Push<u32>(0);  }  template <> -inline void RequestBuilder::Push(u8 value) { +inline void ResponseBuilder::Push(u8 value) {      PushRaw(value);  }  template <> -inline void RequestBuilder::Push(u16 value) { +inline void ResponseBuilder::Push(u16 value) {      PushRaw(value);  }  template <> -inline void RequestBuilder::Push(u64 value) { +inline void ResponseBuilder::Push(u64 value) {      Push(static_cast<u32>(value));      Push(static_cast<u32>(value >> 32));  }  template <> -inline void RequestBuilder::Push(bool value) { +inline void ResponseBuilder::Push(bool value) {      Push(static_cast<u8>(value));  }  template <typename First, typename... Other> -void RequestBuilder::Push(const First& first_value, const Other&... other_values) { +void ResponseBuilder::Push(const First& first_value, const Other&... other_values) {      Push(first_value);      Push(other_values...);  }  template <typename... O> -inline void RequestBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) { +inline void ResponseBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) {      auto objects = {pointers...};      for (auto& object : objects) {          context->AddCopyObject(std::move(object)); @@ -207,7 +244,7 @@ inline void RequestBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) {  }  template <typename... O> -inline void RequestBuilder::PushMoveObjects(Kernel::SharedPtr<O>... pointers) { +inline void ResponseBuilder::PushMoveObjects(Kernel::SharedPtr<O>... pointers) {      auto objects = {pointers...};      for (auto& object : objects) {          context->AddMoveObject(std::move(object)); @@ -226,15 +263,10 @@ public:          Skip(CommandIdSize, false);      } -    RequestBuilder MakeBuilder(u32 normal_params_size, u32 num_handles_to_copy, -                               u32 num_handles_to_move, u32 num_domain_objects, -                               bool validate_header = true) { -        if (validate_header) { -            ValidateHeader(); -        } - -        return {*context, normal_params_size, num_handles_to_copy, num_handles_to_move, -                num_domain_objects}; +    ResponseBuilder MakeBuilder(u32 normal_params_size, u32 num_handles_to_copy, +                                u32 num_handles_to_move, +                                ResponseBuilder::Flags flags = ResponseBuilder::Flags::None) { +        return {*context, normal_params_size, num_handles_to_copy, num_handles_to_move, flags};      }      template <typename T> @@ -305,6 +337,11 @@ inline u64 RequestParser::Pop() {  }  template <> +inline s64 RequestParser::Pop() { +    return static_cast<s64>(Pop<u64>()); +} + +template <>  inline bool RequestParser::Pop() {      return Pop<u8>() != 0;  } diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index d6ab4f893..2258f95bc 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -7,7 +7,7 @@  #include <memory>  #include <string>  #include "common/common_types.h" -#include "core/hle/kernel/sync_object.h" +#include "core/hle/kernel/kernel.h"  #include "core/hle/result.h"  namespace Kernel { @@ -16,7 +16,7 @@ class ServerSession;  class Session;  class Thread; -class ClientSession final : public SyncObject { +class ClientSession final : public Object {  public:      friend class ServerSession; @@ -33,7 +33,7 @@ public:          return HANDLE_TYPE;      } -    ResultCode SendSyncRequest(SharedPtr<Thread> thread) override; +    ResultCode SendSyncRequest(SharedPtr<Thread> thread);      std::string name; ///< Name of client port (optional) diff --git a/src/core/hle/kernel/domain.cpp b/src/core/hle/kernel/domain.cpp deleted file mode 100644 index 5035e9c08..000000000 --- a/src/core/hle/kernel/domain.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/logging/log.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/domain.h" -#include "core/hle/kernel/handle_table.h" -#include "core/hle/kernel/hle_ipc.h" -#include "core/hle/kernel/process.h" -#include "core/hle/kernel/session.h" -#include "core/hle/kernel/thread.h" - -namespace Kernel { - -ResultVal<SharedPtr<Domain>> Domain::Create(std::string name) { -    SharedPtr<Domain> domain(new Domain); -    domain->name = std::move(name); -    return MakeResult(std::move(domain)); -} - -ResultVal<SharedPtr<Domain>> Domain::CreateFromSession(const Session& session) { -    auto res = Create(session.port->GetName() + "_Domain"); -    auto& domain = res.Unwrap(); -    domain->request_handlers.push_back(std::move(session.server->hle_handler)); -    Kernel::g_handle_table.ConvertSessionToDomain(session, domain); -    return res; -} - -ResultCode Domain::SendSyncRequest(SharedPtr<Thread> thread) { -    Kernel::HLERequestContext context(this); -    u32* cmd_buf = (u32*)Memory::GetPointer(Kernel::GetCurrentThread()->GetTLSAddress()); -    context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process, -                                              Kernel::g_handle_table); - -    auto& domain_message_header = context.GetDomainMessageHeader(); -    if (domain_message_header) { -        // If there is a DomainMessageHeader, then this is CommandType "Request" -        const u32 object_id{context.GetDomainMessageHeader()->object_id}; -        switch (domain_message_header->command) { -        case IPC::DomainMessageHeader::CommandType::SendMessage: -            return request_handlers[object_id - 1]->HandleSyncRequest(context); - -        case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { -            LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id); - -            request_handlers[object_id - 1] = nullptr; - -            IPC::RequestBuilder rb{context, 2}; -            rb.Push(RESULT_SUCCESS); - -            return RESULT_SUCCESS; -        } -        } - -        LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value()); -        UNIMPLEMENTED(); -    } -    return request_handlers.front()->HandleSyncRequest(context); -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/domain.h b/src/core/hle/kernel/domain.h deleted file mode 100644 index 3fec3b0b2..000000000 --- a/src/core/hle/kernel/domain.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <memory> -#include <string> -#include <vector> -#include "core/hle/kernel/sync_object.h" -#include "core/hle/result.h" - -namespace Kernel { - -class Session; -class SessionRequestHandler; - -class Domain final : public SyncObject { -public: -    std::string GetTypeName() const override { -        return "Domain"; -    } - -    static const HandleType HANDLE_TYPE = HandleType::Domain; -    HandleType GetHandleType() const override { -        return HANDLE_TYPE; -    } - -    static ResultVal<SharedPtr<Domain>> CreateFromSession(const Session& server); - -    ResultCode SendSyncRequest(SharedPtr<Thread> thread) override; - -    /// The name of this domain (optional) -    std::string name; - -    std::vector<std::shared_ptr<SessionRequestHandler>> request_handlers; - -private: -    Domain() = default; -    ~Domain() override = default; - -    static ResultVal<SharedPtr<Domain>> Create(std::string name = "Unknown"); -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 74d3d0514..3beb55753 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -5,12 +5,10 @@  #include <utility>  #include "common/assert.h"  #include "common/logging/log.h" -#include "core/hle/kernel/client_session.h"  #include "core/hle/kernel/errors.h"  #include "core/hle/kernel/handle_table.h"  #include "core/hle/kernel/kernel.h"  #include "core/hle/kernel/process.h" -#include "core/hle/kernel/session.h"  #include "core/hle/kernel/thread.h"  namespace Kernel { @@ -55,14 +53,6 @@ ResultVal<Handle> HandleTable::Duplicate(Handle handle) {      return Create(std::move(object));  } -void HandleTable::ConvertSessionToDomain(const Session& session, SharedPtr<Object> domain) { -    for (auto& object : objects) { -        if (DynamicObjectCast<ClientSession>(object) == session.client) { -            object = domain; -        } -    } -} -  ResultCode HandleTable::Close(Handle handle) {      if (!IsValid(handle))          return ERR_INVALID_HANDLE; diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index 935cc22b5..ba968c666 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h @@ -17,8 +17,6 @@ enum KernelHandle : Handle {      CurrentProcess = 0xFFFF8001,  }; -class Session; -  /**   * This class allows the creation of Handles, which are references to objects that can be tested   * for validity and looked up. Here they are used to pass references to kernel objects to/from the @@ -62,11 +60,6 @@ public:      ResultVal<Handle> Duplicate(Handle handle);      /** -     * Convert all handles of the specified Session to the specified Domain. -     */ -    void ConvertSessionToDomain(const Session& session, SharedPtr<Object> domain); - -    /**       * Closes a handle, removing it from the table and decreasing the object's ref-count.       * @return `RESULT_SUCCESS` or one of the following errors:       *           - `ERR_INVALID_HANDLE`: an invalid handle was passed in. diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index ecf32c18a..db104e8a2 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -7,7 +7,6 @@  #include "common/common_funcs.h"  #include "common/common_types.h"  #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/domain.h"  #include "core/hle/kernel/handle_table.h"  #include "core/hle/kernel/hle_ipc.h"  #include "core/hle/kernel/kernel.h" @@ -26,10 +25,6 @@ void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_s      boost::range::remove_erase(connected_sessions, server_session);  } -HLERequestContext::HLERequestContext(SharedPtr<Kernel::Domain> domain) : domain(std::move(domain)) { -    cmd_buf[0] = 0; -} -  HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session)      : server_session(std::move(server_session)) {      cmd_buf[0] = 0; @@ -87,7 +82,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {      // Padding to align to 16 bytes      rp.AlignWithPadding(); -    if (IsDomain() && (command_header->type == IPC::CommandType::Request || !incoming)) { +    if (Session()->IsDomain() && (command_header->type == IPC::CommandType::Request || !incoming)) {          // If this is an incoming message, only CommandType "Request" has a domain header          // All outgoing domain messages have the domain header          domain_message_header = @@ -200,12 +195,12 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P      // TODO(Subv): Translate the X/A/B/W buffers. -    if (IsDomain()) { +    if (Session()->IsDomain()) {          ASSERT(domain_message_header->num_objects == domain_objects.size());          // Write the domain objects to the command buffer, these go after the raw untranslated data.          // TODO(Subv): This completely ignores C buffers.          size_t domain_offset = size - domain_message_header->num_objects; -        auto& request_handlers = domain->request_handlers; +        auto& request_handlers = server_session->domain_request_handlers;          for (auto& object : domain_objects) {              request_handlers.emplace_back(object); diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 80fa48d7f..da8335b35 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -86,7 +86,6 @@ protected:   */  class HLERequestContext {  public: -    HLERequestContext(SharedPtr<Kernel::Domain> domain);      HLERequestContext(SharedPtr<Kernel::ServerSession> session);      ~HLERequestContext(); @@ -96,17 +95,10 @@ public:      }      /** -     * Returns the domain through which this request was made. -     */ -    const SharedPtr<Kernel::Domain>& Domain() const { -        return domain; -    } - -    /**       * Returns the session through which this request was made. This can be used as a map key to       * access per-client data on services.       */ -    const SharedPtr<Kernel::ServerSession>& ServerSession() const { +    const SharedPtr<Kernel::ServerSession>& Session() const {          return server_session;      } @@ -151,10 +143,6 @@ public:          return domain_message_header;      } -    bool IsDomain() const { -        return domain != nullptr; -    } -      template <typename T>      SharedPtr<T> GetCopyObject(size_t index) {          ASSERT(index < copy_objects.size()); @@ -187,9 +175,20 @@ public:          domain_objects.clear();      } +    size_t NumMoveObjects() const { +        return move_objects.size(); +    } + +    size_t NumCopyObjects() const { +        return copy_objects.size(); +    } + +    size_t NumDomainObjects() const { +        return domain_objects.size(); +    } +  private:      std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; -    SharedPtr<Kernel::Domain> domain;      SharedPtr<Kernel::ServerSession> server_session;      // TODO(yuriks): Check common usage of this and optimize size accordingly      boost::container::small_vector<SharedPtr<Object>, 8> move_objects; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 4d9549e45..c77e58f3c 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -31,7 +31,6 @@ enum class HandleType : u32 {      ServerPort,      ClientSession,      ServerSession, -    Domain,  };  enum { @@ -84,27 +83,12 @@ public:          case HandleType::CodeSet:          case HandleType::ClientPort:          case HandleType::ClientSession: -        case HandleType::Domain:              return false;          }          UNREACHABLE();      } -    /** -     * Check if svcSendSyncRequest can be called on the object -     * @return True svcSendSyncRequest can be called on the object, otherwise false -     */ -    bool IsSyncable() const { -        switch (GetHandleType()) { -        case HandleType::ClientSession: -        case HandleType::Domain: -            return true; -        } - -        UNREACHABLE(); -    } -  public:      static unsigned int next_object_id; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 09d02a691..54481f7f1 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -4,6 +4,7 @@  #include <tuple> +#include "core/hle/ipc_helpers.h"  #include "core/hle/kernel/client_port.h"  #include "core/hle/kernel/client_session.h"  #include "core/hle/kernel/handle_table.h" @@ -61,6 +62,38 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {      // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or      // similar. +    Kernel::HLERequestContext context(this); +    u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress()); +    context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process, +                                              Kernel::g_handle_table); + +    // If the session has been converted to a domain, handle the doomain request +    if (IsDomain()) { +        auto& domain_message_header = context.GetDomainMessageHeader(); +        if (domain_message_header) { +            // If there is a DomainMessageHeader, then this is CommandType "Request" +            const u32 object_id{context.GetDomainMessageHeader()->object_id}; +            switch (domain_message_header->command) { +            case IPC::DomainMessageHeader::CommandType::SendMessage: +                return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); + +            case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { +                LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id); + +                domain_request_handlers[object_id - 1] = nullptr; + +                IPC::ResponseBuilder rb{context, 2}; +                rb.Push(RESULT_SUCCESS); +                return RESULT_SUCCESS; +            } +            } + +            LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value()); +            ASSERT(false); +        } +        // If there is no domain header, the regular session handler is used +    } +      // If this ServerSession has an associated HLE handler, forward the request to it.      ResultCode result{RESULT_SUCCESS};      if (hle_handler != nullptr) { @@ -69,11 +102,6 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {          if (translate_result.IsError())              return translate_result; -        Kernel::HLERequestContext context(this); -        u32* cmd_buf = (u32*)Memory::GetPointer(Kernel::GetCurrentThread()->GetTLSAddress()); -        context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process, -                                                  Kernel::g_handle_table); -          result = hle_handler->HandleSyncRequest(context);      } else {          // Add the thread to the list of threads that have issued a sync request with this @@ -84,6 +112,15 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {      // If this ServerSession does not have an HLE implementation, just wake up the threads waiting      // on it.      WakeupAllWaitingThreads(); + +    // Handle scenario when ConvertToDomain command was issued, as we must do the conversion at the +    // end of the command such that only commands following this one are handled as domains +    if (convert_to_domain) { +        ASSERT_MSG(domain_request_handlers.empty(), "already a domain"); +        domain_request_handlers = {hle_handler}; +        convert_to_domain = false; +    } +      return result;  } diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 6ff4ef8c1..144692106 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -79,7 +79,10 @@ public:      std::string name;                ///< The name of this session (optional)      std::shared_ptr<Session> parent; ///< The parent session, which links to the client endpoint.      std::shared_ptr<SessionRequestHandler> -        hle_handler; ///< This session's HLE request handler (optional) +        hle_handler; ///< This session's HLE request handler (applicable when not a domain) + +    /// This is the list of domain request handlers (after conversion to a domain) +    std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers;      /// List of threads that are pending a response after a sync request. This list is processed in      /// a LIFO manner, thus, the last request will be dispatched first. @@ -91,6 +94,16 @@ public:      /// TODO(Subv): Find a better name for this.      SharedPtr<Thread> currently_handling; +    /// Returns true if the session has been converted to a domain, otherwise False +    bool IsDomain() const { +        return !domain_request_handlers.empty(); +    } + +    /// Converts the session to a domain at the end of the current command +    void ConvertToDomain() { +        convert_to_domain = true; +    } +  private:      ServerSession();      ~ServerSession() override; @@ -102,6 +115,9 @@ private:       * @return The created server session       */      static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown"); + +    /// When set to True, converts the session to a domain at the end of the command +    bool convert_to_domain{};  };  /** diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 516309036..4c0276cf0 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -20,7 +20,6 @@  #include "core/hle/kernel/shared_memory.h"  #include "core/hle/kernel/svc.h"  #include "core/hle/kernel/svc_wrap.h" -#include "core/hle/kernel/sync_object.h"  #include "core/hle/kernel/thread.h"  #include "core/hle/lock.h"  #include "core/hle/result.h" @@ -87,7 +86,7 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address  /// Makes a blocking IPC call to an OS service.  static ResultCode SendSyncRequest(Handle handle) { -    SharedPtr<SyncObject> session = g_handle_table.Get<SyncObject>(handle); +    SharedPtr<ClientSession> session = g_handle_table.Get<ClientSession>(handle);      if (!session) {          LOG_ERROR(Kernel_SVC, "called with invalid handle=0x%08X", handle);          return ERR_INVALID_HANDLE; diff --git a/src/core/hle/kernel/sync_object.h b/src/core/hle/kernel/sync_object.h deleted file mode 100644 index f2befa2ea..000000000 --- a/src/core/hle/kernel/sync_object.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <boost/smart_ptr/intrusive_ptr.hpp> -#include "core/hle/kernel/kernel.h" -#include "core/hle/result.h" - -namespace Kernel { - -class Thread; - -/// Class that represents a Kernel object that svcSendSyncRequest can be called on -class SyncObject : public Object { -public: -    /** -     * Handle a sync request from the emulated application. -     * @param thread Thread that initiated the request. -     * @returns ResultCode from the operation. -     */ -    virtual ResultCode SendSyncRequest(SharedPtr<Thread> thread) = 0; -}; - -// Specialization of DynamicObjectCast for SyncObjects -template <> -inline SharedPtr<SyncObject> DynamicObjectCast<SyncObject>(SharedPtr<Object> object) { -    if (object != nullptr && object->IsSyncable()) { -        return boost::static_pointer_cast<SyncObject>(std::move(object)); -    } -    return nullptr; -} - -} // namespace Kernel diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 10ddc4feb..656e1b4a7 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -19,6 +19,8 @@  enum class ErrorDescription : u32 {      Success = 0,      RemoteProcessDead = 301, +    InvalidOffset = 6061, +    InvalidLength = 6062,  };  /** diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp index 7f0192fd3..67f05aad4 100644 --- a/src/core/hle/service/acc/acc_u0.cpp +++ b/src/core/hle/service/acc/acc_u0.cpp @@ -22,7 +22,7 @@ private:      void GetBase(Kernel::HLERequestContext& ctx) {          LOG_WARNING(Service, "(STUBBED) called");          ProfileBase profile_base{}; -        IPC::RequestBuilder rb{ctx, 16}; +        IPC::ResponseBuilder rb{ctx, 16};          rb.Push(RESULT_SUCCESS);          rb.PushRaw(profile_base);      } @@ -40,7 +40,7 @@ public:  private:      void CheckAvailability(Kernel::HLERequestContext& ctx) {          LOG_WARNING(Service, "(STUBBED) called"); -        IPC::RequestBuilder rb{ctx, 3}; +        IPC::ResponseBuilder rb{ctx, 3};          rb.Push(RESULT_SUCCESS);          rb.Push(true); // TODO: Check when this is supposed to return true and when not      } @@ -48,13 +48,13 @@ private:  void ACC_U0::GetUserExistence(Kernel::HLERequestContext& ctx) {      LOG_WARNING(Service, "(STUBBED) called"); -    IPC::RequestBuilder rb{ctx, 3}; +    IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS);      rb.Push(true); // TODO: Check when this is supposed to return true and when not  }  void ACC_U0::GetProfile(Kernel::HLERequestContext& ctx) { -    IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +    IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS);      rb.PushIpcInterface<IProfile>();      LOG_DEBUG(Service, "called"); @@ -62,12 +62,12 @@ void ACC_U0::GetProfile(Kernel::HLERequestContext& ctx) {  void ACC_U0::InitializeApplicationInfo(Kernel::HLERequestContext& ctx) {      LOG_WARNING(Service, "(STUBBED) called"); -    IPC::RequestBuilder rb{ctx, 2}; +    IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS);  }  void ACC_U0::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) { -    IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +    IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS);      rb.PushIpcInterface<IManagerForApplication>();      LOG_DEBUG(Service, "called"); diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index a761bea65..b6896852e 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -8,8 +8,9 @@  namespace Service {  namespace AM { -void InstallInterfaces(SM::ServiceManager& service_manager) { -    std::make_shared<AppletOE>()->InstallAsService(service_manager); +void InstallInterfaces(SM::ServiceManager& service_manager, +                       std::shared_ptr<NVFlinger::NVFlinger> nvflinger) { +    std::make_shared<AppletOE>(nvflinger)->InstallAsService(service_manager);  }  } // namespace AM diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 63d86cd41..3b8a06c1d 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -4,13 +4,19 @@  #pragma once +#include <memory>  #include "core/hle/service/service.h"  namespace Service { +namespace NVFlinger { +class NVFlinger; +} +  namespace AM {  /// Registers all AM services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); +void InstallInterfaces(SM::ServiceManager& service_manager, +                       std::shared_ptr<NVFlinger::NVFlinger> nvflinger);  } // namespace AM  } // namespace Service diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index b4a6ad232..15b7701e0 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp @@ -7,6 +7,7 @@  #include "core/hle/kernel/event.h"  #include "core/hle/service/am/applet_oe.h"  #include "core/hle/service/apm/apm.h" +#include "core/hle/service/nvflinger/nvflinger.h"  namespace Service {  namespace AM { @@ -24,14 +25,14 @@ public:  private:      void GetAppletResourceUserId(Kernel::HLERequestContext& ctx) {          LOG_WARNING(Service, "(STUBBED) called"); -        IPC::RequestBuilder rb{ctx, 4}; +        IPC::ResponseBuilder rb{ctx, 4};          rb.Push(RESULT_SUCCESS);          rb.Push<u64>(0);      }      void AcquireForegroundRights(Kernel::HLERequestContext& ctx) {          LOG_WARNING(Service, "(STUBBED) called"); -        IPC::RequestBuilder rb{ctx, 2}; +        IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);      }  }; @@ -53,7 +54,8 @@ public:  class ISelfController final : public ServiceFramework<ISelfController> {  public: -    ISelfController() : ServiceFramework("ISelfController") { +    ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) +        : ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger)) {          static const FunctionInfo functions[] = {              {1, &ISelfController::LockExit, "LockExit"},              {2, &ISelfController::UnlockExit, "UnlockExit"}, @@ -65,6 +67,7 @@ public:              {14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"},              {16, &ISelfController::SetOutOfFocusSuspendingEnabled,               "SetOutOfFocusSuspendingEnabled"}, +            {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},          };          RegisterHandlers(functions);      } @@ -83,14 +86,14 @@ private:          };          auto flags = rp.PopRaw<FocusHandlingModeParams>(); -        IPC::RequestBuilder rb{ctx, 2}; +        IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);          LOG_WARNING(Service, "(STUBBED) called");      }      void SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 2}; +        IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);          LOG_WARNING(Service, "(STUBBED) called"); @@ -101,7 +104,7 @@ private:          bool flag = rp.Pop<bool>(); -        IPC::RequestBuilder rb{ctx, 2}; +        IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);          LOG_WARNING(Service, "(STUBBED) called flag=%u", static_cast<u32>(flag)); @@ -112,7 +115,7 @@ private:          bool flag = rp.Pop<bool>(); -        IPC::RequestBuilder rb{ctx, 2}; +        IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);          LOG_WARNING(Service, "(STUBBED) called flag=%u", static_cast<u32>(flag)); @@ -125,25 +128,40 @@ private:          bool enabled = rp.Pop<bool>(); -        IPC::RequestBuilder rb{ctx, 2}; +        IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);          LOG_WARNING(Service, "(STUBBED) called enabled=%u", static_cast<u32>(enabled));      }      void LockExit(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 2}; +        IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);          LOG_WARNING(Service, "(STUBBED) called");      }      void UnlockExit(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 2}; +        IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);          LOG_WARNING(Service, "(STUBBED) called");      } + +    void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) { +        // TODO(Subv): Find out how AM determines the display to use, for now just create the layer +        // in the Default display. +        u64 display_id = nvflinger->OpenDisplay("Default"); +        u64 layer_id = nvflinger->CreateLayer(display_id); + +        IPC::ResponseBuilder rb{ctx, 4}; +        rb.Push(RESULT_SUCCESS); +        rb.Push(layer_id); + +        LOG_WARNING(Service, "(STUBBED) called"); +    } + +    std::shared_ptr<NVFlinger::NVFlinger> nvflinger;  };  class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { @@ -175,7 +193,7 @@ private:      void GetEventHandle(Kernel::HLERequestContext& ctx) {          event->Signal(); -        IPC::RequestBuilder rb{ctx, 2, 1}; +        IPC::ResponseBuilder rb{ctx, 2, 1};          rb.Push(RESULT_SUCCESS);          rb.PushCopyObjects(event); @@ -183,7 +201,7 @@ private:      }      void ReceiveMessage(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 3}; +        IPC::ResponseBuilder rb{ctx, 3};          rb.Push(RESULT_SUCCESS);          rb.Push<u32>(15); @@ -191,7 +209,7 @@ private:      }      void GetCurrentFocusState(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 3}; +        IPC::ResponseBuilder rb{ctx, 3};          rb.Push(RESULT_SUCCESS);          rb.Push(static_cast<u8>(FocusState::InFocus)); @@ -199,7 +217,7 @@ private:      }      void GetOperationMode(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 3}; +        IPC::ResponseBuilder rb{ctx, 3};          rb.Push(RESULT_SUCCESS);          rb.Push(static_cast<u8>(OperationMode::Handheld)); @@ -207,7 +225,7 @@ private:      }      void GetPerformanceMode(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 3}; +        IPC::ResponseBuilder rb{ctx, 3};          rb.Push(RESULT_SUCCESS);          rb.Push(static_cast<u32>(APM::PerformanceMode::Handheld)); @@ -232,7 +250,7 @@ private:      std::vector<u8> buffer;      void GetSize(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 4}; +        IPC::ResponseBuilder rb{ctx, 4};          rb.Push(RESULT_SUCCESS);          rb.Push(static_cast<u64>(buffer.size())); @@ -251,7 +269,7 @@ private:          Memory::WriteBlock(output_buffer.Address(), buffer.data() + offset, output_buffer.Size()); -        IPC::RequestBuilder rb{ctx, 2}; +        IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS); @@ -273,7 +291,7 @@ private:      std::vector<u8> buffer;      void Open(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +        IPC::ResponseBuilder rb{ctx, 2, 0, 1};          rb.Push(RESULT_SUCCESS);          rb.PushIpcInterface<AM::IStorageAccessor>(buffer); @@ -310,7 +328,7 @@ private:          std::vector<u8> buffer(data, data + sizeof(data)); -        IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +        IPC::ResponseBuilder rb{ctx, 2, 0, 1};          rb.Push(RESULT_SUCCESS);          rb.PushIpcInterface<AM::IStorage>(buffer); @@ -325,34 +343,34 @@ private:          IPC::RequestParser rp{ctx};          u32 result = rp.Pop<u32>(); -        IPC::RequestBuilder rb{ctx, 2}; +        IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);          LOG_WARNING(Service, "(STUBBED) called, result=0x%08X", result);      }      void GetDesiredLanguage(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 4}; +        IPC::ResponseBuilder rb{ctx, 4};          rb.Push(RESULT_SUCCESS);          rb.Push<u64>(SystemLanguage::English);          LOG_WARNING(Service, "(STUBBED) called");      }      void InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 2}; +        IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);          LOG_WARNING(Service, "(STUBBED) called");      }      void SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 2}; +        IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);          LOG_WARNING(Service, "(STUBBED) called");      }      void NotifyRunning(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 3}; +        IPC::ResponseBuilder rb{ctx, 3};          rb.Push(RESULT_SUCCESS);          rb.Push<u8>(0); // Unknown, seems to be ignored by official processes @@ -367,7 +385,8 @@ public:  class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {  public: -    IApplicationProxy() : ServiceFramework("IApplicationProxy") { +    IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) +        : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)) {          static const FunctionInfo functions[] = {              {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},              {1, &IApplicationProxy::GetSelfController, "GetSelfController"}, @@ -383,70 +402,73 @@ public:  private:      void GetAudioController(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +        IPC::ResponseBuilder rb{ctx, 2, 0, 1};          rb.Push(RESULT_SUCCESS);          rb.PushIpcInterface<IAudioController>();          LOG_DEBUG(Service, "called");      }      void GetDisplayController(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +        IPC::ResponseBuilder rb{ctx, 2, 0, 1};          rb.Push(RESULT_SUCCESS);          rb.PushIpcInterface<IDisplayController>();          LOG_DEBUG(Service, "called");      }      void GetDebugFunctions(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +        IPC::ResponseBuilder rb{ctx, 2, 0, 1};          rb.Push(RESULT_SUCCESS);          rb.PushIpcInterface<IDebugFunctions>();          LOG_DEBUG(Service, "called");      }      void GetWindowController(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +        IPC::ResponseBuilder rb{ctx, 2, 0, 1};          rb.Push(RESULT_SUCCESS);          rb.PushIpcInterface<IWindowController>();          LOG_DEBUG(Service, "called");      }      void GetSelfController(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +        IPC::ResponseBuilder rb{ctx, 2, 0, 1};          rb.Push(RESULT_SUCCESS); -        rb.PushIpcInterface<ISelfController>(); +        rb.PushIpcInterface<ISelfController>(nvflinger);          LOG_DEBUG(Service, "called");      }      void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +        IPC::ResponseBuilder rb{ctx, 2, 0, 1};          rb.Push(RESULT_SUCCESS);          rb.PushIpcInterface<ICommonStateGetter>();          LOG_DEBUG(Service, "called");      }      void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +        IPC::ResponseBuilder rb{ctx, 2, 0, 1};          rb.Push(RESULT_SUCCESS);          rb.PushIpcInterface<ILibraryAppletCreator>();          LOG_DEBUG(Service, "called");      }      void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +        IPC::ResponseBuilder rb{ctx, 2, 0, 1};          rb.Push(RESULT_SUCCESS);          rb.PushIpcInterface<IApplicationFunctions>();          LOG_DEBUG(Service, "called");      } + +    std::shared_ptr<NVFlinger::NVFlinger> nvflinger;  };  void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { -    IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +    IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS); -    rb.PushIpcInterface<IApplicationProxy>(); +    rb.PushIpcInterface<IApplicationProxy>(nvflinger);      LOG_DEBUG(Service, "called");  } -AppletOE::AppletOE() : ServiceFramework("appletOE") { +AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) +    : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)) {      static const FunctionInfo functions[] = {          {0x00000000, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},      }; diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h index 6ee5b0e9f..8083135c3 100644 --- a/src/core/hle/service/am/applet_oe.h +++ b/src/core/hle/service/am/applet_oe.h @@ -4,10 +4,15 @@  #pragma once +#include <memory>  #include "core/hle/kernel/hle_ipc.h"  #include "core/hle/service/service.h"  namespace Service { +namespace NVFlinger { +class NVFlinger; +} +  namespace AM {  // TODO: Add more languages @@ -18,11 +23,13 @@ enum SystemLanguage {  class AppletOE final : public ServiceFramework<AppletOE> {  public: -    AppletOE(); +    AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);      ~AppletOE() = default;  private:      void OpenApplicationProxy(Kernel::HLERequestContext& ctx); + +    std::shared_ptr<NVFlinger::NVFlinger> nvflinger;  };  } // namespace AM diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp index bf7e12288..c4b1723c5 100644 --- a/src/core/hle/service/apm/apm.cpp +++ b/src/core/hle/service/apm/apm.cpp @@ -30,7 +30,7 @@ private:          auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());          u32 config = rp.Pop<u32>(); -        IPC::RequestBuilder rb{ctx, 2}; +        IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);          LOG_WARNING(Service, "(STUBBED) called mode=%u config=%u", static_cast<u32>(mode), config); @@ -41,7 +41,7 @@ private:          auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); -        IPC::RequestBuilder rb{ctx, 3}; +        IPC::ResponseBuilder rb{ctx, 3};          rb.Push(RESULT_SUCCESS);          rb.Push<u32>(0); // Performance configuration @@ -58,7 +58,7 @@ APM::APM() : ServiceFramework("apm") {  }  void APM::OpenSession(Kernel::HLERequestContext& ctx) { -    IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +    IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS);      rb.PushIpcInterface<ISession>();  } diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp new file mode 100644 index 000000000..ee749fddd --- /dev/null +++ b/src/core/hle/service/audio/audin_u.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 "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/service/audio/audin_u.h" + +namespace Service { +namespace Audio { + +class IAudioIn final : public ServiceFramework<IAudioIn> { +public: +    IAudioIn() : ServiceFramework("IAudioIn") { +        static const FunctionInfo functions[] = { +            {0x0, nullptr, "GetAudioInState"}, +            {0x1, nullptr, "StartAudioIn"}, +            {0x2, nullptr, "StopAudioIn"}, +            {0x3, nullptr, "AppendAudioInBuffer_1"}, +            {0x4, nullptr, "RegisterBufferEvent"}, +            {0x5, nullptr, "GetReleasedAudioInBuffer_1"}, +            {0x6, nullptr, "ContainsAudioInBuffer"}, +            {0x7, nullptr, "AppendAudioInBuffer_2"}, +            {0x8, nullptr, "GetReleasedAudioInBuffer_2"}, +        }; +        RegisterHandlers(functions); +    } +    ~IAudioIn() = default; +}; + +AudInU::AudInU() : ServiceFramework("audin:u") { +    static const FunctionInfo functions[] = { +        {0x00000000, nullptr, "ListAudioIns"}, +        {0x00000001, nullptr, "OpenAudioIn"}, +    }; +    RegisterHandlers(functions); +} + +} // namespace Audio +} // namespace Service diff --git a/src/core/hle/service/audio/audin_u.h b/src/core/hle/service/audio/audin_u.h new file mode 100644 index 000000000..2b8576756 --- /dev/null +++ b/src/core/hle/service/audio/audin_u.h @@ -0,0 +1,23 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service { +namespace Audio { + +class AudInU final : public ServiceFramework<AudInU> { +public: +    explicit AudInU(); +    ~AudInU() = default; +}; + +} // namespace Audio +} // namespace Service diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp index 2b4c6c5d0..3f7fb44eb 100644 --- a/src/core/hle/service/audio/audio.cpp +++ b/src/core/hle/service/audio/audio.cpp @@ -2,14 +2,22 @@  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. +#include "core/hle/service/audio/audin_u.h"  #include "core/hle/service/audio/audio.h"  #include "core/hle/service/audio/audout_u.h" +#include "core/hle/service/audio/audrec_u.h" +#include "core/hle/service/audio/audren_u.h" +#include "core/hle/service/audio/codecctl.h"  namespace Service {  namespace Audio {  void InstallInterfaces(SM::ServiceManager& service_manager) {      std::make_shared<AudOutU>()->InstallAsService(service_manager); +    std::make_shared<AudInU>()->InstallAsService(service_manager); +    std::make_shared<AudRecU>()->InstallAsService(service_manager); +    std::make_shared<AudRenU>()->InstallAsService(service_manager); +    std::make_shared<CodecCtl>()->InstallAsService(service_manager);  }  } // namespace Audio diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index c028262c6..f56ba2ea1 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -2,23 +2,197 @@  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. +#include <vector>  #include "common/logging/log.h" +#include "core/core_timing.h"  #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/hle_ipc.h"  #include "core/hle/service/audio/audout_u.h"  namespace Service {  namespace Audio { +/// Switch sample rate frequency +constexpr u32 sample_rate{48000}; +/// TODO(st4rk): dynamic number of channels, as I think Switch has support +/// to more audio channels (probably when Docked I guess) +constexpr u32 audio_channels{2}; +/// TODO(st4rk): find a proper value for the audio_ticks +constexpr u64 audio_ticks{static_cast<u64>(BASE_CLOCK_RATE / 500)}; + +class IAudioOut final : public ServiceFramework<IAudioOut> { +public: +    IAudioOut() : ServiceFramework("IAudioOut"), audio_out_state(AudioState::Stopped) { +        static const FunctionInfo functions[] = { +            {0x0, nullptr, "GetAudioOutState"}, +            {0x1, &IAudioOut::StartAudioOut, "StartAudioOut"}, +            {0x2, &IAudioOut::StopAudioOut, "StopAudioOut"}, +            {0x3, &IAudioOut::AppendAudioOutBuffer_1, "AppendAudioOutBuffer_1"}, +            {0x4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"}, +            {0x5, &IAudioOut::GetReleasedAudioOutBuffer_1, "GetReleasedAudioOutBuffer_1"}, +            {0x6, nullptr, "ContainsAudioOutBuffer"}, +            {0x7, nullptr, "AppendAudioOutBuffer_2"}, +            {0x8, nullptr, "GetReleasedAudioOutBuffer_2"}, +        }; +        RegisterHandlers(functions); + +        // This is the event handle used to check if the audio buffer was released +        buffer_event = +            Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioOutBufferReleasedEvent"); + +        // Register event callback to update the Audio Buffer +        audio_event = CoreTiming::RegisterEvent( +            "IAudioOut::UpdateAudioBuffersCallback", [this](u64 userdata, int cycles_late) { +                UpdateAudioBuffersCallback(); +                CoreTiming::ScheduleEvent(audio_ticks - cycles_late, audio_event); +            }); + +        // Start the audio event +        CoreTiming::ScheduleEvent(audio_ticks, audio_event); +    } + +    ~IAudioOut() = default; + +private: +    void StartAudioOut(Kernel::HLERequestContext& ctx) { +        LOG_WARNING(Service_Audio, "(STUBBED) called"); + +        // Start audio +        audio_out_state = AudioState::Started; + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } + +    void StopAudioOut(Kernel::HLERequestContext& ctx) { +        LOG_WARNING(Service_Audio, "(STUBBED) called"); + +        // Stop audio +        audio_out_state = AudioState::Stopped; + +        queue_keys.clear(); + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } + +    void RegisterBufferEvent(Kernel::HLERequestContext& ctx) { +        LOG_WARNING(Service_Audio, "(STUBBED) called"); + +        IPC::ResponseBuilder rb{ctx, 2, 1}; +        rb.Push(RESULT_SUCCESS); +        rb.PushCopyObjects(buffer_event); +    } + +    void AppendAudioOutBuffer_1(Kernel::HLERequestContext& ctx) { +        LOG_WARNING(Service_Audio, "(STUBBED) called"); +        IPC::RequestParser rp{ctx}; + +        const u64 key{rp.Pop<u64>()}; +        queue_keys.insert(queue_keys.begin(), key); + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } + +    void GetReleasedAudioOutBuffer_1(Kernel::HLERequestContext& ctx) { +        LOG_WARNING(Service_Audio, "(STUBBED) called"); + +        const auto& buffer = ctx.BufferDescriptorB()[0]; + +        // TODO(st4rk): This is how libtransistor currently implements the +        // GetReleasedAudioOutBuffer, it should return the key (a VAddr) to the app and this address +        // is used to know which buffer should be filled with data and send again to the service +        // through AppendAudioOutBuffer. Check if this is the proper way to do it. +        u64 key{0}; + +        if (queue_keys.size()) { +            key = queue_keys.back(); +            queue_keys.pop_back(); +        } + +        Memory::WriteBlock(buffer.Address(), &key, sizeof(u64)); + +        IPC::ResponseBuilder rb{ctx, 3}; +        rb.Push(RESULT_SUCCESS); +        // TODO(st4rk): This might be the total of released buffers, needs to be verified on +        // hardware +        rb.Push<u32>(static_cast<u32>(queue_keys.size())); +    } + +    void UpdateAudioBuffersCallback() { +        if (audio_out_state != AudioState::Started) { +            return; +        } + +        if (queue_keys.empty()) { +            return; +        } + +        buffer_event->Signal(); +    } + +    enum class AudioState : u32 { +        Started, +        Stopped, +    }; + +    /// This is used to trigger the audio event callback that is going to read the samples from the +    /// audio_buffer list and enqueue the samples using the sink (audio_core). +    CoreTiming::EventType* audio_event; + +    /// This is the evend handle used to check if the audio buffer was released +    Kernel::SharedPtr<Kernel::Event> buffer_event; + +    /// (st4rk): This is just a temporary workaround for the future implementation. Libtransistor +    /// uses the key as an address in the App, so we need to return when the +    /// GetReleasedAudioOutBuffer_1 is called, otherwise we'll run in problems, because +    /// libtransistor uses the key returned as an pointer. +    std::vector<u64> queue_keys; + +    AudioState audio_out_state; +}; +  void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) { -    LOG_WARNING(Service, "(STUBBED) called"); -    IPC::RequestBuilder rb{ctx, 2}; +    LOG_WARNING(Service_Audio, "(STUBBED) called"); +    IPC::RequestParser rp{ctx}; + +    auto& buffer = ctx.BufferDescriptorB()[0]; +    const std::string audio_interface = "AudioInterface"; + +    Memory::WriteBlock(buffer.Address(), &audio_interface[0], audio_interface.size()); + +    IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0); + +    rb.Push(RESULT_SUCCESS); +    // TODO(st4rk): We're currently returning only one audio interface (stringlist size). However, +    // it's highly possible to have more than one interface (despite that libtransistor requires +    // only one). +    rb.Push<u32>(1); +} + +void AudOutU::OpenAudioOut(Kernel::HLERequestContext& ctx) { +    LOG_WARNING(Service_Audio, "(STUBBED) called"); + +    if (!audio_out_interface) { +        audio_out_interface = std::make_shared<IAudioOut>(); +    } + +    IPC::ResponseBuilder rb{ctx, 6, 0, 1};      rb.Push(RESULT_SUCCESS); +    rb.Push<u32>(sample_rate); +    rb.Push<u32>(audio_channels); +    rb.Push<u32>(static_cast<u32>(PcmFormat::Int16)); +    rb.Push<u32>(0); // This field is unknown +    rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface);  }  AudOutU::AudOutU() : ServiceFramework("audout:u") { -    static const FunctionInfo functions[] = { -        {0x00000000, &AudOutU::ListAudioOuts, "ListAudioOuts"}, -    }; +    static const FunctionInfo functions[] = {{0x00000000, &AudOutU::ListAudioOuts, "ListAudioOuts"}, +                                             {0x00000001, &AudOutU::OpenAudioOut, "OpenAudioOut"}, +                                             {0x00000002, nullptr, "Unknown2"}, +                                             {0x00000003, nullptr, "Unknown3"}};      RegisterHandlers(functions);  } diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h index 42680af94..7fbce2225 100644 --- a/src/core/hle/service/audio/audout_u.h +++ b/src/core/hle/service/audio/audout_u.h @@ -4,19 +4,37 @@  #pragma once -#include "core/hle/kernel/hle_ipc.h"  #include "core/hle/service/service.h" +namespace Kernel { +class HLERequestContext; +} +  namespace Service {  namespace Audio { +class IAudioOut; +  class AudOutU final : public ServiceFramework<AudOutU> {  public:      AudOutU();      ~AudOutU() = default;  private: +    std::shared_ptr<IAudioOut> audio_out_interface; +      void ListAudioOuts(Kernel::HLERequestContext& ctx); +    void OpenAudioOut(Kernel::HLERequestContext& ctx); + +    enum class PcmFormat : u32 { +        Invalid = 0, +        Int8 = 1, +        Int16 = 2, +        Int24 = 3, +        Int32 = 4, +        PcmFloat = 5, +        Adpcm = 6, +    };  };  } // namespace Audio diff --git a/src/core/hle/service/audio/audrec_u.cpp b/src/core/hle/service/audio/audrec_u.cpp new file mode 100644 index 000000000..f2626ec70 --- /dev/null +++ b/src/core/hle/service/audio/audrec_u.cpp @@ -0,0 +1,38 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/service/audio/audrec_u.h" + +namespace Service { +namespace Audio { + +class IFinalOutputRecorder final : public ServiceFramework<IFinalOutputRecorder> { +public: +    IFinalOutputRecorder() : ServiceFramework("IFinalOutputRecorder") { +        static const FunctionInfo functions[] = { +            {0x0, nullptr, "GetFinalOutputRecorderState"}, +            {0x1, nullptr, "StartFinalOutputRecorder"}, +            {0x2, nullptr, "StopFinalOutputRecorder"}, +            {0x3, nullptr, "AppendFinalOutputRecorderBuffer"}, +            {0x4, nullptr, "RegisterBufferEvent"}, +            {0x5, nullptr, "GetReleasedFinalOutputRecorderBuffer"}, +            {0x6, nullptr, "ContainsFinalOutputRecorderBuffer"}, +        }; +        RegisterHandlers(functions); +    } +    ~IFinalOutputRecorder() = default; +}; + +AudRecU::AudRecU() : ServiceFramework("audrec:u") { +    static const FunctionInfo functions[] = { +        {0x00000000, nullptr, "OpenFinalOutputRecorder"}, +    }; +    RegisterHandlers(functions); +} + +} // namespace Audio +} // namespace Service diff --git a/src/core/hle/service/audio/audrec_u.h b/src/core/hle/service/audio/audrec_u.h new file mode 100644 index 000000000..c31e412c1 --- /dev/null +++ b/src/core/hle/service/audio/audrec_u.h @@ -0,0 +1,23 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service { +namespace Audio { + +class AudRecU final : public ServiceFramework<AudRecU> { +public: +    explicit AudRecU(); +    ~AudRecU() = default; +}; + +} // namespace Audio +} // namespace Service diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp new file mode 100644 index 000000000..4bafdfac3 --- /dev/null +++ b/src/core/hle/service/audio/audren_u.cpp @@ -0,0 +1,44 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/service/audio/audren_u.h" + +namespace Service { +namespace Audio { + +class IAudioRenderer final : public ServiceFramework<IAudioRenderer> { +public: +    IAudioRenderer() : ServiceFramework("IAudioRenderer") { +        static const FunctionInfo functions[] = { +            {0x0, nullptr, "GetAudioRendererSampleRate"}, +            {0x1, nullptr, "GetAudioRendererSampleCount"}, +            {0x2, nullptr, "GetAudioRendererMixBufferCount"}, +            {0x3, nullptr, "GetAudioRendererState"}, +            {0x4, nullptr, "RequestUpdateAudioRenderer"}, +            {0x5, nullptr, "StartAudioRenderer"}, +            {0x6, nullptr, "StopAudioRenderer"}, +            {0x7, nullptr, "QuerySystemEvent"}, +            {0x8, nullptr, "SetAudioRendererRenderingTimeLimit"}, +            {0x9, nullptr, "GetAudioRendererRenderingTimeLimit"}, +        }; +        RegisterHandlers(functions); +    } +    ~IAudioRenderer() = default; +}; + +AudRenU::AudRenU() : ServiceFramework("audren:u") { +    static const FunctionInfo functions[] = { +        {0x00000000, nullptr, "OpenAudioRenderer"}, +        {0x00000001, nullptr, "GetAudioRendererWorkBufferSize"}, +        {0x00000002, nullptr, "GetAudioRenderersProcessMasterVolume"}, +        {0x00000003, nullptr, "SetAudioRenderersProcessMasterVolume"}, +    }; +    RegisterHandlers(functions); +} + +} // namespace Audio +} // namespace Service diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h new file mode 100644 index 000000000..1d9264c72 --- /dev/null +++ b/src/core/hle/service/audio/audren_u.h @@ -0,0 +1,23 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service { +namespace Audio { + +class AudRenU final : public ServiceFramework<AudRenU> { +public: +    explicit AudRenU(); +    ~AudRenU() = default; +}; + +} // namespace Audio +} // namespace Service diff --git a/src/core/hle/service/audio/codecctl.cpp b/src/core/hle/service/audio/codecctl.cpp new file mode 100644 index 000000000..d2a7f4cd0 --- /dev/null +++ b/src/core/hle/service/audio/codecctl.cpp @@ -0,0 +1,33 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/service/audio/codecctl.h" + +namespace Service { +namespace Audio { + +CodecCtl::CodecCtl() : ServiceFramework("codecctl") { +    static const FunctionInfo functions[] = { +        {0x00000000, nullptr, "InitializeCodecController"}, +        {0x00000001, nullptr, "FinalizeCodecController"}, +        {0x00000002, nullptr, "SleepCodecController"}, +        {0x00000003, nullptr, "WakeCodecController"}, +        {0x00000004, nullptr, "SetCodecVolume"}, +        {0x00000005, nullptr, "GetCodecVolumeMax"}, +        {0x00000006, nullptr, "GetCodecVolumeMin"}, +        {0x00000007, nullptr, "SetCodecActiveTarget"}, +        {0x00000008, nullptr, "Unknown"}, +        {0x00000009, nullptr, "BindCodecHeadphoneMicJackInterrupt"}, +        {0x0000000A, nullptr, "IsCodecHeadphoneMicJackInserted"}, +        {0x0000000B, nullptr, "ClearCodecHeadphoneMicJackInterrupt"}, +        {0x0000000C, nullptr, "IsCodecDeviceRequested"}, +    }; +    RegisterHandlers(functions); +} + +} // namespace Audio +} // namespace Service diff --git a/src/core/hle/service/audio/codecctl.h b/src/core/hle/service/audio/codecctl.h new file mode 100644 index 000000000..1121ab0b1 --- /dev/null +++ b/src/core/hle/service/audio/codecctl.h @@ -0,0 +1,23 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service { +namespace Audio { + +class CodecCtl final : public ServiceFramework<CodecCtl> { +public: +    explicit CodecCtl(); +    ~CodecCtl() = default; +}; + +} // namespace Audio +} // namespace Service diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp new file mode 100644 index 000000000..4b47548fd --- /dev/null +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -0,0 +1,54 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <boost/container/flat_map.hpp> +#include "core/file_sys/filesystem.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/filesystem/fsp_srv.h" + +namespace Service { +namespace FileSystem { + +/** + * Map of registered file systems, identified by type. Once an file system is registered here, it + * is never removed until UnregisterFileSystems is called. + */ +static boost::container::flat_map<Type, std::unique_ptr<FileSys::FileSystemFactory>> filesystem_map; + +ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& factory, Type type) { +    auto result = filesystem_map.emplace(type, std::move(factory)); + +    bool inserted = result.second; +    ASSERT_MSG(inserted, "Tried to register more than one system with same id code"); + +    auto& filesystem = result.first->second; +    LOG_DEBUG(Service_FS, "Registered file system %s with id code 0x%08X", +              filesystem->GetName().c_str(), static_cast<u32>(type)); +    return RESULT_SUCCESS; +} + +ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type, +                                                                      FileSys::Path& path) { +    LOG_TRACE(Service_FS, "Opening FileSystem with type=%d", type); + +    auto itr = filesystem_map.find(type); +    if (itr == filesystem_map.end()) { +        // TODO(bunnei): Find a better error code for this +        return ResultCode(-1); +    } + +    return itr->second->Open(path); +} + +void UnregisterFileSystems() { +    filesystem_map.clear(); +} + +void InstallInterfaces(SM::ServiceManager& service_manager) { +    UnregisterFileSystems(); +    std::make_shared<FSP_SRV>()->InstallAsService(service_manager); +} + +} // namespace FileSystem +} // namespace Service diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h new file mode 100644 index 000000000..a674c9493 --- /dev/null +++ b/src/core/hle/service/filesystem/filesystem.h @@ -0,0 +1,50 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include "common/common_types.h" +#include "core/hle/result.h" + +namespace FileSys { +class FileSystemBackend; +class FileSystemFactory; +class Path; +} // namespace FileSys + +namespace Service { + +namespace SM { +class ServiceManager; +} // namespace SM + +namespace FileSystem { + +/// Supported FileSystem types +enum class Type { +    RomFS = 1, +}; + +/** + * Registers a FileSystem, instances of which can later be opened using its IdCode. + * @param factory FileSystem backend interface to use + * @param type Type used to access this type of FileSystem + */ +ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& factory, Type type); + +/** + * Opens a file system + * @param type Type of the file system to open + * @param path Path to the file system, used with Binary paths + * @return FileSys::FileSystemBackend interface to the file system + */ +ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type, +                                                                      FileSys::Path& path); + +/// Registers all Filesystem services with the specified service manager. +void InstallInterfaces(SM::ServiceManager& service_manager); + +} // namespace FileSystem +} // namespace Service diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp new file mode 100644 index 000000000..71b82393e --- /dev/null +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -0,0 +1,138 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/core.h" +#include "core/file_sys/filesystem.h" +#include "core/file_sys/storage.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/client_session.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/filesystem/fsp_srv.h" + +namespace Service { +namespace FileSystem { + +class IStorage final : public ServiceFramework<IStorage> { +public: +    IStorage(std::unique_ptr<FileSys::StorageBackend>&& backend) +        : ServiceFramework("IStorage"), backend(std::move(backend)) { +        static const FunctionInfo functions[] = { +            {0, &IStorage::Read, "Read"}, {1, nullptr, "Write"},   {2, nullptr, "Flush"}, +            {3, nullptr, "SetSize"},      {4, nullptr, "GetSize"}, +        }; +        RegisterHandlers(functions); +    } + +private: +    std::unique_ptr<FileSys::StorageBackend> backend; + +    void Read(Kernel::HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        const s64 offset = rp.Pop<s64>(); +        const s64 length = rp.Pop<s64>(); +        const auto& descriptor = ctx.BufferDescriptorB()[0]; + +        LOG_DEBUG(Service_FS, "called, offset=0x%llx, length=0x%llx", offset, length); + +        // Error checking +        ASSERT_MSG(length == descriptor.Size(), "unexpected size difference"); +        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<u8> output(length); +        ResultVal<size_t> 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 +        Memory::WriteBlock(descriptor.Address(), output.data(), descriptor.Size()); + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } +}; + +FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { +    static const FunctionInfo functions[] = { +        {1, &FSP_SRV::Initalize, "Initalize"}, +        {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"}, +        {203, &FSP_SRV::OpenRomStorage, "OpenRomStorage"}, +        {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"}, +    }; +    RegisterHandlers(functions); +} + +void FSP_SRV::TryLoadRomFS() { +    if (romfs) { +        return; +    } +    FileSys::Path unused; +    auto res = OpenFileSystem(Type::RomFS, unused); +    if (res.Succeeded()) { +        romfs = std::move(res.Unwrap()); +    } +} + +void FSP_SRV::Initalize(Kernel::HLERequestContext& ctx) { +    LOG_WARNING(Service_FS, "(STUBBED) called"); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(RESULT_SUCCESS); +} + +void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { +    LOG_WARNING(Service_FS, "(STUBBED) called"); + +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(RESULT_SUCCESS); +    rb.Push<u32>(5); +} + +void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { +    LOG_DEBUG(Service_FS, "called"); + +    TryLoadRomFS(); +    if (!romfs) { +        // TODO (bunnei): Find the right error code to use here +        LOG_CRITICAL(Service_FS, "no file system interface available!"); +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(ResultCode(-1)); +        return; +    } + +    // Attempt to open a StorageBackend interface to the RomFS +    auto storage = romfs->OpenFile({}, {}); +    if (storage.Failed()) { +        LOG_CRITICAL(Service_FS, "no storage interface available!"); +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(storage.Code()); +        return; +    } + +    IPC::ResponseBuilder rb{ctx, 2, 0, 1}; +    rb.Push(RESULT_SUCCESS); +    rb.PushIpcInterface<IStorage>(std::move(storage.Unwrap())); +} + +void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) { +    LOG_WARNING(Service_FS, "(STUBBED) called, using OpenDataStorageByCurrentProcess"); +    OpenDataStorageByCurrentProcess(ctx); +} + +} // namespace FileSystem +} // namespace Service diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h new file mode 100644 index 000000000..15be8edc1 --- /dev/null +++ b/src/core/hle/service/filesystem/fsp_srv.h @@ -0,0 +1,34 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include "core/hle/service/service.h" + +namespace FileSys { +class FileSystemBackend; +} + +namespace Service { +namespace FileSystem { + +class FSP_SRV final : public ServiceFramework<FSP_SRV> { +public: +    explicit FSP_SRV(); +    ~FSP_SRV() = default; + +private: +    void TryLoadRomFS(); + +    void Initalize(Kernel::HLERequestContext& ctx); +    void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); +    void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); +    void OpenRomStorage(Kernel::HLERequestContext& ctx); + +    std::unique_ptr<FileSys::FileSystemBackend> romfs; +}; + +} // namespace FileSystem +} // namespace Service diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index be7a6ff65..326e0a4ab 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -46,7 +46,7 @@ public:  private:      void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { -        IPC::RequestBuilder rb{ctx, 2, 1}; +        IPC::ResponseBuilder rb{ctx, 2, 1};          rb.Push(RESULT_SUCCESS);          rb.PushCopyObjects(shared_mem);          LOG_DEBUG(Service, "called"); @@ -162,18 +162,17 @@ public:      ~Hid() = default;  private: +    std::shared_ptr<IAppletResource> applet_resource; +      void CreateAppletResource(Kernel::HLERequestContext& ctx) { -        auto client_port = std::make_shared<IAppletResource>()->CreatePort(); -        auto session = client_port->Connect(); -        if (session.Succeeded()) { -            LOG_DEBUG(Service, "called, initialized IAppletResource -> session=%u", -                      (*session)->GetObjectId()); -            IPC::RequestBuilder rb{ctx, 2, 0, 1}; -            rb.Push(RESULT_SUCCESS); -            rb.PushMoveObjects(std::move(session).Unwrap()); -        } else { -            UNIMPLEMENTED(); +        if (applet_resource == nullptr) { +            applet_resource = std::make_shared<IAppletResource>();          } + +        IPC::ResponseBuilder rb{ctx, 2, 0, 1}; +        rb.Push(RESULT_SUCCESS); +        rb.PushIpcInterface<IAppletResource>(applet_resource); +        LOG_DEBUG(Service, "called");      }  }; diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp index 13c9ee3d3..2843e0e40 100644 --- a/src/core/hle/service/lm/lm.cpp +++ b/src/core/hle/service/lm/lm.cpp @@ -65,7 +65,7 @@ private:       */      void Log(Kernel::HLERequestContext& ctx) {          // This function only succeeds - Get that out of the way -        IPC::RequestBuilder rb{ctx, 1}; +        IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);          // Read MessageHeader, despite not doing anything with it right now @@ -130,7 +130,7 @@ private:          }          output += message; -        LOG_DEBUG(Debug_Emulated, "%s", output.c_str()); +        LOG_INFO(Debug_Emulated, "%s", output.c_str());      }  }; @@ -146,20 +146,11 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {   *      0: ResultCode   */  void LM::Initialize(Kernel::HLERequestContext& ctx) { -    auto client_port = std::make_shared<Logger>()->CreatePort(); -    auto session = client_port->Connect(); -    if (session.Succeeded()) { -        LOG_DEBUG(Service_SM, "called, initialized logger -> session=%u", -                  (*session)->GetObjectId()); -        IPC::RequestBuilder rb{ctx, 2, 0, 1}; -        rb.Push(RESULT_SUCCESS); -        rb.PushMoveObjects(std::move(session).Unwrap()); -        registered_loggers.emplace_back(std::move(client_port)); -    } else { -        UNIMPLEMENTED(); -    } +    IPC::ResponseBuilder rb{ctx, 2, 0, 1}; +    rb.Push(RESULT_SUCCESS); +    rb.PushIpcInterface<Logger>(); -    LOG_INFO(Service_SM, "called"); +    LOG_DEBUG(Service, "called");  }  LM::LM() : ServiceFramework("lm") { diff --git a/src/core/hle/service/lm/lm.h b/src/core/hle/service/lm/lm.h index 4b954bdb2..371135057 100644 --- a/src/core/hle/service/lm/lm.h +++ b/src/core/hle/service/lm/lm.h @@ -5,7 +5,6 @@  #pragma once  #include <vector> -#include "core/hle/kernel/client_port.h"  #include "core/hle/kernel/kernel.h"  #include "core/hle/service/service.h" @@ -19,8 +18,6 @@ public:  private:      void Initialize(Kernel::HLERequestContext& ctx); - -    std::vector<Kernel::SharedPtr<Kernel::ClientPort>> registered_loggers;  };  /// Registers all LM services with the specified service manager. diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp new file mode 100644 index 000000000..2078f2187 --- /dev/null +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -0,0 +1,46 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/hle/service/nvdrv/devices/nvhost_ctrl.h" + +namespace Service { +namespace Nvidia { +namespace Devices { + +u32 nvhost_ctrl::ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) { +    LOG_DEBUG(Service_NVDRV, "called, command=0x%08x, input_size=0x%lx, output_size=0x%lx", command, +              input.size(), output.size()); + +    switch (command) { +    case IocGetConfigCommand: +        return NvOsGetConfigU32(input, output); +    } +    UNIMPLEMENTED(); +    return 0; +} + +u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { +    IocGetConfigParams params; +    std::memcpy(¶ms, input.data(), sizeof(params)); +    LOG_DEBUG(Service_NVDRV, "called, setting=%s!%s", params.domain_str.data(), +              params.param_str.data()); + +    if (!strcmp(params.domain_str.data(), "nv")) { +        if (!strcmp(params.param_str.data(), "NV_MEMORY_PROFILER")) { +            params.config_str[0] = '1'; +        } else { +            UNIMPLEMENTED(); +        } +    } else { +        UNIMPLEMENTED(); +    } +    std::memcpy(output.data(), ¶ms, sizeof(params)); +    return 0; +} + +} // namespace Devices +} // namespace Nvidia +} // namespace Service diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h new file mode 100644 index 000000000..abce35e17 --- /dev/null +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -0,0 +1,48 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include <cstdlib> +#include <cstring> +#include <vector> +#include "common/common_types.h" +#include "core/hle/service/nvdrv/devices/nvdevice.h" + +namespace Service { +namespace Nvidia { +namespace Devices { + +class nvhost_ctrl final : public nvdevice { +public: +    nvhost_ctrl() = default; +    ~nvhost_ctrl() override = default; + +    u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) override; + +private: +    enum IoctlCommands { +        IocSyncptReadCommand = 0xC0080014, +        IocSyncptIncrCommand = 0x40040015, +        IocSyncptWaitCommand = 0xC00C0016, +        IocModuleMutexCommand = 0x40080017, +        IocModuleRegRDWRCommand = 0xC008010E, +        IocSyncptWaitexCommand = 0xC0100019, +        IocSyncptReadMaxCommand = 0xC008001A, +        IocGetConfigCommand = 0xC183001B, +    }; + +    struct IocGetConfigParams { +        std::array<char, 0x41> domain_str; +        std::array<char, 0x41> param_str; +        std::array<char, 0x101> config_str; +    }; + +    u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); +}; + +} // namespace Devices +} // namespace Nvidia +} // namespace Service diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index d37b5b159..74ee7e154 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -22,20 +22,21 @@ VAddr nvmap::GetObjectAddress(u32 handle) const {  }  u32 nvmap::ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) { -    switch (command) { -    case IocCreateCommand: +    switch (static_cast<IoctlCommand>(command)) { +    case IoctlCommand::Create:          return IocCreate(input, output); -    case IocAllocCommand: +    case IoctlCommand::Alloc:          return IocAlloc(input, output); -    case IocGetIdCommand: +    case IoctlCommand::GetId:          return IocGetId(input, output); -    case IocFromIdCommand: +    case IoctlCommand::FromId:          return IocFromId(input, output); -    case IocParamCommand: +    case IoctlCommand::Param:          return IocParam(input, output);      }      UNIMPLEMENTED(); +    return 0;  }  u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 6954c0324..42e00f370 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -48,12 +48,12 @@ private:      /// Mapping of currently allocated handles to the objects they represent.      std::unordered_map<u32, std::shared_ptr<Object>> handles; -    enum IoctlCommands { -        IocCreateCommand = 0xC0080101, -        IocFromIdCommand = 0xC0080103, -        IocAllocCommand = 0xC0200104, -        IocParamCommand = 0xC00C0109, -        IocGetIdCommand = 0xC008010E +    enum class IoctlCommand : u32 { +        Create = 0xC0080101, +        FromId = 0xC0080103, +        Alloc = 0xC0200104, +        Param = 0xC00C0109, +        GetId = 0xC008010E      };      struct IocCreateParams { diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index 417455200..85ecde6d2 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp @@ -18,7 +18,7 @@ void NVDRV::Open(Kernel::HLERequestContext& ctx) {      std::string device_name = Memory::ReadCString(buffer.Address(), buffer.Size());      u32 fd = nvdrv->Open(device_name); -    IPC::RequestBuilder rb{ctx, 4}; +    IPC::ResponseBuilder rb{ctx, 4};      rb.Push(RESULT_SUCCESS);      rb.Push<u32>(fd);      rb.Push<u32>(0); @@ -43,7 +43,7 @@ void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) {      Memory::WriteBlock(output_buffer.Address(), output.data(), output_buffer.Size()); -    IPC::RequestBuilder rb{ctx, 3}; +    IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS);      rb.Push(nv_result);  } @@ -56,26 +56,25 @@ void NVDRV::Close(Kernel::HLERequestContext& ctx) {      auto result = nvdrv->Close(fd); -    IPC::RequestBuilder rb{ctx, 2}; +    IPC::ResponseBuilder rb{ctx, 2};      rb.Push(result);  }  void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {      LOG_WARNING(Service, "(STUBBED) called"); -    IPC::RequestBuilder rb{ctx, 3}; +    IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS);      rb.Push<u32>(0);  }  void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    u64 pid = rp.Pop<u64>(); -    u64 unk = rp.Pop<u64>(); +    pid = rp.Pop<u64>(); -    LOG_WARNING(Service, "(STUBBED) called, pid=0x%llx, unk=0x%llx", pid, unk); - -    IPC::RequestBuilder rb{ctx, 2}; +    LOG_INFO(Service, "called, pid=0x%lx", pid); +    IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS); +    rb.Push<u32>(0);  }  NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index 2283f358e..f96f2bd29 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h @@ -25,6 +25,8 @@ private:      void SetClientPID(Kernel::HLERequestContext& ctx);      std::shared_ptr<Module> nvdrv; + +    u64 pid{};  };  } // namespace Nvidia diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 9d3013c16..141ddaedd 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -6,9 +6,11 @@  #include "core/hle/service/nvdrv/devices/nvdevice.h"  #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"  #include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" +#include "core/hle/service/nvdrv/devices/nvhost_ctrl.h"  #include "core/hle/service/nvdrv/devices/nvmap.h"  #include "core/hle/service/nvdrv/interface.h"  #include "core/hle/service/nvdrv/nvdrv.h" +#include "core/hle/service/nvdrv/nvmemp.h"  namespace Service {  namespace Nvidia { @@ -19,6 +21,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {      auto module_ = std::make_shared<Module>();      std::make_shared<NVDRV>(module_, "nvdrv")->InstallAsService(service_manager);      std::make_shared<NVDRV>(module_, "nvdrv:a")->InstallAsService(service_manager); +    std::make_shared<NVMEMP>()->InstallAsService(service_manager);      nvdrv = module_;  } @@ -27,6 +30,7 @@ Module::Module() {      devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>();      devices["/dev/nvmap"] = nvmap_dev;      devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev); +    devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>();  }  u32 Module::Open(std::string device_name) { diff --git a/src/core/hle/service/nvdrv/nvmemp.cpp b/src/core/hle/service/nvdrv/nvmemp.cpp new file mode 100644 index 000000000..5a13732c7 --- /dev/null +++ b/src/core/hle/service/nvdrv/nvmemp.cpp @@ -0,0 +1,31 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/service/nvdrv/nvdrv.h" +#include "core/hle/service/nvdrv/nvmemp.h" + +namespace Service { +namespace Nvidia { + +NVMEMP::NVMEMP() : ServiceFramework("nvmemp") { +    static const FunctionInfo functions[] = { +        {0, &NVMEMP::Unknown0, "Unknown0"}, +        {1, &NVMEMP::Unknown1, "Unknown1"}, +    }; +    RegisterHandlers(functions); +} + +void NVMEMP::Unknown0(Kernel::HLERequestContext& ctx) { +    UNIMPLEMENTED(); +} + +void NVMEMP::Unknown1(Kernel::HLERequestContext& ctx) { +    UNIMPLEMENTED(); +} + +} // namespace Nvidia +} // namespace Service diff --git a/src/core/hle/service/nvdrv/nvmemp.h b/src/core/hle/service/nvdrv/nvmemp.h new file mode 100644 index 000000000..a6b5fbb82 --- /dev/null +++ b/src/core/hle/service/nvdrv/nvmemp.h @@ -0,0 +1,23 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace Nvidia { + +class NVMEMP final : public ServiceFramework<NVMEMP> { +public: +    NVMEMP(); +    ~NVMEMP() = default; + +private: +    void Unknown0(Kernel::HLERequestContext& ctx); +    void Unknown1(Kernel::HLERequestContext& ctx); +}; + +} // namespace Nvidia +} // namespace Service diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp new file mode 100644 index 000000000..705bdbe5d --- /dev/null +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp @@ -0,0 +1,96 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> + +#include "common/alignment.h" +#include "common/scope_exit.h" +#include "core/core_timing.h" +#include "core/hle/service/nvflinger/buffer_queue.h" + +namespace Service { +namespace NVFlinger { + +BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { +    native_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "BufferQueue NativeHandle"); +} + +void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) { +    Buffer buffer{}; +    buffer.slot = slot; +    buffer.igbp_buffer = igbp_buffer; +    buffer.status = Buffer::Status::Free; + +    LOG_WARNING(Service, "Adding graphics buffer %u", slot); + +    queue.emplace_back(buffer); +} + +u32 BufferQueue::DequeueBuffer(u32 pixel_format, u32 width, u32 height) { +    auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { +        // Only consider free buffers. Buffers become free once again after they've been Acquired +        // and Released by the compositor, see the NVFlinger::Compose method. +        if (buffer.status != Buffer::Status::Free) +            return false; + +        // Make sure that the parameters match. +        auto& igbp_buffer = buffer.igbp_buffer; +        return igbp_buffer.format == pixel_format && igbp_buffer.width == width && +               igbp_buffer.height == height; +    }); +    ASSERT(itr != queue.end()); + +    itr->status = Buffer::Status::Dequeued; +    return itr->slot; +} + +const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const { +    auto itr = std::find_if(queue.begin(), queue.end(), +                            [&](const Buffer& buffer) { return buffer.slot == slot; }); +    ASSERT(itr != queue.end()); +    ASSERT(itr->status == Buffer::Status::Dequeued); +    return itr->igbp_buffer; +} + +void BufferQueue::QueueBuffer(u32 slot) { +    auto itr = std::find_if(queue.begin(), queue.end(), +                            [&](const Buffer& buffer) { return buffer.slot == slot; }); +    ASSERT(itr != queue.end()); +    ASSERT(itr->status == Buffer::Status::Dequeued); +    itr->status = Buffer::Status::Queued; +} + +boost::optional<const BufferQueue::Buffer&> BufferQueue::AcquireBuffer() { +    auto itr = std::find_if(queue.begin(), queue.end(), [](const Buffer& buffer) { +        return buffer.status == Buffer::Status::Queued; +    }); +    if (itr == queue.end()) +        return boost::none; +    itr->status = Buffer::Status::Acquired; +    return *itr; +} + +void BufferQueue::ReleaseBuffer(u32 slot) { +    auto itr = std::find_if(queue.begin(), queue.end(), +                            [&](const Buffer& buffer) { return buffer.slot == slot; }); +    ASSERT(itr != queue.end()); +    ASSERT(itr->status == Buffer::Status::Acquired); +    itr->status = Buffer::Status::Free; +} + +u32 BufferQueue::Query(QueryType type) { +    LOG_WARNING(Service, "(STUBBED) called type=%u", static_cast<u32>(type)); +    switch (type) { +    case QueryType::NativeWindowFormat: +        // TODO(Subv): Use an enum for this +        static constexpr u32 FormatABGR8 = 1; +        return FormatABGR8; +    } + +    UNIMPLEMENTED(); +    return 0; +} + +} // namespace NVFlinger +} // namespace Service diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h new file mode 100644 index 000000000..5c6719407 --- /dev/null +++ b/src/core/hle/service/nvflinger/buffer_queue.h @@ -0,0 +1,82 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <vector> +#include <boost/optional.hpp> +#include "common/swap.h" +#include "core/hle/kernel/event.h" + +namespace CoreTiming { +struct EventType; +} + +namespace Service { +namespace NVFlinger { + +struct IGBPBuffer { +    u32_le magic; +    u32_le width; +    u32_le height; +    u32_le stride; +    u32_le format; +    u32_le usage; +    INSERT_PADDING_WORDS(1); +    u32_le index; +    INSERT_PADDING_WORDS(3); +    u32_le gpu_buffer_id; +    INSERT_PADDING_WORDS(17); +    u32_le nvmap_handle; +    u32_le offset; +    INSERT_PADDING_WORDS(60); +}; + +static_assert(sizeof(IGBPBuffer) == 0x16C, "IGBPBuffer has wrong size"); + +class BufferQueue final { +public: +    enum class QueryType { +        NativeWindowWidth = 0, +        NativeWindowHeight = 1, +        NativeWindowFormat = 2, +    }; + +    BufferQueue(u32 id, u64 layer_id); +    ~BufferQueue() = default; + +    struct Buffer { +        enum class Status { Free = 0, Queued = 1, Dequeued = 2, Acquired = 3 }; + +        u32 slot; +        Status status = Status::Free; +        IGBPBuffer igbp_buffer; +    }; + +    void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer); +    u32 DequeueBuffer(u32 pixel_format, u32 width, u32 height); +    const IGBPBuffer& RequestBuffer(u32 slot) const; +    void QueueBuffer(u32 slot); +    boost::optional<const Buffer&> AcquireBuffer(); +    void ReleaseBuffer(u32 slot); +    u32 Query(QueryType type); + +    u32 GetId() const { +        return id; +    } + +    Kernel::SharedPtr<Kernel::Event> GetNativeHandle() const { +        return native_handle; +    } + +private: +    u32 id; +    u64 layer_id; + +    std::vector<Buffer> queue; +    Kernel::SharedPtr<Kernel::Event> native_handle; +}; + +} // namespace NVFlinger +} // namespace Service diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp new file mode 100644 index 000000000..fe622b986 --- /dev/null +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -0,0 +1,161 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> + +#include "common/alignment.h" +#include "common/scope_exit.h" +#include "core/core_timing.h" +#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" +#include "core/hle/service/nvdrv/nvdrv.h" +#include "core/hle/service/nvflinger/buffer_queue.h" +#include "core/hle/service/nvflinger/nvflinger.h" +#include "video_core/renderer_base.h" +#include "video_core/video_core.h" + +namespace Service { +namespace NVFlinger { + +constexpr size_t SCREEN_REFRESH_RATE = 60; +constexpr u64 frame_ticks = static_cast<u64>(BASE_CLOCK_RATE / SCREEN_REFRESH_RATE); + +NVFlinger::NVFlinger() { +    // Add the different displays to the list of displays. +    Display default_{0, "Default"}; +    Display external{1, "External"}; +    Display edid{2, "Edid"}; +    Display internal{3, "Internal"}; + +    displays.emplace_back(default_); +    displays.emplace_back(external); +    displays.emplace_back(edid); +    displays.emplace_back(internal); + +    // Schedule the screen composition events +    composition_event = +        CoreTiming::RegisterEvent("ScreenCompositioin", [this](u64 userdata, int cycles_late) { +            Compose(); +            CoreTiming::ScheduleEvent(frame_ticks - cycles_late, composition_event); +        }); + +    CoreTiming::ScheduleEvent(frame_ticks, composition_event); +} + +NVFlinger::~NVFlinger() { +    CoreTiming::UnscheduleEvent(composition_event, 0); +} + +u64 NVFlinger::OpenDisplay(const std::string& name) { +    LOG_WARNING(Service, "Opening display %s", name.c_str()); + +    // TODO(Subv): Currently we only support the Default display. +    ASSERT(name == "Default"); + +    auto itr = std::find_if(displays.begin(), displays.end(), +                            [&](const Display& display) { return display.name == name; }); + +    ASSERT(itr != displays.end()); + +    return itr->id; +} + +u64 NVFlinger::CreateLayer(u64 display_id) { +    auto& display = GetDisplay(display_id); + +    ASSERT_MSG(display.layers.empty(), "Only one layer is supported per display at the moment"); + +    u64 layer_id = next_layer_id++; +    u32 buffer_queue_id = next_buffer_queue_id++; +    auto buffer_queue = std::make_shared<BufferQueue>(buffer_queue_id, layer_id); +    display.layers.emplace_back(layer_id, buffer_queue); +    buffer_queues.emplace_back(std::move(buffer_queue)); +    return layer_id; +} + +u32 NVFlinger::GetBufferQueueId(u64 display_id, u64 layer_id) { +    const auto& layer = GetLayer(display_id, layer_id); +    return layer.buffer_queue->GetId(); +} + +Kernel::SharedPtr<Kernel::Event> NVFlinger::GetVsyncEvent(u64 display_id) { +    const auto& display = GetDisplay(display_id); +    return display.vsync_event; +} + +std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const { +    auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(), +                            [&](const auto& queue) { return queue->GetId() == id; }); + +    ASSERT(itr != buffer_queues.end()); +    return *itr; +} + +Display& NVFlinger::GetDisplay(u64 display_id) { +    auto itr = std::find_if(displays.begin(), displays.end(), +                            [&](const Display& display) { return display.id == display_id; }); + +    ASSERT(itr != displays.end()); +    return *itr; +} + +Layer& NVFlinger::GetLayer(u64 display_id, u64 layer_id) { +    auto& display = GetDisplay(display_id); + +    auto itr = std::find_if(display.layers.begin(), display.layers.end(), +                            [&](const Layer& layer) { return layer.id == layer_id; }); + +    ASSERT(itr != display.layers.end()); +    return *itr; +} + +void NVFlinger::Compose() { +    for (auto& display : displays) { +        // Trigger vsync for this display at the end of drawing +        SCOPE_EXIT({ display.vsync_event->Signal(); }); + +        // Don't do anything for displays without layers. +        if (display.layers.empty()) +            continue; + +        // TODO(Subv): Support more than 1 layer. +        ASSERT_MSG(display.layers.size() == 1, "Max 1 layer per display is supported"); + +        Layer& layer = display.layers[0]; +        auto& buffer_queue = layer.buffer_queue; + +        // Search for a queued buffer and acquire it +        auto buffer = buffer_queue->AcquireBuffer(); + +        if (buffer == boost::none) { +            // There was no queued buffer to draw, render previous frame +            VideoCore::g_renderer->SwapBuffers({}); +            continue; +        } + +        auto& igbp_buffer = buffer->igbp_buffer; + +        // Now send the buffer to the GPU for drawing. +        auto nvdrv = Nvidia::nvdrv.lock(); +        ASSERT(nvdrv); + +        // TODO(Subv): Support more than just disp0. The display device selection is probably based +        // on which display we're drawing (Default, Internal, External, etc) +        auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0"); +        ASSERT(nvdisp); + +        nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format, +                     igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride); + +        buffer_queue->ReleaseBuffer(buffer->slot); +    } +} + +Layer::Layer(u64 id, std::shared_ptr<BufferQueue> queue) : id(id), buffer_queue(std::move(queue)) {} + +Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) { +    vsync_event = Kernel::Event::Create(Kernel::ResetType::Pulse, "Display VSync Event"); +} + +} // namespace NVFlinger +} // namespace Service diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h new file mode 100644 index 000000000..3126018ad --- /dev/null +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -0,0 +1,84 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <boost/optional.hpp> +#include "core/hle/kernel/event.h" + +namespace CoreTiming { +struct EventType; +} + +namespace Service { +namespace NVFlinger { + +class BufferQueue; + +struct Layer { +    Layer(u64 id, std::shared_ptr<BufferQueue> queue); +    ~Layer() = default; + +    u64 id; +    std::shared_ptr<BufferQueue> buffer_queue; +}; + +struct Display { +    Display(u64 id, std::string name); +    ~Display() = default; + +    u64 id; +    std::string name; + +    std::vector<Layer> layers; +    Kernel::SharedPtr<Kernel::Event> vsync_event; +}; + +class NVFlinger final { +public: +    NVFlinger(); +    ~NVFlinger(); + +    /// Opens the specified display and returns the id. +    u64 OpenDisplay(const std::string& name); + +    /// Creates a layer on the specified display and returns the layer id. +    u64 CreateLayer(u64 display_id); + +    /// Gets the buffer queue id of the specified layer in the specified display. +    u32 GetBufferQueueId(u64 display_id, u64 layer_id); + +    /// Gets the vsync event for the specified display. +    Kernel::SharedPtr<Kernel::Event> GetVsyncEvent(u64 display_id); + +    /// Obtains a buffer queue identified by the id. +    std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const; + +    /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when +    /// finished. +    void Compose(); + +private: +    /// Returns the display identified by the specified id. +    Display& GetDisplay(u64 display_id); + +    /// Returns the layer identified by the specified id in the desired display. +    Layer& GetLayer(u64 display_id, u64 layer_id); + +    std::vector<Display> displays; +    std::vector<std::shared_ptr<BufferQueue>> buffer_queues; + +    /// Id to use for the next layer that is created, this counter is shared among all displays. +    u64 next_layer_id = 1; +    /// Id to use for the next buffer queue that is created, this counter is shared among all +    /// layers. +    u32 next_buffer_queue_id = 1; + +    /// CoreTiming event that handles screen composition. +    CoreTiming::EventType* composition_event; +}; + +} // namespace NVFlinger +} // namespace Service diff --git a/src/core/hle/service/pctl/pctl_a.cpp b/src/core/hle/service/pctl/pctl_a.cpp index 7978aecb8..c808b764b 100644 --- a/src/core/hle/service/pctl/pctl_a.cpp +++ b/src/core/hle/service/pctl/pctl_a.cpp @@ -15,7 +15,7 @@ public:  };  void PCTL_A::GetService(Kernel::HLERequestContext& ctx) { -    IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +    IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS);      rb.PushIpcInterface<IParentalControlService>();      LOG_DEBUG(Service, "called"); diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 19213a2f4..294351b76 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -19,6 +19,7 @@  #include "core/hle/service/aoc/aoc_u.h"  #include "core/hle/service/apm/apm.h"  #include "core/hle/service/audio/audio.h" +#include "core/hle/service/filesystem/filesystem.h"  #include "core/hle/service/hid/hid.h"  #include "core/hle/service/lm/lm.h"  #include "core/hle/service/nvdrv/nvdrv.h" @@ -131,7 +132,7 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {  ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) {      switch (context.GetCommandType()) {      case IPC::CommandType::Close: { -        IPC::RequestBuilder rb{context, 1}; +        IPC::ResponseBuilder rb{context, 2};          rb.Push(RESULT_SUCCESS);          return ResultCode(ErrorModule::HIPC, ErrorDescription::RemoteProcessDead);      } @@ -164,21 +165,26 @@ void AddNamedPort(std::string name, SharedPtr<ClientPort> port) {  /// Initialize ServiceManager  void Init() { +    // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it +    // here and pass it into the respective InstallInterfaces functions. +    auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(); +      SM::g_service_manager = std::make_shared<SM::ServiceManager>();      SM::ServiceManager::InstallInterfaces(SM::g_service_manager);      Account::InstallInterfaces(*SM::g_service_manager); -    AM::InstallInterfaces(*SM::g_service_manager); +    AM::InstallInterfaces(*SM::g_service_manager, nv_flinger);      AOC::InstallInterfaces(*SM::g_service_manager);      APM::InstallInterfaces(*SM::g_service_manager);      Audio::InstallInterfaces(*SM::g_service_manager); +    FileSystem::InstallInterfaces(*SM::g_service_manager);      HID::InstallInterfaces(*SM::g_service_manager);      LM::InstallInterfaces(*SM::g_service_manager);      Nvidia::InstallInterfaces(*SM::g_service_manager);      PCTL::InstallInterfaces(*SM::g_service_manager);      Sockets::InstallInterfaces(*SM::g_service_manager);      Time::InstallInterfaces(*SM::g_service_manager); -    VI::InstallInterfaces(*SM::g_service_manager); +    VI::InstallInterfaces(*SM::g_service_manager, nv_flinger);      Set::InstallInterfaces(*SM::g_service_manager);      LOG_DEBUG(Service, "initialized OK"); diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index 3715acd74..e0e157fe1 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp @@ -19,7 +19,7 @@ void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) {      Memory::WriteBlock(output_buffer.Address(), lang_codes.data(), lang_codes.size()); -    IPC::RequestBuilder rb{ctx, 4}; +    IPC::ResponseBuilder rb{ctx, 4};      rb.Push(RESULT_SUCCESS);      rb.Push(static_cast<u64>(lang_codes.size())); diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index 7b1c8ee37..a81ff9f49 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp @@ -4,30 +4,26 @@  #include "common/logging/log.h"  #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/domain.h"  #include "core/hle/service/sm/controller.h"  namespace Service {  namespace SM {  void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) { -    auto domain = Kernel::Domain::CreateFromSession(*ctx.ServerSession()->parent).Unwrap(); +    ASSERT_MSG(!ctx.Session()->IsDomain(), "session is alread a domain"); +    ctx.Session()->ConvertToDomain(); -    IPC::RequestBuilder rb{ctx, 3}; +    IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS); -    rb.Push(static_cast<u32>(domain->request_handlers.size())); +    rb.Push<u32>(1); // Converted sessions start with 1 request handler -    LOG_DEBUG(Service, "called, domain=%d", domain->GetObjectId()); +    LOG_DEBUG(Service, "called, server_session=%d", ctx.Session()->GetObjectId());  }  void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { -    IPC::RequestBuilder rb{ctx, 2, 0, 1}; +    IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};      rb.Push(RESULT_SUCCESS); -    // TODO(Subv): Check if this is correct -    if (ctx.IsDomain()) -        rb.PushMoveObjects(ctx.Domain()); -    else -        rb.PushMoveObjects(ctx.ServerSession()); +    rb.PushMoveObjects(ctx.Session());      LOG_DEBUG(Service, "called");  } @@ -39,7 +35,7 @@ void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {  }  void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { -    IPC::RequestBuilder rb{ctx, 3}; +    IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS);      rb.Push<u32>(0x500); diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index c4078f02f..73aa013e3 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -83,7 +83,7 @@ std::shared_ptr<ServiceManager> g_service_manager;   *      0: ResultCode   */  void SM::Initialize(Kernel::HLERequestContext& ctx) { -    IPC::RequestBuilder rb{ctx, 1}; +    IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS);      LOG_DEBUG(Service_SM, "called");  } @@ -99,7 +99,7 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {      auto client_port = service_manager->GetServicePort(name);      if (client_port.Failed()) { -        IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0); +        IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);          rb.Push(client_port.Code());          LOG_ERROR(Service_SM, "called service=%s -> error 0x%08X", name.c_str(),                    client_port.Code().raw); @@ -112,7 +112,8 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {      if (session.Succeeded()) {          LOG_DEBUG(Service_SM, "called service=%s -> session=%u", name.c_str(),                    (*session)->GetObjectId()); -        IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 1, 0); +        IPC::ResponseBuilder rb = +            rp.MakeBuilder(2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles);          rb.Push(session.Code());          rb.PushMoveObjects(std::move(session).Unwrap());      } diff --git a/src/core/hle/service/sockets/bsd_u.cpp b/src/core/hle/service/sockets/bsd_u.cpp index a819acc96..4fd960bd8 100644 --- a/src/core/hle/service/sockets/bsd_u.cpp +++ b/src/core/hle/service/sockets/bsd_u.cpp @@ -11,7 +11,7 @@ namespace Sockets {  void BSD_U::RegisterClient(Kernel::HLERequestContext& ctx) {      LOG_WARNING(Service, "(STUBBED) called"); -    IPC::RequestBuilder rb{ctx, 3}; +    IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS);      rb.Push<u32>(0); // bsd errno @@ -28,7 +28,7 @@ void BSD_U::Socket(Kernel::HLERequestContext& ctx) {      u32 fd = next_fd++; -    IPC::RequestBuilder rb{ctx, 4}; +    IPC::ResponseBuilder rb{ctx, 4};      rb.Push(RESULT_SUCCESS);      rb.Push<u32>(fd); @@ -38,7 +38,7 @@ void BSD_U::Socket(Kernel::HLERequestContext& ctx) {  void BSD_U::Connect(Kernel::HLERequestContext& ctx) {      LOG_WARNING(Service, "(STUBBED) called"); -    IPC::RequestBuilder rb{ctx, 4}; +    IPC::ResponseBuilder rb{ctx, 4};      rb.Push(RESULT_SUCCESS);      rb.Push<u32>(0); // ret @@ -48,7 +48,7 @@ void BSD_U::Connect(Kernel::HLERequestContext& ctx) {  void BSD_U::SendTo(Kernel::HLERequestContext& ctx) {      LOG_WARNING(Service, "(STUBBED) called"); -    IPC::RequestBuilder rb{ctx, 4}; +    IPC::ResponseBuilder rb{ctx, 4};      rb.Push(RESULT_SUCCESS);      rb.Push<u32>(0); // ret diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 9fed89246..5802f6f6c 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -4,6 +4,7 @@  #include <chrono>  #include "common/logging/log.h" +#include "core/core_timing.h"  #include "core/hle/ipc_helpers.h"  #include "core/hle/kernel/client_port.h"  #include "core/hle/kernel/client_session.h" @@ -19,25 +20,47 @@ public:      ISystemClock() : ServiceFramework("ISystemClock") {          static const FunctionInfo functions[] = {              {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"}, -        }; +            {2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"}};          RegisterHandlers(functions);      }  private:      void GetCurrentTime(Kernel::HLERequestContext& ctx) { -        const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::milliseconds>( +        const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>(                                         std::chrono::system_clock::now().time_since_epoch())                                         .count()}; -        IPC::RequestBuilder rb{ctx, 4}; +        LOG_DEBUG(Service, "called"); +        IPC::ResponseBuilder rb{ctx, 4};          rb.Push(RESULT_SUCCESS);          rb.Push<u64>(time_since_epoch); -        LOG_DEBUG(Service, "called"); +    } + +    void GetSystemClockContext(Kernel::HLERequestContext& ctx) { +        LOG_WARNING(Service, "(STUBBED) called"); +        SystemClockContext system_clock_ontext{}; +        IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2}; +        rb.Push(RESULT_SUCCESS); +        rb.PushRaw(system_clock_ontext);      }  };  class ISteadyClock final : public ServiceFramework<ISteadyClock> {  public: -    ISteadyClock() : ServiceFramework("ISteadyClock") {} +    ISteadyClock() : ServiceFramework("ISteadyClock") { +        static const FunctionInfo functions[] = { +            {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"}, +        }; +        RegisterHandlers(functions); +    } + +private: +    void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) { +        LOG_DEBUG(Service, "called"); +        SteadyClockTimePoint steady_clock_time_point{cyclesToMs(CoreTiming::GetTicks()) / 1000}; +        IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2}; +        rb.Push(RESULT_SUCCESS); +        rb.PushRaw(steady_clock_time_point); +    }  };  class ITimeZoneService final : public ServiceFramework<ITimeZoneService> { @@ -55,14 +78,14 @@ private:      void GetDeviceLocationName(Kernel::HLERequestContext& ctx) {          LOG_WARNING(Service, "(STUBBED) called");          LocationName location_name{}; -        IPC::RequestBuilder rb{ctx, (sizeof(LocationName) / 4) + 2}; +        IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2};          rb.Push(RESULT_SUCCESS);          rb.PushRaw(location_name);      }      void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) {          LOG_WARNING(Service, "(STUBBED) called"); -        IPC::RequestBuilder rb{ctx, 3}; +        IPC::ResponseBuilder rb{ctx, 3};          rb.Push(RESULT_SUCCESS);          rb.Push<u32>(0);      } @@ -75,7 +98,7 @@ private:          CalendarTime calendar_time{2018, 1, 1, 0, 0, 0};          CalendarAdditionalInfo additional_info{}; -        IPC::RequestBuilder rb{ctx, 10}; +        IPC::ResponseBuilder rb{ctx, 10};          rb.Push(RESULT_SUCCESS);          rb.PushRaw(calendar_time);          rb.PushRaw(additional_info); @@ -83,49 +106,28 @@ private:  };  void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) { -    auto client_port = std::make_shared<ISystemClock>()->CreatePort(); -    auto session = client_port->Connect(); -    if (session.Succeeded()) { -        LOG_DEBUG(Service, "called, initialized ISystemClock -> session=%u", -                  (*session)->GetObjectId()); -        IPC::RequestBuilder rb{ctx, 2, 0, 1}; -        rb.Push(RESULT_SUCCESS); -        rb.PushMoveObjects(std::move(session).Unwrap()); -    } else { -        UNIMPLEMENTED(); -    } +    IPC::ResponseBuilder rb{ctx, 2, 0, 1}; +    rb.Push(RESULT_SUCCESS); +    rb.PushIpcInterface<ISystemClock>(); +    LOG_DEBUG(Service, "called");  }  void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) { -    auto client_port = std::make_shared<ISystemClock>()->CreatePort(); -    auto session = client_port->Connect(); -    if (session.Succeeded()) { -        LOG_DEBUG(Service, "called, initialized ISystemClock -> session=%u", -                  (*session)->GetObjectId()); -        IPC::RequestBuilder rb{ctx, 2, 0, 1}; -        rb.Push(RESULT_SUCCESS); -        rb.PushMoveObjects(std::move(session).Unwrap()); -    } else { -        UNIMPLEMENTED(); -    } +    IPC::ResponseBuilder rb{ctx, 2, 0, 1}; +    rb.Push(RESULT_SUCCESS); +    rb.PushIpcInterface<ISystemClock>(); +    LOG_DEBUG(Service, "called");  }  void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { -    auto client_port = std::make_shared<ISteadyClock>()->CreatePort(); -    auto session = client_port->Connect(); -    if (session.Succeeded()) { -        LOG_DEBUG(Service, "called, initialized ISteadyClock -> session=%u", -                  (*session)->GetObjectId()); -        IPC::RequestBuilder rb{ctx, 2, 0, 1}; -        rb.Push(RESULT_SUCCESS); -        rb.PushMoveObjects(std::move(session).Unwrap()); -    } else { -        UNIMPLEMENTED(); -    } +    IPC::ResponseBuilder rb{ctx, 2, 0, 1}; +    rb.Push(RESULT_SUCCESS); +    rb.PushIpcInterface<ISteadyClock>(); +    LOG_DEBUG(Service, "called");  }  void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { -    IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +    IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS);      rb.PushIpcInterface<ITimeZoneService>();      LOG_DEBUG(Service, "called"); diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h index 399f474d6..1cbbadb21 100644 --- a/src/core/hle/service/time/time.h +++ b/src/core/hle/service/time/time.h @@ -33,6 +33,19 @@ struct CalendarAdditionalInfo {  static_assert(sizeof(CalendarAdditionalInfo) == 0x18,                "CalendarAdditionalInfo structure has incorrect size"); +// TODO(bunnei) RE this structure +struct SystemClockContext { +    INSERT_PADDING_BYTES(0x20); +}; +static_assert(sizeof(SystemClockContext) == 0x20, +              "SystemClockContext structure has incorrect size"); + +struct SteadyClockTimePoint { +    u64 value; +    INSERT_PADDING_WORDS(4); +}; +static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size"); +  class Module final {  public:      class Interface : public ServiceFramework<Interface> { diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index c624e734e..3b993f36c 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -8,8 +8,7 @@  #include "common/scope_exit.h"  #include "core/core_timing.h"  #include "core/hle/ipc_helpers.h" -#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" -#include "core/hle/service/nvdrv/nvdrv.h" +#include "core/hle/service/nvflinger/buffer_queue.h"  #include "core/hle/service/vi/vi.h"  #include "core/hle/service/vi/vi_m.h"  #include "video_core/renderer_base.h" @@ -18,9 +17,6 @@  namespace Service {  namespace VI { -constexpr size_t SCREEN_REFRESH_RATE = 60; -constexpr u64 frame_ticks = static_cast<u64>(BASE_CLOCK_RATE / SCREEN_REFRESH_RATE); -  class Parcel {  public:      // This default size was chosen arbitrarily. @@ -204,8 +200,8 @@ public:      void DeserializeData() override {          std::u16string token = ReadInterfaceToken();          data = Read<Data>(); -        ASSERT(data.graphic_buffer_length == sizeof(IGBPBuffer)); -        buffer = Read<IGBPBuffer>(); +        ASSERT(data.graphic_buffer_length == sizeof(NVFlinger::IGBPBuffer)); +        buffer = Read<NVFlinger::IGBPBuffer>();      }      struct Data { @@ -216,7 +212,7 @@ public:      };      Data data; -    IGBPBuffer buffer; +    NVFlinger::IGBPBuffer buffer;  };  class IGBPSetPreallocatedBufferResponseParcel : public Parcel { @@ -288,7 +284,8 @@ public:  class IGBPRequestBufferResponseParcel : public Parcel {  public: -    explicit IGBPRequestBufferResponseParcel(IGBPBuffer buffer) : Parcel(), buffer(buffer) {} +    explicit IGBPRequestBufferResponseParcel(NVFlinger::IGBPBuffer buffer) +        : Parcel(), buffer(buffer) {}      ~IGBPRequestBufferResponseParcel() override = default;  protected: @@ -296,7 +293,7 @@ protected:          // TODO(Subv): Find out what this all means          Write<u32_le>(1); -        Write<u32_le>(sizeof(IGBPBuffer)); +        Write<u32_le>(sizeof(NVFlinger::IGBPBuffer));          Write<u32_le>(0); // Unknown          Write(buffer); @@ -304,7 +301,7 @@ protected:          Write<u32_le>(0);      } -    IGBPBuffer buffer; +    NVFlinger::IGBPBuffer buffer;  };  class IGBPQueueBufferRequestParcel : public Parcel { @@ -356,9 +353,38 @@ private:      Data data{};  }; +class IGBPQueryRequestParcel : public Parcel { +public: +    explicit IGBPQueryRequestParcel(const std::vector<u8>& buffer) : Parcel(buffer) { +        Deserialize(); +    } +    ~IGBPQueryRequestParcel() override = default; + +    void DeserializeData() override { +        std::u16string token = ReadInterfaceToken(); +        type = Read<u32_le>(); +    } + +    u32 type; +}; + +class IGBPQueryResponseParcel : public Parcel { +public: +    explicit IGBPQueryResponseParcel(u32 value) : Parcel(), value(value) {} +    ~IGBPQueryResponseParcel() override = default; + +protected: +    void SerializeData() override { +        Write(value); +    } + +private: +    u32_le value; +}; +  class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {  public: -    explicit IHOSBinderDriver(std::shared_ptr<NVFlinger> nv_flinger) +    explicit IHOSBinderDriver(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)          : ServiceFramework("IHOSBinderDriver"), nv_flinger(std::move(nv_flinger)) {          static const FunctionInfo functions[] = {              {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, @@ -445,12 +471,22 @@ private:              auto response_buffer = response.Serialize();              Memory::WriteBlock(output_buffer.Address(), response_buffer.data(),                                 output_buffer.Size()); +        } else if (transaction == TransactionId::Query) { +            IGBPQueryRequestParcel request{input_data}; + +            u32 value = +                buffer_queue->Query(static_cast<NVFlinger::BufferQueue::QueryType>(request.type)); + +            IGBPQueryResponseParcel response{value}; +            auto response_buffer = response.Serialize(); +            Memory::WriteBlock(output_buffer.Address(), response_buffer.data(), +                               output_buffer.Size());          } else {              ASSERT_MSG(false, "Unimplemented");          }          LOG_WARNING(Service, "(STUBBED) called"); -        IPC::RequestBuilder rb{ctx, 2}; +        IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);      } @@ -461,7 +497,7 @@ private:          u32 type = rp.Pop<u32>();          LOG_WARNING(Service, "(STUBBED) called id=%u, addval=%08X, type=%08X", id, addval, type); -        IPC::RequestBuilder rb{ctx, 2}; +        IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);      } @@ -475,12 +511,12 @@ private:          // TODO(Subv): Find out what this actually is.          LOG_WARNING(Service, "(STUBBED) called id=%u, unknown=%08X", id, unknown); -        IPC::RequestBuilder rb{ctx, 2, 1}; +        IPC::ResponseBuilder rb{ctx, 2, 1};          rb.Push(RESULT_SUCCESS);          rb.PushCopyObjects(buffer_queue->GetNativeHandle());      } -    std::shared_ptr<NVFlinger> nv_flinger; +    std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;  };  class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> { @@ -501,14 +537,14 @@ private:          u64 layer_id = rp.Pop<u64>();          u64 z_value = rp.Pop<u64>(); -        IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0); +        IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);          rb.Push(RESULT_SUCCESS);      }  };  class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {  public: -    explicit IManagerDisplayService(std::shared_ptr<NVFlinger> nv_flinger) +    explicit IManagerDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)          : ServiceFramework("IManagerDisplayService"), nv_flinger(std::move(nv_flinger)) {          static const FunctionInfo functions[] = {              {1020, &IManagerDisplayService::CloseDisplay, "CloseDisplay"}, @@ -526,7 +562,7 @@ private:          IPC::RequestParser rp{ctx};          u64 display = rp.Pop<u64>(); -        IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0); +        IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);          rb.Push(RESULT_SUCCESS);      } @@ -540,7 +576,7 @@ private:          u64 layer_id = nv_flinger->CreateLayer(display); -        IPC::RequestBuilder rb = rp.MakeBuilder(4, 0, 0, 0); +        IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);          rb.Push(RESULT_SUCCESS);          rb.Push(layer_id);      } @@ -551,17 +587,17 @@ private:          u32 stack = rp.Pop<u32>();          u64 layer_id = rp.Pop<u64>(); -        IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0); +        IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);          rb.Push(RESULT_SUCCESS);      } -    std::shared_ptr<NVFlinger> nv_flinger; +    std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;  };  void IApplicationDisplayService::GetRelayService(Kernel::HLERequestContext& ctx) {      LOG_WARNING(Service, "(STUBBED) called"); -    IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +    IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS);      rb.PushIpcInterface<IHOSBinderDriver>(nv_flinger);  } @@ -569,7 +605,7 @@ void IApplicationDisplayService::GetRelayService(Kernel::HLERequestContext& ctx)  void IApplicationDisplayService::GetSystemDisplayService(Kernel::HLERequestContext& ctx) {      LOG_WARNING(Service, "(STUBBED) called"); -    IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +    IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS);      rb.PushIpcInterface<ISystemDisplayService>();  } @@ -577,7 +613,7 @@ void IApplicationDisplayService::GetSystemDisplayService(Kernel::HLERequestConte  void IApplicationDisplayService::GetManagerDisplayService(Kernel::HLERequestContext& ctx) {      LOG_WARNING(Service, "(STUBBED) called"); -    IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +    IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS);      rb.PushIpcInterface<IManagerDisplayService>(nv_flinger);  } @@ -586,7 +622,7 @@ void IApplicationDisplayService::GetIndirectDisplayTransactionService(      Kernel::HLERequestContext& ctx) {      LOG_WARNING(Service, "(STUBBED) called"); -    IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +    IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS);      rb.PushIpcInterface<IHOSBinderDriver>(nv_flinger);  } @@ -601,7 +637,7 @@ void IApplicationDisplayService::OpenDisplay(Kernel::HLERequestContext& ctx) {      ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); -    IPC::RequestBuilder rb = rp.MakeBuilder(4, 0, 0, 0); +    IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);      rb.Push(RESULT_SUCCESS);      rb.Push<u64>(nv_flinger->OpenDisplay(name));  } @@ -611,7 +647,7 @@ void IApplicationDisplayService::CloseDisplay(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx};      u64 display_id = rp.Pop<u64>(); -    IPC::RequestBuilder rb = rp.MakeBuilder(4, 0, 0, 0); +    IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);      rb.Push(RESULT_SUCCESS);  } @@ -635,7 +671,7 @@ void IApplicationDisplayService::OpenLayer(Kernel::HLERequestContext& ctx) {      auto data = native_window.Serialize();      Memory::WriteBlock(buffer.Address(), data.data(), data.size()); -    IPC::RequestBuilder rb = rp.MakeBuilder(4, 0, 0, 0); +    IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);      rb.Push(RESULT_SUCCESS);      rb.Push<u64>(data.size());  } @@ -658,7 +694,7 @@ void IApplicationDisplayService::CreateStrayLayer(Kernel::HLERequestContext& ctx      auto data = native_window.Serialize();      Memory::WriteBlock(buffer.Address(), data.data(), data.size()); -    IPC::RequestBuilder rb = rp.MakeBuilder(6, 0, 0, 0); +    IPC::ResponseBuilder rb = rp.MakeBuilder(6, 0, 0);      rb.Push(RESULT_SUCCESS);      rb.Push(layer_id);      rb.Push<u64>(data.size()); @@ -670,7 +706,7 @@ void IApplicationDisplayService::DestroyStrayLayer(Kernel::HLERequestContext& ct      IPC::RequestParser rp{ctx};      u64 layer_id = rp.Pop<u64>(); -    IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0); +    IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);      rb.Push(RESULT_SUCCESS);  } @@ -680,7 +716,7 @@ void IApplicationDisplayService::SetLayerScalingMode(Kernel::HLERequestContext&      u32 scaling_mode = rp.Pop<u32>();      u64 unknown = rp.Pop<u64>(); -    IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0); +    IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);      rb.Push(RESULT_SUCCESS);  } @@ -691,12 +727,13 @@ void IApplicationDisplayService::GetDisplayVsyncEvent(Kernel::HLERequestContext&      auto vsync_event = nv_flinger->GetVsyncEvent(display_id); -    IPC::RequestBuilder rb = rp.MakeBuilder(2, 1, 0, 0); +    IPC::ResponseBuilder rb = rp.MakeBuilder(2, 1, 0);      rb.Push(RESULT_SUCCESS);      rb.PushCopyObjects(vsync_event);  } -IApplicationDisplayService::IApplicationDisplayService(std::shared_ptr<NVFlinger> nv_flinger) +IApplicationDisplayService::IApplicationDisplayService( +    std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)      : ServiceFramework("IApplicationDisplayService"), nv_flinger(std::move(nv_flinger)) {      static const FunctionInfo functions[] = {          {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"}, @@ -716,212 +753,9 @@ IApplicationDisplayService::IApplicationDisplayService(std::shared_ptr<NVFlinger      RegisterHandlers(functions);  } -void InstallInterfaces(SM::ServiceManager& service_manager) { -    std::make_shared<VI_M>()->InstallAsService(service_manager); -} - -NVFlinger::NVFlinger() { -    // Add the different displays to the list of displays. -    Display default_{0, "Default"}; -    Display external{1, "External"}; -    Display edid{2, "Edid"}; -    Display internal{3, "Internal"}; - -    displays.emplace_back(default_); -    displays.emplace_back(external); -    displays.emplace_back(edid); -    displays.emplace_back(internal); - -    // Schedule the screen composition events -    composition_event = -        CoreTiming::RegisterEvent("ScreenCompositioin", [this](u64 userdata, int cycles_late) { -            Compose(); -            CoreTiming::ScheduleEvent(frame_ticks - cycles_late, composition_event); -        }); - -    CoreTiming::ScheduleEvent(frame_ticks, composition_event); -} - -NVFlinger::~NVFlinger() { -    CoreTiming::UnscheduleEvent(composition_event, 0); -} - -u64 NVFlinger::OpenDisplay(const std::string& name) { -    LOG_WARNING(Service, "Opening display %s", name.c_str()); - -    // TODO(Subv): Currently we only support the Default display. -    ASSERT(name == "Default"); - -    auto itr = std::find_if(displays.begin(), displays.end(), -                            [&](const Display& display) { return display.name == name; }); - -    ASSERT(itr != displays.end()); - -    return itr->id; -} - -u64 NVFlinger::CreateLayer(u64 display_id) { -    auto& display = GetDisplay(display_id); - -    ASSERT_MSG(display.layers.empty(), "Only one layer is supported per display at the moment"); - -    u64 layer_id = next_layer_id++; -    u32 buffer_queue_id = next_buffer_queue_id++; -    auto buffer_queue = std::make_shared<BufferQueue>(buffer_queue_id, layer_id); -    display.layers.emplace_back(layer_id, buffer_queue); -    buffer_queues.emplace_back(std::move(buffer_queue)); -    return layer_id; -} - -u32 NVFlinger::GetBufferQueueId(u64 display_id, u64 layer_id) { -    const auto& layer = GetLayer(display_id, layer_id); -    return layer.buffer_queue->GetId(); -} - -Kernel::SharedPtr<Kernel::Event> NVFlinger::GetVsyncEvent(u64 display_id) { -    const auto& display = GetDisplay(display_id); -    return display.vsync_event; -} - -std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const { -    auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(), -                            [&](const auto& queue) { return queue->GetId() == id; }); - -    ASSERT(itr != buffer_queues.end()); -    return *itr; -} - -Display& NVFlinger::GetDisplay(u64 display_id) { -    auto itr = std::find_if(displays.begin(), displays.end(), -                            [&](const Display& display) { return display.id == display_id; }); - -    ASSERT(itr != displays.end()); -    return *itr; -} - -Layer& NVFlinger::GetLayer(u64 display_id, u64 layer_id) { -    auto& display = GetDisplay(display_id); - -    auto itr = std::find_if(display.layers.begin(), display.layers.end(), -                            [&](const Layer& layer) { return layer.id == layer_id; }); - -    ASSERT(itr != display.layers.end()); -    return *itr; -} - -void NVFlinger::Compose() { -    for (auto& display : displays) { -        // Trigger vsync for this display at the end of drawing -        SCOPE_EXIT({ display.vsync_event->Signal(); }); - -        // Don't do anything for displays without layers. -        if (display.layers.empty()) -            continue; - -        // TODO(Subv): Support more than 1 layer. -        ASSERT_MSG(display.layers.size() == 1, "Max 1 layer per display is supported"); - -        Layer& layer = display.layers[0]; -        auto& buffer_queue = layer.buffer_queue; - -        // Search for a queued buffer and acquire it -        auto buffer = buffer_queue->AcquireBuffer(); - -        if (buffer == boost::none) { -            // There was no queued buffer to draw, render previous frame -            VideoCore::g_renderer->SwapBuffers({}); -            continue; -        } - -        auto& igbp_buffer = buffer->igbp_buffer; - -        // Now send the buffer to the GPU for drawing. -        auto nvdrv = Nvidia::nvdrv.lock(); -        ASSERT(nvdrv); - -        // TODO(Subv): Support more than just disp0. The display device selection is probably based -        // on which display we're drawing (Default, Internal, External, etc) -        auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0"); -        ASSERT(nvdisp); - -        nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format, -                     igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride); - -        buffer_queue->ReleaseBuffer(buffer->slot); -    } -} - -BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { -    native_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "BufferQueue NativeHandle"); -} - -void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) { -    Buffer buffer{}; -    buffer.slot = slot; -    buffer.igbp_buffer = igbp_buffer; -    buffer.status = Buffer::Status::Free; - -    LOG_WARNING(Service, "Adding graphics buffer %u", slot); - -    queue.emplace_back(buffer); -} - -u32 BufferQueue::DequeueBuffer(u32 pixel_format, u32 width, u32 height) { -    auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { -        // Only consider free buffers. Buffers become free once again after they've been Acquired -        // and Released by the compositor, see the NVFlinger::Compose method. -        if (buffer.status != Buffer::Status::Free) -            return false; - -        // Make sure that the parameters match. -        auto& igbp_buffer = buffer.igbp_buffer; -        return igbp_buffer.format == pixel_format && igbp_buffer.width == width && -               igbp_buffer.height == height; -    }); -    ASSERT(itr != queue.end()); - -    itr->status = Buffer::Status::Dequeued; -    return itr->slot; -} - -const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const { -    auto itr = std::find_if(queue.begin(), queue.end(), -                            [&](const Buffer& buffer) { return buffer.slot == slot; }); -    ASSERT(itr != queue.end()); -    ASSERT(itr->status == Buffer::Status::Dequeued); -    return itr->igbp_buffer; -} - -void BufferQueue::QueueBuffer(u32 slot) { -    auto itr = std::find_if(queue.begin(), queue.end(), -                            [&](const Buffer& buffer) { return buffer.slot == slot; }); -    ASSERT(itr != queue.end()); -    ASSERT(itr->status == Buffer::Status::Dequeued); -    itr->status = Buffer::Status::Queued; -} - -boost::optional<const BufferQueue::Buffer&> BufferQueue::AcquireBuffer() { -    auto itr = std::find_if(queue.begin(), queue.end(), [](const Buffer& buffer) { -        return buffer.status == Buffer::Status::Queued; -    }); -    if (itr == queue.end()) -        return boost::none; -    itr->status = Buffer::Status::Acquired; -    return *itr; -} - -void BufferQueue::ReleaseBuffer(u32 slot) { -    auto itr = std::find_if(queue.begin(), queue.end(), -                            [&](const Buffer& buffer) { return buffer.slot == slot; }); -    ASSERT(itr != queue.end()); -    ASSERT(itr->status == Buffer::Status::Acquired); -    itr->status = Buffer::Status::Free; -} - -Layer::Layer(u64 id, std::shared_ptr<BufferQueue> queue) : id(id), buffer_queue(std::move(queue)) {} - -Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) { -    vsync_event = Kernel::Event::Create(Kernel::ResetType::Pulse, "Display VSync Event"); +void InstallInterfaces(SM::ServiceManager& service_manager, +                       std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) { +    std::make_shared<VI_M>(nv_flinger)->InstallAsService(service_manager);  }  } // namespace VI diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index 81d4f3daa..a6e084f87 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h @@ -7,6 +7,7 @@  #include <memory>  #include <boost/optional.hpp>  #include "core/hle/kernel/event.h" +#include "core/hle/service/nvflinger/nvflinger.h"  #include "core/hle/service/service.h"  namespace CoreTiming { @@ -16,127 +17,9 @@ struct EventType;  namespace Service {  namespace VI { -struct IGBPBuffer { -    u32_le magic; -    u32_le width; -    u32_le height; -    u32_le stride; -    u32_le format; -    u32_le usage; -    INSERT_PADDING_WORDS(1); -    u32_le index; -    INSERT_PADDING_WORDS(3); -    u32_le gpu_buffer_id; -    INSERT_PADDING_WORDS(17); -    u32_le nvmap_handle; -    u32_le offset; -    INSERT_PADDING_WORDS(60); -}; - -static_assert(sizeof(IGBPBuffer) == 0x16C, "IGBPBuffer has wrong size"); - -class BufferQueue { -public: -    BufferQueue(u32 id, u64 layer_id); -    ~BufferQueue() = default; - -    struct Buffer { -        enum class Status { Free = 0, Queued = 1, Dequeued = 2, Acquired = 3 }; - -        u32 slot; -        Status status = Status::Free; -        IGBPBuffer igbp_buffer; -    }; - -    void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer); -    u32 DequeueBuffer(u32 pixel_format, u32 width, u32 height); -    const IGBPBuffer& RequestBuffer(u32 slot) const; -    void QueueBuffer(u32 slot); -    boost::optional<const Buffer&> AcquireBuffer(); -    void ReleaseBuffer(u32 slot); - -    u32 GetId() const { -        return id; -    } - -    Kernel::SharedPtr<Kernel::Event> GetNativeHandle() const { -        return native_handle; -    } - -private: -    u32 id; -    u64 layer_id; - -    std::vector<Buffer> queue; -    Kernel::SharedPtr<Kernel::Event> native_handle; -}; - -struct Layer { -    Layer(u64 id, std::shared_ptr<BufferQueue> queue); -    ~Layer() = default; - -    u64 id; -    std::shared_ptr<BufferQueue> buffer_queue; -}; - -struct Display { -    Display(u64 id, std::string name); -    ~Display() = default; - -    u64 id; -    std::string name; - -    std::vector<Layer> layers; -    Kernel::SharedPtr<Kernel::Event> vsync_event; -}; - -class NVFlinger { -public: -    NVFlinger(); -    ~NVFlinger(); - -    /// Opens the specified display and returns the id. -    u64 OpenDisplay(const std::string& name); - -    /// Creates a layer on the specified display and returns the layer id. -    u64 CreateLayer(u64 display_id); - -    /// Gets the buffer queue id of the specified layer in the specified display. -    u32 GetBufferQueueId(u64 display_id, u64 layer_id); - -    /// Gets the vsync event for the specified display. -    Kernel::SharedPtr<Kernel::Event> GetVsyncEvent(u64 display_id); - -    /// Obtains a buffer queue identified by the id. -    std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const; - -    /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when -    /// finished. -    void Compose(); - -private: -    /// Returns the display identified by the specified id. -    Display& GetDisplay(u64 display_id); - -    /// Returns the layer identified by the specified id in the desired display. -    Layer& GetLayer(u64 display_id, u64 layer_id); - -    std::vector<Display> displays; -    std::vector<std::shared_ptr<BufferQueue>> buffer_queues; - -    /// Id to use for the next layer that is created, this counter is shared among all displays. -    u64 next_layer_id = 1; -    /// Id to use for the next buffer queue that is created, this counter is shared among all -    /// layers. -    u32 next_buffer_queue_id = 1; - -    /// CoreTiming event that handles screen composition. -    CoreTiming::EventType* composition_event; -}; -  class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {  public: -    IApplicationDisplayService(std::shared_ptr<NVFlinger> nv_flinger); +    IApplicationDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);      ~IApplicationDisplayService() = default;  private: @@ -152,11 +35,12 @@ private:      void DestroyStrayLayer(Kernel::HLERequestContext& ctx);      void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx); -    std::shared_ptr<NVFlinger> nv_flinger; +    std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;  };  /// Registers all VI services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); +void InstallInterfaces(SM::ServiceManager& service_manager, +                       std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);  } // namespace VI  } // namespace Service diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp index 1a5a28b0d..bb440cadb 100644 --- a/src/core/hle/service/vi/vi_m.cpp +++ b/src/core/hle/service/vi/vi_m.cpp @@ -13,17 +13,18 @@ namespace VI {  void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) {      LOG_WARNING(Service, "(STUBBED) called"); -    IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; +    IPC::ResponseBuilder rb{ctx, 2, 0, 1}; +    rb.Push(RESULT_SUCCESS);      rb.PushIpcInterface<IApplicationDisplayService>(nv_flinger);  } -VI_M::VI_M() : ServiceFramework("vi:m") { +VI_M::VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) +    : ServiceFramework("vi:m"), nv_flinger(std::move(nv_flinger)) {      static const FunctionInfo functions[] = {          {2, &VI_M::GetDisplayService, "GetDisplayService"},          {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},      };      RegisterHandlers(functions); -    nv_flinger = std::make_shared<NVFlinger>();  }  } // namespace VI diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h index 70ff7a2f3..e5319b1e7 100644 --- a/src/core/hle/service/vi/vi_m.h +++ b/src/core/hle/service/vi/vi_m.h @@ -8,17 +8,21 @@  #include "core/hle/service/service.h"  namespace Service { +namespace NVFlinger { +class NVFlinger; +} +  namespace VI {  class VI_M final : public ServiceFramework<VI_M> {  public: -    VI_M(); +    VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);      ~VI_M() = default;  private:      void GetDisplayService(Kernel::HLERequestContext& ctx); -    std::shared_ptr<NVFlinger> nv_flinger; +    std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;  };  } // namespace VI diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 4bee5fb86..37030683b 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -7,14 +7,44 @@  #include "common/file_util.h"  #include "common/logging/log.h"  #include "common/string_util.h" +#include "core/file_sys/romfs_factory.h"  #include "core/hle/kernel/process.h"  #include "core/hle/kernel/resource_limit.h" +#include "core/hle/service/filesystem/filesystem.h"  #include "core/loader/deconstructed_rom_directory.h"  #include "core/loader/nso.h"  #include "core/memory.h"  namespace Loader { +static std::string FindRomFS(const std::string& directory) { +    std::string filepath_romfs; +    const auto callback = [&filepath_romfs](unsigned*, const std::string& directory, +                                            const std::string& virtual_name) -> bool { +        const std::string physical_name = directory + virtual_name; +        if (FileUtil::IsDirectory(physical_name)) { +            // Skip directories +            return true; +        } + +        // Verify extension +        const std::string extension = physical_name.substr(physical_name.find_last_of(".") + 1); +        if (Common::ToLower(extension) != "istorage") { +            return true; +        } + +        // Found it - we are done +        filepath_romfs = std::move(physical_name); +        return false; +    }; + +    // Search the specified directory recursively, looking for the first .istorage file, which will +    // be used for the RomFS +    FileUtil::ForeachDirectoryEntry(nullptr, directory, callback); + +    return filepath_romfs; +} +  AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileUtil::IOFile&& file,                                                                           std::string filepath)      : AppLoader(std::move(file)), filepath(std::move(filepath)) {} @@ -79,10 +109,10 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(      // Load NSO modules      VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR}; +    const std::string directory = filepath.substr(0, filepath.find_last_of("/\\")) + DIR_SEP;      for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",                                 "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { -        const std::string path = -            filepath.substr(0, filepath.find_last_of("/\\")) + DIR_SEP + module; +        const std::string path = directory + DIR_SEP + module;          const VAddr load_addr = next_load_addr;          next_load_addr = AppLoader_NSO::LoadModule(path, load_addr);          if (next_load_addr) { @@ -98,8 +128,43 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(          Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);      process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Kernel::DEFAULT_STACK_SIZE); +    // Find the RomFS by searching for a ".istorage" file in this directory +    filepath_romfs = FindRomFS(directory); + +    // Register the RomFS if a ".istorage" file was found +    if (!filepath_romfs.empty()) { +        Service::FileSystem::RegisterFileSystem(std::make_unique<FileSys::RomFS_Factory>(*this), +                                                Service::FileSystem::Type::RomFS); +    } +      is_loaded = true;      return ResultStatus::Success;  } +ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS( +    std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) { + +    if (filepath_romfs.empty()) { +        LOG_DEBUG(Loader, "No RomFS available"); +        return ResultStatus::ErrorNotUsed; +    } + +    // We reopen the file, to allow its position to be independent +    romfs_file = std::make_shared<FileUtil::IOFile>(filepath_romfs, "rb"); +    if (!romfs_file->IsOpen()) { +        return ResultStatus::Error; +    } + +    offset = 0; +    size = romfs_file->GetSize(); + +    LOG_DEBUG(Loader, "RomFS offset:           0x%08X", offset); +    LOG_DEBUG(Loader, "RomFS size:             0x%08X", size); + +    // Reset read pointer +    file.Seek(0, SEEK_SET); + +    return ResultStatus::Success; +} +  } // namespace Loader diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h index 162541d54..26493de5e 100644 --- a/src/core/loader/deconstructed_rom_directory.h +++ b/src/core/loader/deconstructed_rom_directory.h @@ -35,7 +35,11 @@ public:      ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; +    ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, +                           u64& size) override; +  private: +    std::string filepath_romfs;      std::string filepath;  };  | 
