diff options
Diffstat (limited to 'src/core')
99 files changed, 2783 insertions, 1667 deletions
| diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a1d8dcfa5..e370fd225 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -458,6 +458,8 @@ add_library(core STATIC      hle/service/nvflinger/buffer_queue.h      hle/service/nvflinger/nvflinger.cpp      hle/service/nvflinger/nvflinger.h +    hle/service/olsc/olsc.cpp +    hle/service/olsc/olsc.h      hle/service/pcie/pcie.cpp      hle/service/pcie/pcie.h      hle/service/pctl/module.cpp diff --git a/src/core/arm/cpu_interrupt_handler.h b/src/core/arm/cpu_interrupt_handler.h index 71e582f79..c20c280f1 100644 --- a/src/core/arm/cpu_interrupt_handler.h +++ b/src/core/arm/cpu_interrupt_handler.h @@ -21,8 +21,8 @@ public:      CPUInterruptHandler(const CPUInterruptHandler&) = delete;      CPUInterruptHandler& operator=(const CPUInterruptHandler&) = delete; -    CPUInterruptHandler(CPUInterruptHandler&&) = default; -    CPUInterruptHandler& operator=(CPUInterruptHandler&&) = default; +    CPUInterruptHandler(CPUInterruptHandler&&) = delete; +    CPUInterruptHandler& operator=(CPUInterruptHandler&&) = delete;      bool IsInterrupted() const {          return is_interrupted; diff --git a/src/core/core.cpp b/src/core/core.cpp index 242796008..7ca3652af 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -145,7 +145,7 @@ struct System::Impl {      }      ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { -        LOG_DEBUG(HW_Memory, "initialized OK"); +        LOG_DEBUG(Core, "initialized OK");          device_memory = std::make_unique<Core::DeviceMemory>(); @@ -187,7 +187,7 @@ struct System::Impl {          service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); -        Service::Init(service_manager, system); +        services = std::make_unique<Service::Services>(service_manager, system);          GDBStub::DeferStart();          interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system); @@ -208,9 +208,11 @@ struct System::Impl {          return ResultStatus::Success;      } -    ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, -                      const std::string& filepath) { -        app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); +    ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath, +                      std::size_t program_index) { +        app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath), +                                       program_index); +          if (!app_loader) {              LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);              return ResultStatus::ErrorGetLoader; @@ -224,7 +226,7 @@ struct System::Impl {              return init_result;          } -        telemetry_session->AddInitialInfo(*app_loader); +        telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);          auto main_process =              Kernel::Process::Create(system, "main", Kernel::Process::ProcessType::Userland);          const auto [load_result, load_parameters] = app_loader->Load(*main_process, system); @@ -296,7 +298,7 @@ struct System::Impl {          // Shutdown emulation session          GDBStub::Shutdown(); -        Service::Shutdown(); +        services.reset();          service_manager.reset();          cheat_engine.reset();          telemetry_session.reset(); @@ -306,8 +308,8 @@ struct System::Impl {          cpu_manager.Shutdown();          // Shutdown kernel and core timing -        kernel.Shutdown();          core_timing.Shutdown(); +        kernel.Shutdown();          // Close app loader          app_loader.reset(); @@ -338,7 +340,7 @@ struct System::Impl {          Service::Glue::ApplicationLaunchProperty launch{};          launch.title_id = process.GetTitleID(); -        FileSys::PatchManager pm{launch.title_id}; +        FileSys::PatchManager pm{launch.title_id, fs_controller, *content_provider};          launch.version = pm.GetGameVersion().value_or(0);          // TODO(DarkLordZach): When FSController/Game Card Support is added, if @@ -398,6 +400,9 @@ struct System::Impl {      /// Service manager      std::shared_ptr<Service::SM::ServiceManager> service_manager; +    /// Services +    std::unique_ptr<Service::Services> services; +      /// Telemetry session for this emulation session      std::unique_ptr<Core::TelemetrySession> telemetry_session; @@ -413,6 +418,8 @@ struct System::Impl {      bool is_multicore{};      bool is_async_gpu{}; +    ExecuteProgramCallback execute_program_callback; +      std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};      std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{};  }; @@ -444,8 +451,13 @@ void System::InvalidateCpuInstructionCaches() {      impl->kernel.InvalidateAllInstructionCaches();  } -System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { -    return impl->Load(*this, emu_window, filepath); +void System::Shutdown() { +    impl->Shutdown(); +} + +System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath, +                                  std::size_t program_index) { +    return impl->Load(*this, emu_window, filepath, program_index);  }  bool System::IsPoweredOn() const { @@ -632,7 +644,11 @@ const std::string& System::GetStatusDetails() const {      return impl->status_details;  } -Loader::AppLoader& System::GetAppLoader() const { +Loader::AppLoader& System::GetAppLoader() { +    return *impl->app_loader; +} + +const Loader::AppLoader& System::GetAppLoader() const {      return *impl->app_loader;  } @@ -748,14 +764,6 @@ const System::CurrentBuildProcessID& System::GetCurrentProcessBuildID() const {      return impl->build_id;  } -System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { -    return impl->Init(*this, emu_window); -} - -void System::Shutdown() { -    impl->Shutdown(); -} -  Service::SM::ServiceManager& System::ServiceManager() {      return *impl->service_manager;  } @@ -786,4 +794,16 @@ bool System::IsMulticore() const {      return impl->is_multicore;  } +void System::RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback) { +    impl->execute_program_callback = std::move(callback); +} + +void System::ExecuteProgram(std::size_t program_index) { +    if (impl->execute_program_callback) { +        impl->execute_program_callback(program_index); +    } else { +        LOG_CRITICAL(Core, "execute_program_callback must be initialized by the frontend"); +    } +} +  } // namespace Core diff --git a/src/core/core.h b/src/core/core.h index 6db896bae..f642befc0 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -5,6 +5,7 @@  #pragma once  #include <cstddef> +#include <functional>  #include <memory>  #include <string>  #include <vector> @@ -144,19 +145,19 @@ public:       * Run the OS and Application       * This function will start emulation and run the relevant devices       */ -    ResultStatus Run(); +    [[nodiscard]] ResultStatus Run();      /**       * Pause the OS and Application       * This function will pause emulation and stop the relevant devices       */ -    ResultStatus Pause(); +    [[nodiscard]] ResultStatus Pause();      /**       * Step the CPU one instruction       * @return Result status, indicating whether or not the operation succeeded.       */ -    ResultStatus SingleStep(); +    [[nodiscard]] ResultStatus SingleStep();      /**       * Invalidate the CPU instruction caches @@ -173,22 +174,24 @@ public:       * @param emu_window Reference to the host-system window used for video output and keyboard       *                   input.       * @param filepath String path to the executable application to load on the host file system. +     * @param program_index Specifies the index within the container of the program to launch.       * @returns ResultStatus code, indicating if the operation succeeded.       */ -    ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath); +    [[nodiscard]] ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath, +                                    std::size_t program_index = 0);      /**       * Indicates if the emulated system is powered on (all subsystems initialized and able to run an       * application).       * @returns True if the emulated system is powered on, otherwise false.       */ -    bool IsPoweredOn() const; +    [[nodiscard]] bool IsPoweredOn() const;      /// Gets a reference to the telemetry session for this emulation session. -    Core::TelemetrySession& TelemetrySession(); +    [[nodiscard]] Core::TelemetrySession& TelemetrySession();      /// Gets a reference to the telemetry session for this emulation session. -    const Core::TelemetrySession& TelemetrySession() const; +    [[nodiscard]] const Core::TelemetrySession& TelemetrySession() const;      /// Prepare the core emulation for a reschedule      void PrepareReschedule(); @@ -197,185 +200,178 @@ public:      void PrepareReschedule(u32 core_index);      /// Gets and resets core performance statistics -    PerfStatsResults GetAndResetPerfStats(); +    [[nodiscard]] PerfStatsResults GetAndResetPerfStats();      /// Gets an ARM interface to the CPU core that is currently running -    ARM_Interface& CurrentArmInterface(); +    [[nodiscard]] ARM_Interface& CurrentArmInterface();      /// Gets an ARM interface to the CPU core that is currently running -    const ARM_Interface& CurrentArmInterface() const; +    [[nodiscard]] const ARM_Interface& CurrentArmInterface() const;      /// Gets the index of the currently running CPU core -    std::size_t CurrentCoreIndex() const; +    [[nodiscard]] std::size_t CurrentCoreIndex() const;      /// Gets the scheduler for the CPU core that is currently running -    Kernel::Scheduler& CurrentScheduler(); +    [[nodiscard]] Kernel::Scheduler& CurrentScheduler();      /// Gets the scheduler for the CPU core that is currently running -    const Kernel::Scheduler& CurrentScheduler() const; +    [[nodiscard]] const Kernel::Scheduler& CurrentScheduler() const;      /// Gets the physical core for the CPU core that is currently running -    Kernel::PhysicalCore& CurrentPhysicalCore(); +    [[nodiscard]] Kernel::PhysicalCore& CurrentPhysicalCore();      /// Gets the physical core for the CPU core that is currently running -    const Kernel::PhysicalCore& CurrentPhysicalCore() const; +    [[nodiscard]] const Kernel::PhysicalCore& CurrentPhysicalCore() const;      /// Gets a reference to an ARM interface for the CPU core with the specified index -    ARM_Interface& ArmInterface(std::size_t core_index); +    [[nodiscard]] ARM_Interface& ArmInterface(std::size_t core_index);      /// Gets a const reference to an ARM interface from the CPU core with the specified index -    const ARM_Interface& ArmInterface(std::size_t core_index) const; +    [[nodiscard]] const ARM_Interface& ArmInterface(std::size_t core_index) const; -    CpuManager& GetCpuManager(); +    /// Gets a reference to the underlying CPU manager. +    [[nodiscard]] CpuManager& GetCpuManager(); -    const CpuManager& GetCpuManager() const; +    /// Gets a const reference to the underlying CPU manager +    [[nodiscard]] const CpuManager& GetCpuManager() const;      /// Gets a reference to the exclusive monitor -    ExclusiveMonitor& Monitor(); +    [[nodiscard]] ExclusiveMonitor& Monitor();      /// Gets a constant reference to the exclusive monitor -    const ExclusiveMonitor& Monitor() const; +    [[nodiscard]] const ExclusiveMonitor& Monitor() const;      /// Gets a mutable reference to the system memory instance. -    Core::Memory::Memory& Memory(); +    [[nodiscard]] Core::Memory::Memory& Memory();      /// Gets a constant reference to the system memory instance. -    const Core::Memory::Memory& Memory() const; +    [[nodiscard]] const Core::Memory::Memory& Memory() const;      /// Gets a mutable reference to the GPU interface -    Tegra::GPU& GPU(); +    [[nodiscard]] Tegra::GPU& GPU();      /// Gets an immutable reference to the GPU interface. -    const Tegra::GPU& GPU() const; +    [[nodiscard]] const Tegra::GPU& GPU() const;      /// Gets a mutable reference to the renderer. -    VideoCore::RendererBase& Renderer(); +    [[nodiscard]] VideoCore::RendererBase& Renderer();      /// Gets an immutable reference to the renderer. -    const VideoCore::RendererBase& Renderer() const; +    [[nodiscard]] const VideoCore::RendererBase& Renderer() const;      /// Gets the scheduler for the CPU core with the specified index -    Kernel::Scheduler& Scheduler(std::size_t core_index); +    [[nodiscard]] Kernel::Scheduler& Scheduler(std::size_t core_index);      /// Gets the scheduler for the CPU core with the specified index -    const Kernel::Scheduler& Scheduler(std::size_t core_index) const; +    [[nodiscard]] const Kernel::Scheduler& Scheduler(std::size_t core_index) const;      /// Gets the global scheduler -    Kernel::GlobalScheduler& GlobalScheduler(); +    [[nodiscard]] Kernel::GlobalScheduler& GlobalScheduler();      /// Gets the global scheduler -    const Kernel::GlobalScheduler& GlobalScheduler() const; +    [[nodiscard]] const Kernel::GlobalScheduler& GlobalScheduler() const;      /// Gets the manager for the guest device memory -    Core::DeviceMemory& DeviceMemory(); +    [[nodiscard]] Core::DeviceMemory& DeviceMemory();      /// Gets the manager for the guest device memory -    const Core::DeviceMemory& DeviceMemory() const; +    [[nodiscard]] const Core::DeviceMemory& DeviceMemory() const;      /// Provides a pointer to the current process -    Kernel::Process* CurrentProcess(); +    [[nodiscard]] Kernel::Process* CurrentProcess();      /// Provides a constant pointer to the current process. -    const Kernel::Process* CurrentProcess() const; +    [[nodiscard]] const Kernel::Process* CurrentProcess() const;      /// Provides a reference to the core timing instance. -    Timing::CoreTiming& CoreTiming(); +    [[nodiscard]] Timing::CoreTiming& CoreTiming();      /// Provides a constant reference to the core timing instance. -    const Timing::CoreTiming& CoreTiming() const; +    [[nodiscard]] const Timing::CoreTiming& CoreTiming() const;      /// Provides a reference to the interrupt manager instance. -    Core::Hardware::InterruptManager& InterruptManager(); +    [[nodiscard]] Core::Hardware::InterruptManager& InterruptManager();      /// Provides a constant reference to the interrupt manager instance. -    const Core::Hardware::InterruptManager& InterruptManager() const; +    [[nodiscard]] const Core::Hardware::InterruptManager& InterruptManager() const;      /// Provides a reference to the kernel instance. -    Kernel::KernelCore& Kernel(); +    [[nodiscard]] Kernel::KernelCore& Kernel();      /// Provides a constant reference to the kernel instance. -    const Kernel::KernelCore& Kernel() const; +    [[nodiscard]] const Kernel::KernelCore& Kernel() const;      /// Provides a reference to the internal PerfStats instance. -    Core::PerfStats& GetPerfStats(); +    [[nodiscard]] Core::PerfStats& GetPerfStats();      /// Provides a constant reference to the internal PerfStats instance. -    const Core::PerfStats& GetPerfStats() const; +    [[nodiscard]] const Core::PerfStats& GetPerfStats() const;      /// Provides a reference to the frame limiter; -    Core::FrameLimiter& FrameLimiter(); +    [[nodiscard]] Core::FrameLimiter& FrameLimiter();      /// Provides a constant referent to the frame limiter -    const Core::FrameLimiter& FrameLimiter() const; +    [[nodiscard]] const Core::FrameLimiter& FrameLimiter() const;      /// Gets the name of the current game -    Loader::ResultStatus GetGameName(std::string& out) const; +    [[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const;      void SetStatus(ResultStatus new_status, const char* details); -    const std::string& GetStatusDetails() const; +    [[nodiscard]] const std::string& GetStatusDetails() const; -    Loader::AppLoader& GetAppLoader() const; +    [[nodiscard]] Loader::AppLoader& GetAppLoader(); +    [[nodiscard]] const Loader::AppLoader& GetAppLoader() const; -    Service::SM::ServiceManager& ServiceManager(); -    const Service::SM::ServiceManager& ServiceManager() const; +    [[nodiscard]] Service::SM::ServiceManager& ServiceManager(); +    [[nodiscard]] const Service::SM::ServiceManager& ServiceManager() const;      void SetFilesystem(FileSys::VirtualFilesystem vfs); -    FileSys::VirtualFilesystem GetFilesystem() const; +    [[nodiscard]] FileSys::VirtualFilesystem GetFilesystem() const;      void RegisterCheatList(const std::vector<Memory::CheatEntry>& list,                             const std::array<u8, 0x20>& build_id, VAddr main_region_begin,                             u64 main_region_size);      void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set); -      void SetDefaultAppletFrontendSet(); -    Service::AM::Applets::AppletManager& GetAppletManager(); - -    const Service::AM::Applets::AppletManager& GetAppletManager() const; +    [[nodiscard]] Service::AM::Applets::AppletManager& GetAppletManager(); +    [[nodiscard]] const Service::AM::Applets::AppletManager& GetAppletManager() const;      void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider); -    FileSys::ContentProvider& GetContentProvider(); - -    const FileSys::ContentProvider& GetContentProvider() const; +    [[nodiscard]] FileSys::ContentProvider& GetContentProvider(); +    [[nodiscard]] const FileSys::ContentProvider& GetContentProvider() const; -    Service::FileSystem::FileSystemController& GetFileSystemController(); - -    const Service::FileSystem::FileSystemController& GetFileSystemController() const; +    [[nodiscard]] Service::FileSystem::FileSystemController& GetFileSystemController(); +    [[nodiscard]] const Service::FileSystem::FileSystemController& GetFileSystemController() const;      void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,                                   FileSys::ContentProvider* provider);      void ClearContentProvider(FileSys::ContentProviderUnionSlot slot); -    const Reporter& GetReporter() const; - -    Service::Glue::ARPManager& GetARPManager(); +    [[nodiscard]] const Reporter& GetReporter() const; -    const Service::Glue::ARPManager& GetARPManager() const; +    [[nodiscard]] Service::Glue::ARPManager& GetARPManager(); +    [[nodiscard]] const Service::Glue::ARPManager& GetARPManager() const; -    Service::APM::Controller& GetAPMController(); +    [[nodiscard]] Service::APM::Controller& GetAPMController(); +    [[nodiscard]] const Service::APM::Controller& GetAPMController() const; -    const Service::APM::Controller& GetAPMController() const; +    [[nodiscard]] Service::LM::Manager& GetLogManager(); +    [[nodiscard]] const Service::LM::Manager& GetLogManager() const; -    Service::LM::Manager& GetLogManager(); - -    const Service::LM::Manager& GetLogManager() const; - -    Service::Time::TimeManager& GetTimeManager(); - -    const Service::Time::TimeManager& GetTimeManager() const; +    [[nodiscard]] Service::Time::TimeManager& GetTimeManager(); +    [[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const;      void SetExitLock(bool locked); - -    bool GetExitLock() const; +    [[nodiscard]] bool GetExitLock() const;      void SetCurrentProcessBuildID(const CurrentBuildProcessID& id); - -    const CurrentBuildProcessID& GetCurrentProcessBuildID() const; +    [[nodiscard]] const CurrentBuildProcessID& GetCurrentProcessBuildID() const;      /// Register a host thread as an emulated CPU Core.      void RegisterCoreThread(std::size_t id); @@ -390,18 +386,27 @@ public:      void ExitDynarmicProfile();      /// Tells if system is running on multicore. -    bool IsMulticore() const; +    [[nodiscard]] bool IsMulticore() const; -private: -    System(); +    /// Type used for the frontend to designate a callback for System to re-launch the application +    /// using a specified program index. +    using ExecuteProgramCallback = std::function<void(std::size_t)>;      /** -     * Initialize the emulated system. -     * @param emu_window Reference to the host-system window used for video output and keyboard -     *                   input. -     * @return ResultStatus code, indicating if the operation succeeded. +     * Registers a callback from the frontend for System to re-launch the application using a +     * specified program index. +     * @param callback Callback from the frontend to relaunch the application. +     */ +    void RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback); + +    /** +     * Instructs the frontend to re-launch the application using the specified program_index. +     * @param program_index Specifies the index within the application of the program to launch.       */ -    ResultStatus Init(Frontend::EmuWindow& emu_window); +    void ExecuteProgram(std::size_t program_index); + +private: +    System();      struct Impl;      std::unique_ptr<Impl> impl; diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index 956da68f7..8dee5590b 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp @@ -29,7 +29,7 @@ constexpr std::array partition_names{      "logo",  }; -XCI::XCI(VirtualFile file_) +XCI::XCI(VirtualFile file_, std::size_t program_index)      : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA},        partitions(partition_names.size()),        partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} { @@ -62,7 +62,8 @@ XCI::XCI(VirtualFile file_)      }      secure_partition = std::make_shared<NSP>( -        main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)])); +        main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)]), +        program_index);      ncas = secure_partition->GetNCAsCollapsed();      program = diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h index 2d0a0f285..4960e90fe 100644 --- a/src/core/file_sys/card_image.h +++ b/src/core/file_sys/card_image.h @@ -78,7 +78,7 @@ enum class XCIPartition : u8 { Update, Normal, Secure, Logo };  class XCI : public ReadOnlyVfsDirectory {  public: -    explicit XCI(VirtualFile file); +    explicit XCI(VirtualFile file, std::size_t program_index = 0);      ~XCI() override;      Loader::ResultStatus GetStatus() const; diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 807b05821..e9d1607d0 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -112,7 +112,10 @@ bool IsDirValidAndNonEmpty(const VirtualDir& dir) {  }  } // Anonymous namespace -PatchManager::PatchManager(u64 title_id) : title_id(title_id) {} +PatchManager::PatchManager(u64 title_id_, +                           const Service::FileSystem::FileSystemController& fs_controller_, +                           const ContentProvider& content_provider_) +    : title_id{title_id_}, fs_controller{fs_controller_}, content_provider{content_provider_} {}  PatchManager::~PatchManager() = default; @@ -128,34 +131,30 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {      if (Settings::values.dump_exefs) {          LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id); -        const auto dump_dir = -            Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id); +        const auto dump_dir = fs_controller.GetModificationDumpRoot(title_id);          if (dump_dir != nullptr) {              const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs");              VfsRawCopyD(exefs, exefs_dir);          }      } -    const auto& installed = Core::System::GetInstance().GetContentProvider(); -      const auto& disabled = Settings::values.disabled_addons[title_id];      const auto update_disabled =          std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend();      // Game Updates      const auto update_tid = GetUpdateTitleID(title_id); -    const auto update = installed.GetEntry(update_tid, ContentRecordType::Program); +    const auto update = content_provider.GetEntry(update_tid, ContentRecordType::Program);      if (!update_disabled && update != nullptr && update->GetExeFS() != nullptr &&          update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {          LOG_INFO(Loader, "    ExeFS: Update ({}) applied successfully", -                 FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0))); +                 FormatTitleVersion(content_provider.GetEntryVersion(update_tid).value_or(0)));          exefs = update->GetExeFS();      }      // LayeredExeFS -    const auto load_dir = -        Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id); +    const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);      if (load_dir != nullptr && load_dir->GetSize() > 0) {          auto patch_dirs = load_dir->GetSubdirectories();          std::sort( @@ -241,8 +240,7 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st      if (Settings::values.dump_nso) {          LOG_INFO(Loader, "Dumping NSO for name={}, build_id={}, title_id={:016X}", name, build_id,                   title_id); -        const auto dump_dir = -            Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id); +        const auto dump_dir = fs_controller.GetModificationDumpRoot(title_id);          if (dump_dir != nullptr) {              const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso");              const auto file = nso_dir->CreateFile(fmt::format("{}-{}.nso", name, build_id)); @@ -254,8 +252,7 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st      LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id); -    const auto load_dir = -        Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id); +    const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);      if (load_dir == nullptr) {          LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);          return nso; @@ -298,8 +295,7 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_) const {      LOG_INFO(Loader, "Querying NSO patch existence for build_id={}", build_id); -    const auto load_dir = -        Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id); +    const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);      if (load_dir == nullptr) {          LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);          return false; @@ -313,8 +309,8 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_) const {  }  std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList( -    const Core::System& system, const BuildID& build_id_) const { -    const auto load_dir = system.GetFileSystemController().GetModificationLoadRoot(title_id); +    const BuildID& build_id_) const { +    const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);      if (load_dir == nullptr) {          LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);          return {}; @@ -347,9 +343,9 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(      return out;  } -static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) { -    const auto load_dir = -        Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id); +static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type, +                           const Service::FileSystem::FileSystemController& fs_controller) { +    const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);      if ((type != ContentRecordType::Program && type != ContentRecordType::Data) ||          load_dir == nullptr || load_dir->GetSize() <= 0) {          return; @@ -411,19 +407,19 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content      const auto log_string = fmt::format("Patching RomFS for title_id={:016X}, type={:02X}",                                          title_id, static_cast<u8>(type)); -    if (type == ContentRecordType::Program || type == ContentRecordType::Data) +    if (type == ContentRecordType::Program || type == ContentRecordType::Data) {          LOG_INFO(Loader, "{}", log_string); -    else +    } else {          LOG_DEBUG(Loader, "{}", log_string); +    } -    if (romfs == nullptr) +    if (romfs == nullptr) {          return romfs; - -    const auto& installed = Core::System::GetInstance().GetContentProvider(); +    }      // Game Updates      const auto update_tid = GetUpdateTitleID(title_id); -    const auto update = installed.GetEntryRaw(update_tid, type); +    const auto update = content_provider.GetEntryRaw(update_tid, type);      const auto& disabled = Settings::values.disabled_addons[title_id];      const auto update_disabled = @@ -434,7 +430,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content          if (new_nca->GetStatus() == Loader::ResultStatus::Success &&              new_nca->GetRomFS() != nullptr) {              LOG_INFO(Loader, "    RomFS: Update ({}) applied successfully", -                     FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0))); +                     FormatTitleVersion(content_provider.GetEntryVersion(update_tid).value_or(0)));              romfs = new_nca->GetRomFS();          }      } else if (!update_disabled && update_raw != nullptr) { @@ -447,7 +443,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content      }      // LayeredFS -    ApplyLayeredFS(romfs, title_id, type); +    ApplyLayeredFS(romfs, title_id, type, fs_controller);      return romfs;  } @@ -458,12 +454,11 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u      }      std::map<std::string, std::string, std::less<>> out; -    const auto& installed = Core::System::GetInstance().GetContentProvider();      const auto& disabled = Settings::values.disabled_addons[title_id];      // Game Updates      const auto update_tid = GetUpdateTitleID(title_id); -    PatchManager update{update_tid}; +    PatchManager update{update_tid, fs_controller, content_provider};      const auto metadata = update.GetControlMetadata();      const auto& nacp = metadata.first; @@ -474,8 +469,8 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u      if (nacp != nullptr) {          out.insert_or_assign(update_label, nacp->GetVersionString());      } else { -        if (installed.HasEntry(update_tid, ContentRecordType::Program)) { -            const auto meta_ver = installed.GetEntryVersion(update_tid); +        if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) { +            const auto meta_ver = content_provider.GetEntryVersion(update_tid);              if (meta_ver.value_or(0) == 0) {                  out.insert_or_assign(update_label, "");              } else { @@ -487,8 +482,7 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u      }      // General Mods (LayeredFS and IPS) -    const auto mod_dir = -        Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id); +    const auto mod_dir = fs_controller.GetModificationLoadRoot(title_id);      if (mod_dir != nullptr && mod_dir->GetSize() > 0) {          for (const auto& mod : mod_dir->GetSubdirectories()) {              std::string types; @@ -532,13 +526,15 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u      }      // DLC -    const auto dlc_entries = installed.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data); +    const auto dlc_entries = +        content_provider.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);      std::vector<ContentProviderEntry> dlc_match;      dlc_match.reserve(dlc_entries.size());      std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match), -                 [this, &installed](const ContentProviderEntry& entry) { +                 [this](const ContentProviderEntry& entry) {                       return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id && -                            installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success; +                            content_provider.GetEntry(entry)->GetStatus() == +                                Loader::ResultStatus::Success;                   });      if (!dlc_match.empty()) {          // Ensure sorted so DLC IDs show in order. @@ -559,19 +555,16 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u  }  std::optional<u32> PatchManager::GetGameVersion() const { -    const auto& installed = Core::System::GetInstance().GetContentProvider();      const auto update_tid = GetUpdateTitleID(title_id); -    if (installed.HasEntry(update_tid, ContentRecordType::Program)) { -        return installed.GetEntryVersion(update_tid); +    if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) { +        return content_provider.GetEntryVersion(update_tid);      } -    return installed.GetEntryVersion(title_id); +    return content_provider.GetEntryVersion(title_id);  }  PatchManager::Metadata PatchManager::GetControlMetadata() const { -    const auto& installed = Core::System::GetInstance().GetContentProvider(); - -    const auto base_control_nca = installed.GetEntry(title_id, ContentRecordType::Control); +    const auto base_control_nca = content_provider.GetEntry(title_id, ContentRecordType::Control);      if (base_control_nca == nullptr) {          return {};      } diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h index 1f28c6241..fb1853035 100644 --- a/src/core/file_sys/patch_manager.h +++ b/src/core/file_sys/patch_manager.h @@ -17,8 +17,13 @@ namespace Core {  class System;  } +namespace Service::FileSystem { +class FileSystemController; +} +  namespace FileSys { +class ContentProvider;  class NCA;  class NACP; @@ -29,7 +34,9 @@ public:      using Metadata = std::pair<std::unique_ptr<NACP>, VirtualFile>;      using PatchVersionNames = std::map<std::string, std::string, std::less<>>; -    explicit PatchManager(u64 title_id); +    explicit PatchManager(u64 title_id_, +                          const Service::FileSystem::FileSystemController& fs_controller_, +                          const ContentProvider& content_provider_);      ~PatchManager();      [[nodiscard]] u64 GetTitleID() const; @@ -50,7 +57,7 @@ public:      // Creates a CheatList object with all      [[nodiscard]] std::vector<Core::Memory::CheatEntry> CreateCheatList( -        const Core::System& system, const BuildID& build_id) const; +        const BuildID& build_id) const;      // Currently tracked RomFS patches:      // - Game Updates @@ -80,6 +87,8 @@ private:                                                            const std::string& build_id) const;      u64 title_id; +    const Service::FileSystem::FileSystemController& fs_controller; +    const ContentProvider& content_provider;  };  } // namespace FileSys diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp index e967a254e..987199747 100644 --- a/src/core/file_sys/romfs_factory.cpp +++ b/src/core/file_sys/romfs_factory.cpp @@ -37,10 +37,12 @@ void RomFSFactory::SetPackedUpdate(VirtualFile update_raw) {  }  ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const { -    if (!updatable) +    if (!updatable) {          return MakeResult<VirtualFile>(file); +    } -    const PatchManager patch_manager(current_process_title_id); +    const PatchManager patch_manager{current_process_title_id, filesystem_controller, +                                     content_provider};      return MakeResult<VirtualFile>(          patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw));  } diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp index 90641d23b..c05735ddd 100644 --- a/src/core/file_sys/submission_package.cpp +++ b/src/core/file_sys/submission_package.cpp @@ -20,8 +20,8 @@  namespace FileSys { -NSP::NSP(VirtualFile file_) -    : file(std::move(file_)), status{Loader::ResultStatus::Success}, +NSP::NSP(VirtualFile file_, std::size_t program_index) +    : file(std::move(file_)), program_index(program_index), status{Loader::ResultStatus::Success},        pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} {      if (pfs->GetStatus() != Loader::ResultStatus::Success) {          status = pfs->GetStatus(); @@ -146,7 +146,7 @@ std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type, TitleType      if (extracted)          LOG_WARNING(Service_FS, "called on an NSP that is of type extracted."); -    const auto title_id_iter = ncas.find(title_id); +    const auto title_id_iter = ncas.find(title_id + program_index);      if (title_id_iter == ncas.end())          return nullptr; diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h index c70a11b5b..54581a6f3 100644 --- a/src/core/file_sys/submission_package.h +++ b/src/core/file_sys/submission_package.h @@ -27,7 +27,7 @@ enum class ContentRecordType : u8;  class NSP : public ReadOnlyVfsDirectory {  public: -    explicit NSP(VirtualFile file); +    explicit NSP(VirtualFile file, std::size_t program_index = 0);      ~NSP() override;      Loader::ResultStatus GetStatus() const; @@ -69,6 +69,8 @@ private:      VirtualFile file; +    const std::size_t program_index; +      bool extracted = false;      Loader::ResultStatus status;      std::map<u64, Loader::ResultStatus> program_status; diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index 5582091f4..03bbedf8b 100644 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp @@ -27,19 +27,19 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb              ->GetAppletResource()              ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad); -    auto& players = Settings::values.players; +    auto& players = Settings::values.players.GetValue();      const std::size_t min_supported_players =          parameters.enable_single_mode ? 1 : parameters.min_players;      // Disconnect Handheld first. -    npad.DisconnectNPadAtIndex(8); +    npad.DisconnectNpadAtIndex(8);      // Deduce the best configuration based on the input parameters.      for (std::size_t index = 0; index < players.size() - 2; ++index) {          // First, disconnect all controllers regardless of the value of keep_controllers_connected.          // This makes it easy to connect the desired controllers. -        npad.DisconnectNPadAtIndex(index); +        npad.DisconnectNpadAtIndex(index);          // Only connect the minimum number of required players.          if (index >= min_supported_players) { @@ -66,7 +66,7 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb                      npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index);              }          } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && -                   !Settings::values.use_docked_mode) { +                   !Settings::values.use_docked_mode.GetValue()) {              // We should *never* reach here under any normal circumstances.              npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld),                                      index); diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index 1acc82497..b9a270a55 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp @@ -47,7 +47,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) {  FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {      u32 width, height; -    if (Settings::values.use_docked_mode) { +    if (Settings::values.use_docked_mode.GetValue()) {          width = ScreenDocked::Width * res_scale;          height = ScreenDocked::Height * res_scale;      } else { diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index 277b70e53..11c2e96ca 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h @@ -30,10 +30,12 @@ public:      virtual StatusType GetStatus() const {          return {};      } -    virtual bool GetAnalogDirectionStatus(AnalogDirection direction) const { +    virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const {          return {};      } -    virtual bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const { +    virtual bool SetRumblePlay([[maybe_unused]] f32 amp_low, [[maybe_unused]] f32 freq_low, +                               [[maybe_unused]] f32 amp_high, +                               [[maybe_unused]] f32 freq_high) const {          return {};      }  }; @@ -122,6 +124,13 @@ using ButtonDevice = InputDevice<bool>;  using AnalogDevice = InputDevice<std::tuple<float, float>>;  /** + * A vibration device is an input device that returns an unsigned byte as status. + * It represents whether the vibration device supports vibration or not. + * If the status returns 1, it supports vibration. Otherwise, it does not support vibration. + */ +using VibrationDevice = InputDevice<u8>; + +/**   * A motion status is an object that returns a tuple of accelerometer state vector,   * gyroscope state vector, rotation state vector and orientation state matrix.   * diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 1c354037d..d57776ce9 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -12,7 +12,6 @@  #include <utility>  #include "common/assert.h"  #include "common/common_types.h" -#include "core/core.h"  #include "core/hle/ipc.h"  #include "core/hle/kernel/client_port.h"  #include "core/hle/kernel/client_session.h" @@ -73,14 +72,12 @@ public:          AlwaysMoveHandles = 1,      }; -    explicit ResponseBuilder(u32* command_buffer) : RequestHelperBase(command_buffer) {} -      explicit 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) { +          num_handles_to_copy(num_handles_to_copy), +          num_objects_to_move(num_objects_to_move), kernel{context.kernel} {          memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH); @@ -140,7 +137,6 @@ public:          if (context->Session()->IsDomain()) {              context->AddDomainObject(std::move(iface));          } else { -            auto& kernel = Core::System::GetInstance().Kernel();              auto [client, server] = Kernel::Session::Create(kernel, iface->GetServiceName());              context->AddMoveObject(std::move(client));              iface->ClientConnected(std::move(server)); @@ -214,6 +210,7 @@ private:      u32 num_handles_to_copy{};      u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent      std::ptrdiff_t datapayload_index{}; +    Kernel::KernelCore& kernel;  };  /// Push /// diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index f3277b766..c31a65476 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -24,6 +24,10 @@ namespace Core::Memory {  class Memory;  } +namespace IPC { +class ResponseBuilder; +} +  namespace Service {  class ServiceFrameworkBase;  } @@ -287,6 +291,8 @@ public:      }  private: +    friend class IPC::ResponseBuilder; +      void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);      std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index bafd1ced7..e3b770d66 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -681,7 +681,7 @@ static void Break32(Core::System& system, u32 reason, u32 info1, u32 info2) {  }  /// Used to output a message on a debug hardware unit - does nothing on a retail unit -static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr address, u64 len) { +static void OutputDebugString(Core::System& system, VAddr address, u64 len) {      if (len == 0) {          return;      } diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 2850dd805..c2c11dbcb 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -11,6 +11,7 @@  #include "common/string_util.h"  #include "common/swap.h"  #include "core/constants.h" +#include "core/core.h"  #include "core/core_timing.h"  #include "core/file_sys/control_metadata.h"  #include "core/file_sys/patch_manager.h" @@ -741,8 +742,10 @@ void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx      bool is_locked = false;      if (res != Loader::ResultStatus::Success) { -        FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()}; -        auto nacp_unique = pm.GetControlMetadata().first; +        const FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID(), +                                       system.GetFileSystemController(), +                                       system.GetContentProvider()}; +        const auto nacp_unique = pm.GetControlMetadata().first;          if (nacp_unique != nullptr) {              is_locked = nacp_unique->GetUserAccountSwitchLock(); diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 2ce742e35..703a9b234 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -246,9 +246,8 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} {  IDebugFunctions::~IDebugFunctions() = default; -ISelfController::ISelfController(Core::System& system, -                                 std::shared_ptr<NVFlinger::NVFlinger> nvflinger) -    : ServiceFramework("ISelfController"), system(system), nvflinger(std::move(nvflinger)) { +ISelfController::ISelfController(Core::System& system, NVFlinger::NVFlinger& nvflinger) +    : ServiceFramework("ISelfController"), system(system), nvflinger(nvflinger) {      // clang-format off      static const FunctionInfo functions[] = {          {0, &ISelfController::Exit, "Exit"}, @@ -458,8 +457,8 @@ void ISelfController::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. -    const auto display_id = nvflinger->OpenDisplay("Default"); -    const auto layer_id = nvflinger->CreateLayer(*display_id); +    const auto display_id = nvflinger.OpenDisplay("Default"); +    const auto layer_id = nvflinger.CreateLayer(*display_id);      IPC::ResponseBuilder rb{ctx, 4};      rb.Push(RESULT_SUCCESS); @@ -476,8 +475,8 @@ void ISelfController::CreateManagedDisplaySeparableLayer(Kernel::HLERequestConte      // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse      // side effects.      // TODO: Support multiple layers -    const auto display_id = nvflinger->OpenDisplay("Default"); -    const auto layer_id = nvflinger->CreateLayer(*display_id); +    const auto display_id = nvflinger.OpenDisplay("Default"); +    const auto layer_id = nvflinger.CreateLayer(*display_id);      IPC::ResponseBuilder rb{ctx, 4};      rb.Push(RESULT_SUCCESS); @@ -751,7 +750,7 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext&      IPC::ResponseBuilder rb{ctx, 4};      rb.Push(RESULT_SUCCESS); -    if (Settings::values.use_docked_mode) { +    if (Settings::values.use_docked_mode.GetValue()) {          rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *                  static_cast<u32>(Settings::values.resolution_factor.GetValue()));          rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) * @@ -824,7 +823,7 @@ void IStorage::Open(Kernel::HLERequestContext& ctx) {  }  void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { -    const bool use_docked_mode{Settings::values.use_docked_mode}; +    const bool use_docked_mode{Settings::values.use_docked_mode.GetValue()};      LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);      IPC::ResponseBuilder rb{ctx, 3}; @@ -1189,9 +1188,9 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)          {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"},          {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"},          {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"}, -        {120, nullptr, "ExecuteProgram"}, -        {121, nullptr, "ClearUserChannel"}, -        {122, nullptr, "UnpopToUserChannel"}, +        {120, &IApplicationFunctions::ExecuteProgram, "ExecuteProgram"}, +        {121, &IApplicationFunctions::ClearUserChannel, "ClearUserChannel"}, +        {122, &IApplicationFunctions::UnpopToUserChannel, "UnpopToUserChannel"},          {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"},          {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},          {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, @@ -1381,13 +1380,16 @@ void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) {      const auto res = [this] {          const auto title_id = system.CurrentProcess()->GetTitleID(); -        FileSys::PatchManager pm{title_id}; +        const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), +                                       system.GetContentProvider()};          auto res = pm.GetControlMetadata();          if (res.first != nullptr) {              return res;          } -        FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id)}; +        const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), +                                              system.GetFileSystemController(), +                                              system.GetContentProvider()};          return pm_update.GetControlMetadata();      }(); @@ -1415,13 +1417,16 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {      const auto res = [this] {          const auto title_id = system.CurrentProcess()->GetTitleID(); -        FileSys::PatchManager pm{title_id}; +        const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), +                                       system.GetContentProvider()};          auto res = pm.GetControlMetadata();          if (res.first != nullptr) {              return res;          } -        FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id)}; +        const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), +                                              system.GetFileSystemController(), +                                              system.GetContentProvider()};          return pm_update.GetControlMetadata();      }(); @@ -1556,6 +1561,34 @@ void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLEReque      rb.Push<u32>(0);  } +void IApplicationFunctions::ExecuteProgram(Kernel::HLERequestContext& ctx) { +    LOG_WARNING(Service_AM, "(STUBBED) called"); + +    IPC::RequestParser rp{ctx}; +    [[maybe_unused]] const auto unk_1 = rp.Pop<u32>(); +    [[maybe_unused]] const auto unk_2 = rp.Pop<u32>(); +    const auto program_index = rp.Pop<u64>(); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(RESULT_SUCCESS); + +    system.ExecuteProgram(program_index); +} + +void IApplicationFunctions::ClearUserChannel(Kernel::HLERequestContext& ctx) { +    LOG_WARNING(Service_AM, "(STUBBED) called"); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(RESULT_SUCCESS); +} + +void IApplicationFunctions::UnpopToUserChannel(Kernel::HLERequestContext& ctx) { +    LOG_WARNING(Service_AM, "(STUBBED) called"); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(RESULT_SUCCESS); +} +  void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) {      LOG_WARNING(Service_AM, "(STUBBED) called"); @@ -1580,8 +1613,8 @@ void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERe      rb.PushCopyObjects(friend_invitation_storage_channel_event.readable);  } -void InstallInterfaces(SM::ServiceManager& service_manager, -                       std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system) { +void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, +                       Core::System& system) {      auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel());      // Needed on game boot      message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index bcc06affe..af97c303a 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -121,8 +121,7 @@ public:  class ISelfController final : public ServiceFramework<ISelfController> {  public: -    explicit ISelfController(Core::System& system_, -                             std::shared_ptr<NVFlinger::NVFlinger> nvflinger_); +    explicit ISelfController(Core::System& system_, NVFlinger::NVFlinger& nvflinger_);      ~ISelfController() override;  private: @@ -156,7 +155,7 @@ private:      };      Core::System& system; -    std::shared_ptr<NVFlinger::NVFlinger> nvflinger; +    NVFlinger::NVFlinger& nvflinger;      Kernel::EventPair launchable_event;      Kernel::EventPair accumulated_suspended_tick_changed_event; @@ -288,6 +287,9 @@ private:      void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx);      void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx);      void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx); +    void ExecuteProgram(Kernel::HLERequestContext& ctx); +    void ClearUserChannel(Kernel::HLERequestContext& ctx); +    void UnpopToUserChannel(Kernel::HLERequestContext& ctx);      void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx);      void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx);      void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx); @@ -332,7 +334,7 @@ public:  };  /// Registers all AM services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager, -                       std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system); +void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, +                       Core::System& system);  } // namespace Service::AM diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index 9df286d17..7de506b70 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp @@ -3,8 +3,8 @@  // Refer to the license.txt file included.  #include "common/logging/log.h" +#include "core/core.h"  #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/process.h"  #include "core/hle/service/am/am.h"  #include "core/hle/service/am/applet_ae.h"  #include "core/hle/service/nvflinger/nvflinger.h" @@ -13,10 +13,10 @@ namespace Service::AM {  class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {  public: -    explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, +    explicit ILibraryAppletProxy(NVFlinger::NVFlinger& nvflinger,                                   std::shared_ptr<AppletMessageQueue> msg_queue,                                   Core::System& system) -        : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)), +        : ServiceFramework("ILibraryAppletProxy"), nvflinger(nvflinger),            msg_queue(std::move(msg_queue)), system(system) {          // clang-format off          static const FunctionInfo functions[] = { @@ -109,16 +109,16 @@ private:          rb.PushIpcInterface<IApplicationFunctions>(system);      } -    std::shared_ptr<NVFlinger::NVFlinger> nvflinger; +    NVFlinger::NVFlinger& nvflinger;      std::shared_ptr<AppletMessageQueue> msg_queue;      Core::System& system;  };  class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {  public: -    explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, +    explicit ISystemAppletProxy(NVFlinger::NVFlinger& nvflinger,                                  std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system) -        : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)), +        : ServiceFramework("ISystemAppletProxy"), nvflinger(nvflinger),            msg_queue(std::move(msg_queue)), system(system) {          // clang-format off          static const FunctionInfo functions[] = { @@ -220,7 +220,8 @@ private:          rb.Push(RESULT_SUCCESS);          rb.PushIpcInterface<IApplicationCreator>();      } -    std::shared_ptr<NVFlinger::NVFlinger> nvflinger; + +    NVFlinger::NVFlinger& nvflinger;      std::shared_ptr<AppletMessageQueue> msg_queue;      Core::System& system;  }; @@ -249,10 +250,10 @@ void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {      rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system);  } -AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, -                   std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system) -    : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)), -      msg_queue(std::move(msg_queue)), system(system) { +AppletAE::AppletAE(NVFlinger::NVFlinger& nvflinger, std::shared_ptr<AppletMessageQueue> msg_queue, +                   Core::System& system) +    : ServiceFramework("appletAE"), nvflinger(nvflinger), msg_queue(std::move(msg_queue)), +      system(system) {      // clang-format off      static const FunctionInfo functions[] = {          {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h index 2e3e45915..761844a1f 100644 --- a/src/core/hle/service/am/applet_ae.h +++ b/src/core/hle/service/am/applet_ae.h @@ -23,7 +23,7 @@ class AppletMessageQueue;  class AppletAE final : public ServiceFramework<AppletAE> {  public: -    explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, +    explicit AppletAE(NVFlinger::NVFlinger& nvflinger,                        std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system);      ~AppletAE() override; @@ -34,7 +34,7 @@ private:      void OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx);      void OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx); -    std::shared_ptr<NVFlinger::NVFlinger> nvflinger; +    NVFlinger::NVFlinger& nvflinger;      std::shared_ptr<AppletMessageQueue> msg_queue;      Core::System& system;  }; diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index a2ffaa440..7bed86ec4 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp @@ -12,9 +12,9 @@ namespace Service::AM {  class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {  public: -    explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, +    explicit IApplicationProxy(NVFlinger::NVFlinger& nvflinger,                                 std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system) -        : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)), +        : ServiceFramework("IApplicationProxy"), nvflinger(nvflinger),            msg_queue(std::move(msg_queue)), system(system) {          // clang-format off          static const FunctionInfo functions[] = { @@ -98,7 +98,7 @@ private:          rb.PushIpcInterface<IApplicationFunctions>(system);      } -    std::shared_ptr<NVFlinger::NVFlinger> nvflinger; +    NVFlinger::NVFlinger& nvflinger;      std::shared_ptr<AppletMessageQueue> msg_queue;      Core::System& system;  }; @@ -111,10 +111,10 @@ void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {      rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue, system);  } -AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, -                   std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system) -    : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)), -      msg_queue(std::move(msg_queue)), system(system) { +AppletOE::AppletOE(NVFlinger::NVFlinger& nvflinger, std::shared_ptr<AppletMessageQueue> msg_queue, +                   Core::System& system) +    : ServiceFramework("appletOE"), nvflinger(nvflinger), msg_queue(std::move(msg_queue)), +      system(system) {      static const FunctionInfo functions[] = {          {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},      }; diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h index 758da792d..88906d354 100644 --- a/src/core/hle/service/am/applet_oe.h +++ b/src/core/hle/service/am/applet_oe.h @@ -23,7 +23,7 @@ class AppletMessageQueue;  class AppletOE final : public ServiceFramework<AppletOE> {  public: -    explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, +    explicit AppletOE(NVFlinger::NVFlinger& nvflinger,                        std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system);      ~AppletOE() override; @@ -32,7 +32,7 @@ public:  private:      void OpenApplicationProxy(Kernel::HLERequestContext& ctx); -    std::shared_ptr<NVFlinger::NVFlinger> nvflinger; +    NVFlinger::NVFlinger& nvflinger;      std::shared_ptr<AppletMessageQueue> msg_queue;      Core::System& system;  }; diff --git a/src/core/hle/service/am/applets/controller.cpp b/src/core/hle/service/am/applets/controller.cpp index 2151da783..3ca63f020 100644 --- a/src/core/hle/service/am/applets/controller.cpp +++ b/src/core/hle/service/am/applets/controller.cpp @@ -25,7 +25,7 @@ namespace Service::AM::Applets {  static Core::Frontend::ControllerParameters ConvertToFrontendParameters(      ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text,      std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) { -    HID::Controller_NPad::NPadType npad_style_set; +    HID::Controller_NPad::NpadStyleSet npad_style_set;      npad_style_set.raw = private_arg.style_set;      return { @@ -62,7 +62,7 @@ void Controller::Initialize() {                common_args.play_startup_sound, common_args.size, common_args.system_tick,                common_args.theme_color); -    library_applet_version = LibraryAppletVersion{common_args.library_version}; +    controller_applet_version = ControllerAppletVersion{common_args.library_version};      const auto private_arg_storage = broker.PopNormalDataToApplet();      ASSERT(private_arg_storage != nullptr); @@ -70,39 +70,78 @@ void Controller::Initialize() {      const auto& private_arg = private_arg_storage->GetData();      ASSERT(private_arg.size() == sizeof(ControllerSupportArgPrivate)); -    std::memcpy(&controller_private_arg, private_arg.data(), sizeof(ControllerSupportArgPrivate)); +    std::memcpy(&controller_private_arg, private_arg.data(), private_arg.size());      ASSERT_MSG(controller_private_arg.arg_private_size == sizeof(ControllerSupportArgPrivate),                 "Unknown ControllerSupportArgPrivate revision={} with size={}", -               library_applet_version, controller_private_arg.arg_private_size); +               controller_applet_version, controller_private_arg.arg_private_size); + +    // Some games such as Cave Story+ set invalid values for the ControllerSupportMode. +    // Defer to arg_size to set the ControllerSupportMode. +    if (controller_private_arg.mode >= ControllerSupportMode::MaxControllerSupportMode) { +        switch (controller_private_arg.arg_size) { +        case sizeof(ControllerSupportArgOld): +        case sizeof(ControllerSupportArgNew): +            controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport; +            break; +        case sizeof(ControllerUpdateFirmwareArg): +            controller_private_arg.mode = ControllerSupportMode::ShowControllerFirmwareUpdate; +            break; +        default: +            UNIMPLEMENTED_MSG("Unknown ControllerPrivateArg mode={} with arg_size={}", +                              controller_private_arg.mode, controller_private_arg.arg_size); +            controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport; +            break; +        } +    } + +    // Some games such as Cave Story+ set invalid values for the ControllerSupportCaller. +    // This is always 0 (Application) except with ShowControllerFirmwareUpdateForSystem. +    if (controller_private_arg.caller >= ControllerSupportCaller::MaxControllerSupportCaller) { +        if (controller_private_arg.flag_1 && +            controller_private_arg.mode == ControllerSupportMode::ShowControllerFirmwareUpdate) { +            controller_private_arg.caller = ControllerSupportCaller::System; +        } else { +            controller_private_arg.caller = ControllerSupportCaller::Application; +        } +    }      switch (controller_private_arg.mode) { -    case ControllerSupportMode::ShowControllerSupport: { +    case ControllerSupportMode::ShowControllerSupport: +    case ControllerSupportMode::ShowControllerStrapGuide: {          const auto user_arg_storage = broker.PopNormalDataToApplet();          ASSERT(user_arg_storage != nullptr);          const auto& user_arg = user_arg_storage->GetData(); -        switch (library_applet_version) { -        case LibraryAppletVersion::Version3: -        case LibraryAppletVersion::Version4: -        case LibraryAppletVersion::Version5: +        switch (controller_applet_version) { +        case ControllerAppletVersion::Version3: +        case ControllerAppletVersion::Version4: +        case ControllerAppletVersion::Version5:              ASSERT(user_arg.size() == sizeof(ControllerSupportArgOld)); -            std::memcpy(&controller_user_arg_old, user_arg.data(), sizeof(ControllerSupportArgOld)); +            std::memcpy(&controller_user_arg_old, user_arg.data(), user_arg.size());              break; -        case LibraryAppletVersion::Version7: +        case ControllerAppletVersion::Version7:              ASSERT(user_arg.size() == sizeof(ControllerSupportArgNew)); -            std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew)); +            std::memcpy(&controller_user_arg_new, user_arg.data(), user_arg.size());              break;          default:              UNIMPLEMENTED_MSG("Unknown ControllerSupportArg revision={} with size={}", -                              library_applet_version, controller_private_arg.arg_size); +                              controller_applet_version, controller_private_arg.arg_size);              ASSERT(user_arg.size() >= sizeof(ControllerSupportArgNew));              std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew));              break;          }          break;      } -    case ControllerSupportMode::ShowControllerStrapGuide: -    case ControllerSupportMode::ShowControllerFirmwareUpdate: +    case ControllerSupportMode::ShowControllerFirmwareUpdate: { +        const auto update_arg_storage = broker.PopNormalDataToApplet(); +        ASSERT(update_arg_storage != nullptr); + +        const auto& update_arg = update_arg_storage->GetData(); +        ASSERT(update_arg.size() == sizeof(ControllerUpdateFirmwareArg)); + +        std::memcpy(&controller_update_arg, update_arg.data(), update_arg.size()); +        break; +    }      default: {          UNIMPLEMENTED_MSG("Unimplemented ControllerSupportMode={}", controller_private_arg.mode);          break; @@ -126,10 +165,10 @@ void Controller::Execute() {      switch (controller_private_arg.mode) {      case ControllerSupportMode::ShowControllerSupport: {          const auto parameters = [this] { -            switch (library_applet_version) { -            case LibraryAppletVersion::Version3: -            case LibraryAppletVersion::Version4: -            case LibraryAppletVersion::Version5: +            switch (controller_applet_version) { +            case ControllerAppletVersion::Version3: +            case ControllerAppletVersion::Version4: +            case ControllerAppletVersion::Version5:                  return ConvertToFrontendParameters(                      controller_private_arg, controller_user_arg_old.header,                      controller_user_arg_old.enable_explain_text, @@ -138,7 +177,7 @@ void Controller::Execute() {                          controller_user_arg_old.identification_colors.end()),                      std::vector<ExplainText>(controller_user_arg_old.explain_text.begin(),                                               controller_user_arg_old.explain_text.end())); -            case LibraryAppletVersion::Version7: +            case ControllerAppletVersion::Version7:              default:                  return ConvertToFrontendParameters(                      controller_private_arg, controller_user_arg_new.header, @@ -170,6 +209,9 @@ void Controller::Execute() {      }      case ControllerSupportMode::ShowControllerStrapGuide:      case ControllerSupportMode::ShowControllerFirmwareUpdate: +        UNIMPLEMENTED_MSG("ControllerSupportMode={} is not implemented", +                          controller_private_arg.mode); +        [[fallthrough]];      default: {          ConfigurationComplete();          break; @@ -180,7 +222,7 @@ void Controller::Execute() {  void Controller::ConfigurationComplete() {      ControllerSupportResultInfo result_info{}; -    const auto& players = Settings::values.players; +    const auto& players = Settings::values.players.GetValue();      // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters.      // Otherwise, only count connected players from P1-P8. diff --git a/src/core/hle/service/am/applets/controller.h b/src/core/hle/service/am/applets/controller.h index f7bb3fba9..a7a1f2b65 100644 --- a/src/core/hle/service/am/applets/controller.h +++ b/src/core/hle/service/am/applets/controller.h @@ -21,7 +21,7 @@ namespace Service::AM::Applets {  using IdentificationColor = std::array<u8, 4>;  using ExplainText = std::array<char, 0x81>; -enum class LibraryAppletVersion : u32_le { +enum class ControllerAppletVersion : u32_le {      Version3 = 0x3, // 1.0.0 - 2.3.0      Version4 = 0x4, // 3.0.0 - 5.1.0      Version5 = 0x5, // 6.0.0 - 7.0.1 @@ -29,14 +29,18 @@ enum class LibraryAppletVersion : u32_le {  };  enum class ControllerSupportMode : u8 { -    ShowControllerSupport = 0, -    ShowControllerStrapGuide = 1, -    ShowControllerFirmwareUpdate = 2, +    ShowControllerSupport, +    ShowControllerStrapGuide, +    ShowControllerFirmwareUpdate, + +    MaxControllerSupportMode,  };  enum class ControllerSupportCaller : u8 { -    Application = 0, -    System = 1, +    Application, +    System, + +    MaxControllerSupportCaller,  };  struct ControllerSupportArgPrivate { @@ -84,6 +88,13 @@ struct ControllerSupportArgNew {  static_assert(sizeof(ControllerSupportArgNew) == 0x430,                "ControllerSupportArgNew has incorrect size."); +struct ControllerUpdateFirmwareArg { +    bool enable_force_update{}; +    INSERT_PADDING_BYTES(3); +}; +static_assert(sizeof(ControllerUpdateFirmwareArg) == 0x4, +              "ControllerUpdateFirmwareArg has incorrect size."); +  struct ControllerSupportResultInfo {      s8 player_count{};      INSERT_PADDING_BYTES(3); @@ -110,10 +121,11 @@ public:  private:      const Core::Frontend::ControllerApplet& frontend; -    LibraryAppletVersion library_applet_version; +    ControllerAppletVersion controller_applet_version;      ControllerSupportArgPrivate controller_private_arg;      ControllerSupportArgOld controller_user_arg_old;      ControllerSupportArgNew controller_user_arg_new; +    ControllerUpdateFirmwareArg controller_update_arg;      bool complete{false};      ResultCode status{RESULT_SUCCESS};      bool is_single_mode{false}; diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 8e79f707b..173b36da4 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp @@ -6,6 +6,7 @@  #include <numeric>  #include <vector>  #include "common/logging/log.h" +#include "core/core.h"  #include "core/file_sys/content_archive.h"  #include "core/file_sys/control_metadata.h"  #include "core/file_sys/nca_metadata.h" @@ -163,7 +164,8 @@ void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {      rb.Push(RESULT_SUCCESS);      const auto title_id = system.CurrentProcess()->GetTitleID(); -    FileSys::PatchManager pm{title_id}; +    const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), +                                   system.GetContentProvider()};      const auto res = pm.GetControlMetadata();      if (res.first == nullptr) { diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp index 85bbf5988..e2d8f0027 100644 --- a/src/core/hle/service/apm/apm.cpp +++ b/src/core/hle/service/apm/apm.cpp @@ -2,6 +2,7 @@  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. +#include "core/core.h"  #include "core/hle/ipc_helpers.h"  #include "core/hle/service/apm/apm.h"  #include "core/hle/service/apm/interface.h" diff --git a/src/core/hle/service/apm/controller.cpp b/src/core/hle/service/apm/controller.cpp index 25a886238..ce993bad3 100644 --- a/src/core/hle/service/apm/controller.cpp +++ b/src/core/hle/service/apm/controller.cpp @@ -69,7 +69,8 @@ void Controller::SetFromCpuBoostMode(CpuBoostMode mode) {  }  PerformanceMode Controller::GetCurrentPerformanceMode() const { -    return Settings::values.use_docked_mode ? PerformanceMode::Docked : PerformanceMode::Handheld; +    return Settings::values.use_docked_mode.GetValue() ? PerformanceMode::Docked +                                                       : PerformanceMode::Handheld;  }  PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) { diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index db0e06ca1..68deb0600 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -8,6 +8,7 @@  #include "common/hex_util.h"  #include "common/logging/log.h"  #include "common/string_util.h" +#include "core/core.h"  #include "core/file_sys/vfs.h"  #include "core/hle/ipc_helpers.h"  #include "core/hle/kernel/process.h" diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp index f311afa2f..d4f0dd1ab 100644 --- a/src/core/hle/service/btdrv/btdrv.cpp +++ b/src/core/hle/service/btdrv/btdrv.cpp @@ -3,6 +3,7 @@  // Refer to the license.txt file included.  #include "common/logging/log.h" +#include "core/core.h"  #include "core/hle/ipc_helpers.h"  #include "core/hle/kernel/hle_ipc.h"  #include "core/hle/kernel/kernel.h" diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp index 0d251c6d0..c8f8ddbd5 100644 --- a/src/core/hle/service/btm/btm.cpp +++ b/src/core/hle/service/btm/btm.cpp @@ -5,6 +5,7 @@  #include <memory>  #include "common/logging/log.h" +#include "core/core.h"  #include "core/hle/ipc_helpers.h"  #include "core/hle/kernel/hle_ipc.h"  #include "core/hle/kernel/kernel.h" diff --git a/src/core/hle/service/caps/caps_u.cpp b/src/core/hle/service/caps/caps_u.cpp index 8e2b83629..f9479bdb3 100644 --- a/src/core/hle/service/caps/caps_u.cpp +++ b/src/core/hle/service/caps/caps_u.cpp @@ -41,7 +41,7 @@ CAPS_U::CAPS_U() : ServiceFramework("caps:u") {          {130, nullptr, "PrecheckToCreateContentsForApplication"},          {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"},          {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"}, -        {142, nullptr, "GetAlbumFileList3AaeAruid"}, +        {142, &CAPS_U::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"},          {143, nullptr, "GetAlbumFileList4AaeUidAruid"},          {60002, nullptr, "OpenAccessorSessionForApplication"},      }; @@ -77,17 +77,24 @@ void CAPS_U::GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& c      // TODO: Update this when we implement the album.      // Currently we do not have a method of accessing album entries, set this to 0 for now. -    constexpr s32 total_entries{0}; +    constexpr u32 total_entries_1{}; +    constexpr u32 total_entries_2{}; -    LOG_WARNING(Service_Capture, -                "(STUBBED) called. pid={}, content_type={}, start_posix_time={}, " -                "end_posix_time={}, applet_resource_user_id={}, total_entries={}", -                pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id, -                total_entries); +    LOG_WARNING( +        Service_Capture, +        "(STUBBED) called. pid={}, content_type={}, start_posix_time={}, " +        "end_posix_time={}, applet_resource_user_id={}, total_entries_1={}, total_entries_2={}", +        pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id, +        total_entries_1, total_entries_2); -    IPC::ResponseBuilder rb{ctx, 3}; +    IPC::ResponseBuilder rb{ctx, 4};      rb.Push(RESULT_SUCCESS); -    rb.Push(total_entries); +    rb.Push(total_entries_1); +    rb.Push(total_entries_2); +} + +void CAPS_U::GetAlbumFileList3AaeAruid(Kernel::HLERequestContext& ctx) { +    GetAlbumContentsFileListForApplication(ctx);  }  } // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_u.h b/src/core/hle/service/caps/caps_u.h index e04e56bbc..4b80f3156 100644 --- a/src/core/hle/service/caps/caps_u.h +++ b/src/core/hle/service/caps/caps_u.h @@ -20,6 +20,7 @@ public:  private:      void SetShimLibraryVersion(Kernel::HLERequestContext& ctx);      void GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx); +    void GetAlbumFileList3AaeAruid(Kernel::HLERequestContext& ctx);  };  } // namespace Service::Capture diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 3cdef4888..2e53cae5b 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -455,7 +455,9 @@ FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataTy          const auto res = system.GetAppLoader().ReadControlData(nacp);          if (res != Loader::ResultStatus::Success) { -            FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()}; +            const FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID(), +                                           system.GetFileSystemController(), +                                           system.GetContentProvider()};              const auto metadata = pm.GetControlMetadata();              const auto& nacp_unique = metadata.first; @@ -728,7 +730,8 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove  void InstallInterfaces(Core::System& system) {      std::make_shared<FSP_LDR>()->InstallAsService(system.ServiceManager());      std::make_shared<FSP_PR>()->InstallAsService(system.ServiceManager()); -    std::make_shared<FSP_SRV>(system.GetFileSystemController(), system.GetReporter()) +    std::make_shared<FSP_SRV>(system.GetFileSystemController(), system.GetContentProvider(), +                              system.GetReporter())          ->InstallAsService(system.ServiceManager());  } diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 649128be4..031c6dbf6 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -650,8 +650,10 @@ private:      u64 next_entry_index = 0;  }; -FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter) -    : ServiceFramework("fsp-srv"), fsc(fsc), reporter(reporter) { +FSP_SRV::FSP_SRV(FileSystemController& fsc_, const FileSys::ContentProvider& content_provider_, +                 const Core::Reporter& reporter_) +    : ServiceFramework("fsp-srv"), fsc(fsc_), content_provider{content_provider_}, +      reporter(reporter_) {      // clang-format off      static const FunctionInfo functions[] = {          {0, nullptr, "OpenFileSystem"}, @@ -968,7 +970,7 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {          return;      } -    FileSys::PatchManager pm{title_id}; +    const FileSys::PatchManager pm{title_id, fsc, content_provider};      auto storage = std::make_shared<IStorage>(          pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data)); diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index 4964e874e..6c7239e6a 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h @@ -12,8 +12,9 @@ class Reporter;  }  namespace FileSys { +class ContentProvider;  class FileSystemBackend; -} +} // namespace FileSys  namespace Service::FileSystem { @@ -32,7 +33,8 @@ enum class LogMode : u32 {  class FSP_SRV final : public ServiceFramework<FSP_SRV> {  public: -    explicit FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter); +    explicit FSP_SRV(FileSystemController& fsc_, const FileSys::ContentProvider& content_provider_, +                     const Core::Reporter& reporter_);      ~FSP_SRV() override;  private: @@ -55,6 +57,7 @@ private:      void OpenMultiCommitManager(Kernel::HLERequestContext& ctx);      FileSystemController& fsc; +    const FileSys::ContentProvider& content_provider;      FileSys::VirtualFile romfs;      u64 current_process_id = 0; diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index b7adaffc7..ebb323da2 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -5,6 +5,7 @@  #include <queue>  #include "common/logging/log.h"  #include "common/uuid.h" +#include "core/core.h"  #include "core/hle/ipc_helpers.h"  #include "core/hle/kernel/readable_event.h"  #include "core/hle/kernel/writable_event.h" diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp index b591ce31b..c6252ff89 100644 --- a/src/core/hle/service/glue/arp.cpp +++ b/src/core/hle/service/glue/arp.cpp @@ -5,6 +5,7 @@  #include <memory>  #include "common/logging/log.h" +#include "core/core.h"  #include "core/file_sys/control_metadata.h"  #include "core/hle/ipc_helpers.h"  #include "core/hle/kernel/hle_ipc.h" diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index e311bc18c..e2539ded8 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -117,7 +117,10 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) {  }  Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {} -Controller_NPad::~Controller_NPad() = default; + +Controller_NPad::~Controller_NPad() { +    OnRelease(); +}  void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {      const auto controller_type = connected_controllers[controller_idx].type; @@ -139,7 +142,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {          controller.properties.is_vertical.Assign(1);          controller.properties.use_plus.Assign(1);          controller.properties.use_minus.Assign(1); -        controller.pad_assignment = NPadAssignments::Single; +        controller.pad_assignment = NpadAssignments::Single;          break;      case NPadControllerType::Handheld:          controller.joy_styles.handheld.Assign(1); @@ -147,7 +150,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {          controller.properties.is_vertical.Assign(1);          controller.properties.use_plus.Assign(1);          controller.properties.use_minus.Assign(1); -        controller.pad_assignment = NPadAssignments::Dual; +        controller.pad_assignment = NpadAssignments::Dual;          break;      case NPadControllerType::JoyDual:          controller.joy_styles.joycon_dual.Assign(1); @@ -156,26 +159,26 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {          controller.properties.is_vertical.Assign(1);          controller.properties.use_plus.Assign(1);          controller.properties.use_minus.Assign(1); -        controller.pad_assignment = NPadAssignments::Dual; +        controller.pad_assignment = NpadAssignments::Dual;          break;      case NPadControllerType::JoyLeft:          controller.joy_styles.joycon_left.Assign(1);          controller.device_type.joycon_left.Assign(1);          controller.properties.is_horizontal.Assign(1);          controller.properties.use_minus.Assign(1); -        controller.pad_assignment = NPadAssignments::Single; +        controller.pad_assignment = NpadAssignments::Single;          break;      case NPadControllerType::JoyRight:          controller.joy_styles.joycon_right.Assign(1);          controller.device_type.joycon_right.Assign(1);          controller.properties.is_horizontal.Assign(1);          controller.properties.use_plus.Assign(1); -        controller.pad_assignment = NPadAssignments::Single; +        controller.pad_assignment = NpadAssignments::Single;          break;      case NPadControllerType::Pokeball:          controller.joy_styles.pokeball.Assign(1);          controller.device_type.pokeball.Assign(1); -        controller.pad_assignment = NPadAssignments::Single; +        controller.pad_assignment = NpadAssignments::Single;          break;      } @@ -184,11 +187,14 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {      controller.single_color.button_color = 0;      controller.dual_color_error = ColorReadError::ReadOk; -    controller.left_color.body_color = Settings::values.players[controller_idx].body_color_left; -    controller.left_color.button_color = Settings::values.players[controller_idx].button_color_left; -    controller.right_color.body_color = Settings::values.players[controller_idx].body_color_right; +    controller.left_color.body_color = +        Settings::values.players.GetValue()[controller_idx].body_color_left; +    controller.left_color.button_color = +        Settings::values.players.GetValue()[controller_idx].button_color_left; +    controller.right_color.body_color = +        Settings::values.players.GetValue()[controller_idx].body_color_right;      controller.right_color.button_color = -        Settings::values.players[controller_idx].button_color_right; +        Settings::values.players.GetValue()[controller_idx].button_color_right;      controller.battery_level[0] = BATTERY_FULL;      controller.battery_level[1] = BATTERY_FULL; @@ -199,7 +205,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {  void Controller_NPad::OnInit() {      auto& kernel = system.Kernel(); -    for (std::size_t i = 0; i < styleset_changed_events.size(); i++) { +    for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {          styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair(              kernel, fmt::format("npad:NpadStyleSetChanged_{}", i));      } @@ -208,6 +214,8 @@ void Controller_NPad::OnInit() {          return;      } +    OnLoadInputDevices(); +      if (style.raw == 0) {          // We want to support all controllers          style.handheld.Assign(1); @@ -218,12 +226,27 @@ void Controller_NPad::OnInit() {          style.pokeball.Assign(1);      } -    std::transform(Settings::values.players.begin(), Settings::values.players.end(), -                   connected_controllers.begin(), [](const Settings::PlayerInput& player) { +    std::transform(Settings::values.players.GetValue().begin(), +                   Settings::values.players.GetValue().end(), connected_controllers.begin(), +                   [](const Settings::PlayerInput& player) {                         return ControllerHolder{MapSettingsTypeToNPad(player.controller_type),                                                 player.connected};                     }); +    // Connect the Player 1 or Handheld controller if none are connected. +    if (std::none_of(connected_controllers.begin(), connected_controllers.end(), +                     [](const ControllerHolder& controller) { return controller.is_connected; })) { +        const auto controller = +            MapSettingsTypeToNPad(Settings::values.players.GetValue()[0].controller_type); +        if (controller == NPadControllerType::Handheld) { +            Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true; +            connected_controllers[HANDHELD_INDEX] = {controller, true}; +        } else { +            Settings::values.players.GetValue()[0].connected = true; +            connected_controllers[0] = {controller, true}; +        } +    } +      // Account for handheld      if (connected_controllers[HANDHELD_INDEX].is_connected) {          connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld; @@ -242,7 +265,7 @@ void Controller_NPad::OnInit() {  }  void Controller_NPad::OnLoadInputDevices() { -    const auto& players = Settings::values.players; +    const auto& players = Settings::values.players.GetValue();      for (std::size_t i = 0; i < players.size(); ++i) {          std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,                         players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END, @@ -250,13 +273,26 @@ void Controller_NPad::OnLoadInputDevices() {          std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,                         players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END,                         sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>); +        std::transform(players[i].vibrations.begin() + +                           Settings::NativeVibration::VIBRATION_HID_BEGIN, +                       players[i].vibrations.begin() + Settings::NativeVibration::VIBRATION_HID_END, +                       vibrations[i].begin(), Input::CreateDevice<Input::VibrationDevice>);          std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN,                         players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END,                         motions[i].begin(), Input::CreateDevice<Input::MotionDevice>); +        for (std::size_t device_idx = 0; device_idx < vibrations[i].size(); ++device_idx) { +            InitializeVibrationDeviceAtIndex(i, device_idx); +        }      }  } -void Controller_NPad::OnRelease() {} +void Controller_NPad::OnRelease() { +    for (std::size_t npad_idx = 0; npad_idx < vibrations.size(); ++npad_idx) { +        for (std::size_t device_idx = 0; device_idx < vibrations[npad_idx].size(); ++device_idx) { +            VibrateControllerAtIndex(npad_idx, device_idx, {}); +        } +    } +}  void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {      const auto controller_idx = NPadIdToIndex(npad_id); @@ -339,7 +375,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*      if (!IsControllerActivated()) {          return;      } -    for (std::size_t i = 0; i < shared_memory_entries.size(); i++) { +    for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) {          auto& npad = shared_memory_entries[i];          const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states,                                                             &npad.handheld_states, @@ -481,7 +517,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing      if (!IsControllerActivated()) {          return;      } -    for (std::size_t i = 0; i < shared_memory_entries.size(); i++) { +    for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) {          auto& npad = shared_memory_entries[i];          const auto& controller_type = connected_controllers[i].type; @@ -515,7 +551,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing          // Try to read sixaxis sensor states          std::array<MotionDevice, 2> motion_devices; -        if (sixaxis_sensors_enabled && Settings::values.motion_enabled) { +        if (sixaxis_sensors_enabled && Settings::values.motion_enabled.GetValue()) {              sixaxis_at_rest = true;              for (std::size_t e = 0; e < motion_devices.size(); ++e) {                  const auto& device = motions[i][e]; @@ -601,15 +637,15 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing                  shared_memory_entries.size() * sizeof(NPadEntry));  } -void Controller_NPad::SetSupportedStyleSet(NPadType style_set) { +void Controller_NPad::SetSupportedStyleSet(NpadStyleSet style_set) {      style.raw = style_set.raw;  } -Controller_NPad::NPadType Controller_NPad::GetSupportedStyleSet() const { +Controller_NPad::NpadStyleSet Controller_NPad::GetSupportedStyleSet() const {      return style;  } -void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) { +void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) {      ASSERT(length > 0 && (length % sizeof(u32)) == 0);      supported_npad_id_types.clear();      supported_npad_id_types.resize(length / sizeof(u32)); @@ -621,7 +657,7 @@ void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length)      std::memcpy(data, supported_npad_id_types.data(), supported_npad_id_types.size());  } -std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const { +std::size_t Controller_NPad::GetSupportedNpadIdTypesSize() const {      return supported_npad_id_types.size();  } @@ -641,7 +677,7 @@ Controller_NPad::NpadHandheldActivationMode Controller_NPad::GetNpadHandheldActi      return handheld_activation_mode;  } -void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { +void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments assignment_mode) {      const std::size_t npad_index = NPadIdToIndex(npad_id);      ASSERT(npad_index < shared_memory_entries.size());      if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) { @@ -649,35 +685,140 @@ void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode)      }  } -void Controller_NPad::VibrateController(const std::vector<u32>& controllers, -                                        const std::vector<Vibration>& vibrations) { -    LOG_TRACE(Service_HID, "called"); - -    if (!Settings::values.vibration_enabled || !can_controllers_vibrate) { -        return; +bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index, +                                               const VibrationValue& vibration_value) { +    if (!connected_controllers[npad_index].is_connected || !vibrations[npad_index][device_index]) { +        return false;      } -    bool success = true; -    for (std::size_t i = 0; i < controllers.size(); ++i) { -        if (!connected_controllers[i].is_connected) { -            continue; + +    const auto& player = Settings::values.players.GetValue()[npad_index]; + +    if (!player.vibration_enabled) { +        if (latest_vibration_values[npad_index][device_index].amp_low != 0.0f || +            latest_vibration_values[npad_index][device_index].amp_high != 0.0f) { +            // Send an empty vibration to stop any vibrations. +            vibrations[npad_index][device_index]->SetRumblePlay(0.0f, 160.0f, 0.0f, 320.0f); +            // Then reset the vibration value to its default value. +            latest_vibration_values[npad_index][device_index] = {};          } -        using namespace Settings::NativeButton; -        const auto& button_state = buttons[i]; -        if (button_state[A - BUTTON_HID_BEGIN]) { -            if (button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay( -                    vibrations[0].amp_high, vibrations[0].amp_low, vibrations[0].freq_high, -                    vibrations[0].freq_low)) { -                success = false; -            } + +        return false; +    } + +    if (!Settings::values.enable_accurate_vibrations.GetValue()) { +        using std::chrono::duration_cast; +        using std::chrono::milliseconds; +        using std::chrono::steady_clock; + +        const auto now = steady_clock::now(); + +        // Filter out non-zero vibrations that are within 10ms of each other. +        if ((vibration_value.amp_low != 0.0f || vibration_value.amp_high != 0.0f) && +            duration_cast<milliseconds>(now - last_vibration_timepoints[npad_index][device_index]) < +                milliseconds(10)) { +            return false;          } + +        last_vibration_timepoints[npad_index][device_index] = now; +    } + +    auto& vibration = vibrations[npad_index][device_index]; +    const auto player_vibration_strength = static_cast<f32>(player.vibration_strength); +    const auto amp_low = +        std::min(vibration_value.amp_low * player_vibration_strength / 100.0f, 1.0f); +    const auto amp_high = +        std::min(vibration_value.amp_high * player_vibration_strength / 100.0f, 1.0f); +    return vibration->SetRumblePlay(amp_low, vibration_value.freq_low, amp_high, +                                    vibration_value.freq_high); +} + +void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_handle, +                                        const VibrationValue& vibration_value) { +    if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { +        return; +    } + +    const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); +    const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); + +    if (!vibration_devices_mounted[npad_index][device_index] || +        !connected_controllers[npad_index].is_connected) { +        return;      } -    if (success) { -        last_processed_vibration = vibrations.back(); + +    if (vibration_device_handle.device_index == DeviceIndex::None) { +        UNREACHABLE_MSG("DeviceIndex should never be None!"); +        return; +    } + +    // Some games try to send mismatched parameters in the device handle, block these. +    if ((connected_controllers[npad_index].type == NPadControllerType::JoyLeft && +         (vibration_device_handle.npad_type == NpadType::JoyconRight || +          vibration_device_handle.device_index == DeviceIndex::Right)) || +        (connected_controllers[npad_index].type == NPadControllerType::JoyRight && +         (vibration_device_handle.npad_type == NpadType::JoyconLeft || +          vibration_device_handle.device_index == DeviceIndex::Left))) { +        return; +    } + +    // Filter out vibrations with equivalent values to reduce unnecessary state changes. +    if (vibration_value.amp_low == latest_vibration_values[npad_index][device_index].amp_low && +        vibration_value.amp_high == latest_vibration_values[npad_index][device_index].amp_high) { +        return; +    } + +    if (VibrateControllerAtIndex(npad_index, device_index, vibration_value)) { +        latest_vibration_values[npad_index][device_index] = vibration_value;      }  } -Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { -    return last_processed_vibration; +void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles, +                                         const std::vector<VibrationValue>& vibration_values) { +    if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { +        return; +    } + +    ASSERT_OR_EXECUTE_MSG( +        vibration_device_handles.size() == vibration_values.size(), { return; }, +        "The amount of device handles does not match with the amount of vibration values," +        "this is undefined behavior!"); + +    for (std::size_t i = 0; i < vibration_device_handles.size(); ++i) { +        VibrateController(vibration_device_handles[i], vibration_values[i]); +    } +} + +Controller_NPad::VibrationValue Controller_NPad::GetLastVibration( +    const DeviceHandle& vibration_device_handle) const { +    const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); +    const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); +    return latest_vibration_values[npad_index][device_index]; +} + +void Controller_NPad::InitializeVibrationDevice(const DeviceHandle& vibration_device_handle) { +    const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); +    const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); +    InitializeVibrationDeviceAtIndex(npad_index, device_index); +} + +void Controller_NPad::InitializeVibrationDeviceAtIndex(std::size_t npad_index, +                                                       std::size_t device_index) { +    if (vibrations[npad_index][device_index]) { +        vibration_devices_mounted[npad_index][device_index] = +            vibrations[npad_index][device_index]->GetStatus() == 1; +    } else { +        vibration_devices_mounted[npad_index][device_index] = false; +    } +} + +void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) { +    permit_vibration_session_enabled = permit_vibration_session; +} + +bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const { +    const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); +    const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); +    return vibration_devices_mounted[npad_index][device_index];  }  std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const { @@ -696,31 +837,38 @@ void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::siz  void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index,                                           bool connected) {      if (!connected) { -        DisconnectNPadAtIndex(npad_index); +        DisconnectNpadAtIndex(npad_index);          return;      }      if (controller == NPadControllerType::Handheld) { -        Settings::values.players[HANDHELD_INDEX].controller_type = +        Settings::values.players.GetValue()[HANDHELD_INDEX].controller_type =              MapNPadToSettingsType(controller); -        Settings::values.players[HANDHELD_INDEX].connected = true; +        Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true;          connected_controllers[HANDHELD_INDEX] = {controller, true};          InitNewlyAddedController(HANDHELD_INDEX);          return;      } -    Settings::values.players[npad_index].controller_type = MapNPadToSettingsType(controller); -    Settings::values.players[npad_index].connected = true; +    Settings::values.players.GetValue()[npad_index].controller_type = +        MapNPadToSettingsType(controller); +    Settings::values.players.GetValue()[npad_index].connected = true;      connected_controllers[npad_index] = {controller, true};      InitNewlyAddedController(npad_index);  } -void Controller_NPad::DisconnectNPad(u32 npad_id) { -    DisconnectNPadAtIndex(NPadIdToIndex(npad_id)); +void Controller_NPad::DisconnectNpad(u32 npad_id) { +    DisconnectNpadAtIndex(NPadIdToIndex(npad_id));  } -void Controller_NPad::DisconnectNPadAtIndex(std::size_t npad_index) { -    Settings::values.players[npad_index].connected = false; +void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) { +    for (std::size_t device_idx = 0; device_idx < vibrations[npad_index].size(); ++device_idx) { +        // Send an empty vibration to stop any vibrations. +        VibrateControllerAtIndex(npad_index, device_idx, {}); +        vibration_devices_mounted[npad_index][device_idx] = false; +    } + +    Settings::values.players.GetValue()[npad_index].connected = false;      connected_controllers[npad_index].is_connected = false;      auto& controller = shared_memory_entries[npad_index]; @@ -758,7 +906,7 @@ void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) {          (connected_controllers[npad_index_2].type == NPadControllerType::JoyLeft &&           connected_controllers[npad_index_1].type == NPadControllerType::JoyRight)) {          // Disconnect the joycon at the second id and connect the dual joycon at the first index. -        DisconnectNPad(npad_id_2); +        DisconnectNpad(npad_id_2);          AddNewControllerAt(NPadControllerType::JoyDual, npad_index_1);      }  } @@ -830,14 +978,6 @@ void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_prot      unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled;  } -void Controller_NPad::SetVibrationEnabled(bool can_vibrate) { -    can_controllers_vibrate = can_vibrate; -} - -bool Controller_NPad::IsVibrationEnabled() const { -    return can_controllers_vibrate; -} -  void Controller_NPad::ClearAllConnectedControllers() {      for (auto& controller : connected_controllers) {          if (controller.is_connected && controller.type != NPadControllerType::None) { @@ -882,7 +1022,7 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const              return false;          }          // Handheld should not be supported in docked mode -        if (Settings::values.use_docked_mode) { +        if (Settings::values.use_docked_mode.GetValue()) {              return false;          } diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index fd5c5a6eb..160dcbbe3 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -39,28 +39,30 @@ public:      // Called when input devices should be loaded      void OnLoadInputDevices() override; -    struct NPadType { -        union { -            u32_le raw{}; - -            BitField<0, 1, u32> pro_controller; -            BitField<1, 1, u32> handheld; -            BitField<2, 1, u32> joycon_dual; -            BitField<3, 1, u32> joycon_left; -            BitField<4, 1, u32> joycon_right; +    enum class NPadControllerType { +        None, +        ProController, +        Handheld, +        JoyDual, +        JoyLeft, +        JoyRight, +        Pokeball, +    }; -            BitField<6, 1, u32> pokeball; // TODO(ogniK): Confirm when possible -        }; +    enum class NpadType : u8 { +        ProController = 3, +        Handheld = 4, +        JoyconDual = 5, +        JoyconLeft = 6, +        JoyconRight = 7, +        Pokeball = 9,      }; -    static_assert(sizeof(NPadType) == 4, "NPadType is an invalid size"); -    struct Vibration { -        f32 amp_low; -        f32 freq_low; -        f32 amp_high; -        f32 freq_high; +    enum class DeviceIndex : u8 { +        Left = 0, +        Right = 1, +        None = 2,      }; -    static_assert(sizeof(Vibration) == 0x10, "Vibration is an invalid size");      enum class GyroscopeZeroDriftMode : u32 {          Loose = 0, @@ -73,7 +75,7 @@ public:          Horizontal = 1,      }; -    enum class NPadAssignments : u32_le { +    enum class NpadAssignments : u32 {          Dual = 0,          Single = 1,      }; @@ -84,15 +86,36 @@ public:          None = 2,      }; -    enum class NPadControllerType { -        None, -        ProController, -        Handheld, -        JoyDual, -        JoyLeft, -        JoyRight, -        Pokeball, +    struct DeviceHandle { +        NpadType npad_type{}; +        u8 npad_id{}; +        DeviceIndex device_index{}; +        INSERT_PADDING_BYTES(1); +    }; +    static_assert(sizeof(DeviceHandle) == 4, "DeviceHandle is an invalid size"); + +    struct NpadStyleSet { +        union { +            u32_le raw{}; + +            BitField<0, 1, u32> pro_controller; +            BitField<1, 1, u32> handheld; +            BitField<2, 1, u32> joycon_dual; +            BitField<3, 1, u32> joycon_left; +            BitField<4, 1, u32> joycon_right; + +            BitField<6, 1, u32> pokeball; // TODO(ogniK): Confirm when possible +        }; +    }; +    static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size"); + +    struct VibrationValue { +        f32 amp_low{0.0f}; +        f32 freq_low{160.0f}; +        f32 amp_high{0.0f}; +        f32 freq_high{320.0f};      }; +    static_assert(sizeof(VibrationValue) == 0x10, "Vibration is an invalid size");      struct LedPattern {          explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { @@ -110,12 +133,12 @@ public:          };      }; -    void SetSupportedStyleSet(NPadType style_set); -    NPadType GetSupportedStyleSet() const; +    void SetSupportedStyleSet(NpadStyleSet style_set); +    NpadStyleSet GetSupportedStyleSet() const; -    void SetSupportedNPadIdTypes(u8* data, std::size_t length); +    void SetSupportedNpadIdTypes(u8* data, std::size_t length);      void GetSupportedNpadIdTypes(u32* data, std::size_t max_length); -    std::size_t GetSupportedNPadIdTypesSize() const; +    std::size_t GetSupportedNpadIdTypesSize() const;      void SetHoldType(NpadHoldType joy_hold_type);      NpadHoldType GetHoldType() const; @@ -123,12 +146,26 @@ public:      void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode);      NpadHandheldActivationMode GetNpadHandheldActivationMode() const; -    void SetNpadMode(u32 npad_id, NPadAssignments assignment_mode); +    void SetNpadMode(u32 npad_id, NpadAssignments assignment_mode); + +    bool VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index, +                                  const VibrationValue& vibration_value); + +    void VibrateController(const DeviceHandle& vibration_device_handle, +                           const VibrationValue& vibration_value); + +    void VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles, +                            const std::vector<VibrationValue>& vibration_values); + +    VibrationValue GetLastVibration(const DeviceHandle& vibration_device_handle) const; + +    void InitializeVibrationDevice(const DeviceHandle& vibration_device_handle); + +    void InitializeVibrationDeviceAtIndex(std::size_t npad_index, std::size_t device_index); -    void VibrateController(const std::vector<u32>& controllers, -                           const std::vector<Vibration>& vibrations); +    void SetPermitVibrationSession(bool permit_vibration_session); -    Vibration GetLastVibration() const; +    bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const;      std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;      void SignalStyleSetChangedEvent(u32 npad_id) const; @@ -138,8 +175,8 @@ public:      // Adds a new controller at an index with connection status.      void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected); -    void DisconnectNPad(u32 npad_id); -    void DisconnectNPadAtIndex(std::size_t index); +    void DisconnectNpad(u32 npad_id); +    void DisconnectNpadAtIndex(std::size_t index);      void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode);      GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const; @@ -148,8 +185,6 @@ public:      LedPattern GetLedPattern(u32 npad_id);      bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const;      void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id); -    void SetVibrationEnabled(bool can_vibrate); -    bool IsVibrationEnabled() const;      void ClearAllConnectedControllers();      void DisconnectAllConnectedControllers();      void ConnectAllDisconnectedControllers(); @@ -324,8 +359,8 @@ private:      };      struct NPadEntry { -        NPadType joy_styles; -        NPadAssignments pad_assignment; +        NpadStyleSet joy_styles; +        NpadAssignments pad_assignment;          ColorReadError single_color_error;          ControllerColor single_color; @@ -368,7 +403,7 @@ private:      u32 press_state{}; -    NPadType style{}; +    NpadStyleSet style{};      std::array<NPadEntry, 10> shared_memory_entries{};      using ButtonArray = std::array<          std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>, @@ -376,22 +411,28 @@ private:      using StickArray = std::array<          std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>,          10>; +    using VibrationArray = std::array<std::array<std::unique_ptr<Input::VibrationDevice>, +                                                 Settings::NativeVibration::NUM_VIBRATIONS_HID>, +                                      10>;      using MotionArray = std::array< -        std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTION_HID>, +        std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>,          10>;      ButtonArray buttons;      StickArray sticks; +    VibrationArray vibrations;      MotionArray motions;      std::vector<u32> supported_npad_id_types{};      NpadHoldType hold_type{NpadHoldType::Vertical};      NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};      // Each controller should have their own styleset changed event      std::array<Kernel::EventPair, 10> styleset_changed_events; -    Vibration last_processed_vibration{}; +    std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10> last_vibration_timepoints; +    std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{}; +    bool permit_vibration_session_enabled{false}; +    std::array<std::array<bool, 2>, 10> vibration_devices_mounted{};      std::array<ControllerHolder, 10> connected_controllers{};      std::array<bool, 10> unintended_home_button_input_protection{};      GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; -    bool can_controllers_vibrate{true};      bool sixaxis_sensors_enabled{true};      bool sixaxis_at_rest{true};      std::array<ControllerPad, 10> npad_pad_states{}; diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 50f709b25..902516b29 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -139,20 +139,34 @@ void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanose  class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {  public: -    IActiveVibrationDeviceList() : ServiceFramework("IActiveVibrationDeviceList") { +    explicit IActiveVibrationDeviceList(std::shared_ptr<IAppletResource> applet_resource_) +        : ServiceFramework("IActiveVibrationDeviceList"), applet_resource(applet_resource_) { +        // clang-format off          static const FunctionInfo functions[] = { -            {0, &IActiveVibrationDeviceList::ActivateVibrationDevice, "ActivateVibrationDevice"}, +            {0, &IActiveVibrationDeviceList::InitializeVibrationDevice, "InitializeVibrationDevice"},          }; +        // clang-format on +          RegisterHandlers(functions);      }  private: -    void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) { -        LOG_WARNING(Service_HID, "(STUBBED) called"); +    void InitializeVibrationDevice(Kernel::HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; + +        applet_resource->GetController<Controller_NPad>(HidController::NPad) +            .InitializeVibrationDevice(vibration_device_handle); + +        LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}", +                  vibration_device_handle.npad_type, vibration_device_handle.npad_id, +                  vibration_device_handle.device_index);          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);      } + +    std::shared_ptr<IAppletResource> applet_resource;  };  std::shared_ptr<IAppletResource> Hid::GetAppletResource() { @@ -241,7 +255,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {          {208, nullptr, "GetActualVibrationGcErmCommand"},          {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"},          {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"}, -        {211, nullptr, "IsVibrationDeviceMounted"}, +        {211, &Hid::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"},          {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},          {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},          {302, &Hid::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"}, @@ -320,142 +334,152 @@ void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) {      rb.PushIpcInterface<IAppletResource>(applet_resource);  } -void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) { +void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto basic_xpad_id{rp.Pop<u32>()};      const auto applet_resource_user_id{rp.Pop<u64>()}; -    LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}", basic_xpad_id, -              applet_resource_user_id); +    applet_resource->ActivateController(HidController::DebugPad); + +    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); -    applet_resource->ActivateController(HidController::XPad);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS);  } -void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) { +void Hid::ActivateTouchScreen(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx};      const auto applet_resource_user_id{rp.Pop<u64>()}; -    LOG_DEBUG(Service_HID, "(STUBBED) called, applet_resource_user_id={}", applet_resource_user_id); - -    IPC::ResponseBuilder rb{ctx, 3}; -    rb.Push(RESULT_SUCCESS); -    rb.Push(0); -} +    applet_resource->ActivateController(HidController::Touchscreen); -void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { -    IPC::RequestParser rp{ctx}; -    const auto handle{rp.Pop<u32>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; -    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true); -    LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, -              applet_resource_user_id); +    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS);  } -void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { +void Hid::ActivateMouse(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto handle{rp.Pop<u32>()};      const auto applet_resource_user_id{rp.Pop<u64>()}; -    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false); -    LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, -              applet_resource_user_id); +    applet_resource->ActivateController(HidController::Mouse); + +    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS);  } -void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) { +void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx};      const auto applet_resource_user_id{rp.Pop<u64>()}; +    applet_resource->ActivateController(HidController::Keyboard); +      LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); -    applet_resource->ActivateController(HidController::DebugPad);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS);  } -void Hid::ActivateTouchScreen(Kernel::HLERequestContext& ctx) { +void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    const auto flags{rp.Pop<u32>()}; -    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); +    LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags); -    applet_resource->ActivateController(HidController::Touchscreen);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS);  } -void Hid::ActivateMouse(Kernel::HLERequestContext& ctx) { +void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    struct Parameters { +        u32 basic_xpad_id{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; -    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); +    const auto parameters{rp.PopRaw<Parameters>()}; + +    applet_resource->ActivateController(HidController::XPad); + +    LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}", +              parameters.basic_xpad_id, parameters.applet_resource_user_id); -    applet_resource->ActivateController(HidController::Mouse);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS);  } -void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) { +void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx};      const auto applet_resource_user_id{rp.Pop<u64>()}; -    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); +    LOG_DEBUG(Service_HID, "(STUBBED) called, applet_resource_user_id={}", applet_resource_user_id); -    applet_resource->ActivateController(HidController::Keyboard); -    IPC::ResponseBuilder rb{ctx, 2}; +    IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS); +    rb.Push(0);  } -void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) { +void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto flags{rp.Pop<u32>()}; -    LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags); +    struct Parameters { +        Controller_NPad::DeviceHandle sixaxis_handle{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; -    IPC::ResponseBuilder rb{ctx, 2}; -    rb.Push(RESULT_SUCCESS); -} +    const auto parameters{rp.PopRaw<Parameters>()}; -void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { -    IPC::RequestParser rp{ctx}; -    const auto unknown{rp.Pop<u32>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true); -    LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, -              applet_resource_user_id); +    LOG_DEBUG(Service_HID, +              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", +              parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, +              parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); -    applet_resource->ActivateController(HidController::Gesture);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS);  } -void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { -    // Should have no effect with how our npad sets up the data +void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto unknown{rp.Pop<u32>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    struct Parameters { +        Controller_NPad::DeviceHandle sixaxis_handle{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; -    LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, -              applet_resource_user_id); +    const auto parameters{rp.PopRaw<Parameters>()}; + +    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false); + +    LOG_DEBUG(Service_HID, +              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", +              parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, +              parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); -    applet_resource->ActivateController(HidController::NPad);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS);  }  void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto handle{rp.Pop<u32>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    struct Parameters { +        Controller_NPad::DeviceHandle sixaxis_handle{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; -    LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, -                applet_resource_user_id); +    const auto parameters{rp.PopRaw<Parameters>()}; + +    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true); + +    LOG_DEBUG(Service_HID, +              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", +              parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, +              parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS); @@ -463,11 +487,20 @@ void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {  void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto handle{rp.Pop<u32>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    struct Parameters { +        Controller_NPad::DeviceHandle sixaxis_handle{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; -    LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, -                applet_resource_user_id); +    const auto parameters{rp.PopRaw<Parameters>()}; + +    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false); + +    LOG_DEBUG(Service_HID, +              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", +              parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, +              parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS); @@ -475,12 +508,21 @@ void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {  void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    [[maybe_unused]] const auto enable{rp.Pop<bool>()}; -    const auto handle{rp.Pop<u32>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    struct Parameters { +        bool enable_sixaxis_sensor_fusion{}; +        INSERT_PADDING_BYTES(3); +        Controller_NPad::DeviceHandle sixaxis_handle{}; +        u64 applet_resource_user_id{}; +    }; -    LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, -                applet_resource_user_id); +    const auto parameters{rp.PopRaw<Parameters>()}; + +    LOG_WARNING(Service_HID, +                "(STUBBED) called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, " +                "device_index={}, applet_resource_user_id={}", +                parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type, +                parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index, +                parameters.applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS); @@ -488,14 +530,17 @@ void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) {  void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto handle{rp.Pop<u32>()}; -    const auto drift_mode{rp.Pop<u32>()}; +    const auto sixaxis_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; +    const auto drift_mode{rp.PopEnum<Controller_NPad::GyroscopeZeroDriftMode>()};      const auto applet_resource_user_id{rp.Pop<u64>()};      applet_resource->GetController<Controller_NPad>(HidController::NPad) -        .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode{drift_mode}); +        .SetGyroscopeZeroDriftMode(drift_mode); -    LOG_DEBUG(Service_HID, "called, handle={}, drift_mode={}, applet_resource_user_id={}", handle, +    LOG_DEBUG(Service_HID, +              "called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, " +              "applet_resource_user_id={}", +              sixaxis_handle.npad_type, sixaxis_handle.npad_id, sixaxis_handle.device_index,                drift_mode, applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 2}; @@ -504,29 +549,42 @@ void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {  void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto handle{rp.Pop<u32>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    struct Parameters { +        Controller_NPad::DeviceHandle sixaxis_handle{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; + +    const auto parameters{rp.PopRaw<Parameters>()}; -    LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, -              applet_resource_user_id); +    LOG_DEBUG(Service_HID, +              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", +              parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, +              parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS); -    rb.Push<u32>( -        static_cast<u32>(applet_resource->GetController<Controller_NPad>(HidController::NPad) -                             .GetGyroscopeZeroDriftMode())); +    rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad) +                    .GetGyroscopeZeroDriftMode());  }  void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto handle{rp.Pop<u32>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    struct Parameters { +        Controller_NPad::DeviceHandle sixaxis_handle{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; + +    const auto parameters{rp.PopRaw<Parameters>()};      applet_resource->GetController<Controller_NPad>(HidController::NPad)          .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode::Standard); -    LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, -              applet_resource_user_id); +    LOG_DEBUG(Service_HID, +              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", +              parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, +              parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS); @@ -534,11 +592,18 @@ void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {  void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto handle{rp.Pop<u32>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    struct Parameters { +        Controller_NPad::DeviceHandle sixaxis_handle{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; + +    const auto parameters{rp.PopRaw<Parameters>()}; -    LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, -              applet_resource_user_id); +    LOG_DEBUG(Service_HID, +              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", +              parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, +              parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS); @@ -546,15 +611,34 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {                  .IsSixAxisSensorAtRest());  } +void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    struct Parameters { +        u32 unknown{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; + +    const auto parameters{rp.PopRaw<Parameters>()}; + +    applet_resource->ActivateController(HidController::Gesture); + +    LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown, +              parameters.applet_resource_user_id); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(RESULT_SUCCESS); +} +  void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx};      const auto supported_styleset{rp.Pop<u32>()}; -    LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset); -      applet_resource->GetController<Controller_NPad>(HidController::NPad)          .SetSupportedStyleSet({supported_styleset}); +    LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset); +      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS);  } @@ -565,21 +649,22 @@ void Hid::GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {      LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); -    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); -      IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS); -    rb.Push<u32>(controller.GetSupportedStyleSet().raw); +    rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad) +                .GetSupportedStyleSet() +                .raw);  }  void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx};      const auto applet_resource_user_id{rp.Pop<u64>()}; +    applet_resource->GetController<Controller_NPad>(HidController::NPad) +        .SetSupportedNpadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize()); +      LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); -    applet_resource->GetController<Controller_NPad>(HidController::NPad) -        .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS);  } @@ -588,48 +673,62 @@ void Hid::ActivateNpad(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx};      const auto applet_resource_user_id{rp.Pop<u64>()}; +    applet_resource->ActivateController(HidController::NPad); +      LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS); -    applet_resource->ActivateController(HidController::NPad);  }  void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx};      const auto applet_resource_user_id{rp.Pop<u64>()}; +    applet_resource->DeactivateController(HidController::NPad); +      LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS); -    applet_resource->DeactivateController(HidController::NPad);  }  void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto npad_id{rp.Pop<u32>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; -    const auto unknown{rp.Pop<u64>()}; +    struct Parameters { +        u32 npad_id{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +        u64 unknown{}; +    }; -    LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", npad_id, -              applet_resource_user_id, unknown); +    const auto parameters{rp.PopRaw<Parameters>()}; + +    LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", +              parameters.npad_id, parameters.applet_resource_user_id, parameters.unknown);      IPC::ResponseBuilder rb{ctx, 2, 1};      rb.Push(RESULT_SUCCESS);      rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) -                           .GetStyleSetChangedEvent(npad_id)); +                           .GetStyleSetChangedEvent(parameters.npad_id));  }  void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto npad_id{rp.Pop<u32>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    struct Parameters { +        u32 npad_id{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; -    LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, -              applet_resource_user_id); +    const auto parameters{rp.PopRaw<Parameters>()}; + +    applet_resource->GetController<Controller_NPad>(HidController::NPad) +        .DisconnectNpad(parameters.npad_id); + +    LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, +              parameters.applet_resource_user_id); -    applet_resource->GetController<Controller_NPad>(HidController::NPad).DisconnectNPad(npad_id);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS);  } @@ -642,22 +741,41 @@ void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {      IPC::ResponseBuilder rb{ctx, 4};      rb.Push(RESULT_SUCCESS); -    rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) -                        .GetLedPattern(npad_id) -                        .raw); +    rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad) +                .GetLedPattern(npad_id) +                .raw); +} + +void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { +    // Should have no effect with how our npad sets up the data +    IPC::RequestParser rp{ctx}; +    struct Parameters { +        u32 unknown{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; + +    const auto parameters{rp.PopRaw<Parameters>()}; + +    applet_resource->ActivateController(HidController::NPad); + +    LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown, +              parameters.applet_resource_user_id); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(RESULT_SUCCESS);  }  void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx};      const auto applet_resource_user_id{rp.Pop<u64>()}; -    const auto hold_type{rp.Pop<u64>()}; +    const auto hold_type{rp.PopEnum<Controller_NPad::NpadHoldType>()}; + +    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetHoldType(hold_type);      LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}",                applet_resource_user_id, hold_type); -    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); -    controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type}); -      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS);  } @@ -668,22 +786,26 @@ void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {      LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); -    const auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);      IPC::ResponseBuilder rb{ctx, 4};      rb.Push(RESULT_SUCCESS); -    rb.Push<u64>(static_cast<u64>(controller.GetHoldType())); +    rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad).GetHoldType());  }  void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto npad_id{rp.Pop<u32>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    struct Parameters { +        u32 npad_id{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; -    LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id, -                applet_resource_user_id); +    const auto parameters{rp.PopRaw<Parameters>()}; + +    applet_resource->GetController<Controller_NPad>(HidController::NPad) +        .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single); -    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); -    controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Single); +    LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", +                parameters.npad_id, parameters.applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS); @@ -692,16 +814,22 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx  void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {      // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault      IPC::RequestParser rp{ctx}; -    const auto npad_id{rp.Pop<u32>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; -    const auto npad_joy_device_type{rp.Pop<u64>()}; +    struct Parameters { +        u32 npad_id{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +        u64 npad_joy_device_type{}; +    }; + +    const auto parameters{rp.PopRaw<Parameters>()}; + +    applet_resource->GetController<Controller_NPad>(HidController::NPad) +        .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single);      LOG_WARNING(Service_HID,                  "(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", -                npad_id, applet_resource_user_id, npad_joy_device_type); - -    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); -    controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Single); +                parameters.npad_id, parameters.applet_resource_user_id, +                parameters.npad_joy_device_type);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS); @@ -709,14 +837,19 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {  void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto npad_id{rp.Pop<u32>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    struct Parameters { +        u32 npad_id{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; + +    const auto parameters{rp.PopRaw<Parameters>()}; -    LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, -              applet_resource_user_id); +    applet_resource->GetController<Controller_NPad>(HidController::NPad) +        .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Dual); -    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); -    controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); +    LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", +                parameters.npad_id, parameters.applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS); @@ -728,12 +861,12 @@ void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {      const auto npad_id_2{rp.Pop<u32>()};      const auto applet_resource_user_id{rp.Pop<u64>()}; +    applet_resource->GetController<Controller_NPad>(HidController::NPad) +        .MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2); +      LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",                npad_id_1, npad_id_2, applet_resource_user_id); -    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); -    controller.MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2); -      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS);  } @@ -742,9 +875,9 @@ void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx};      const auto applet_resource_user_id{rp.Pop<u64>()}; +    applet_resource->GetController<Controller_NPad>(HidController::NPad).StartLRAssignmentMode(); +      LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); -    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); -    controller.StartLRAssignmentMode();      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS); @@ -754,9 +887,9 @@ void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx};      const auto applet_resource_user_id{rp.Pop<u64>()}; +    applet_resource->GetController<Controller_NPad>(HidController::NPad).StopLRAssignmentMode(); +      LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); -    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); -    controller.StopLRAssignmentMode();      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS); @@ -765,13 +898,13 @@ void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) {  void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx};      const auto applet_resource_user_id{rp.Pop<u64>()}; -    const auto mode{rp.Pop<u64>()}; - -    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, mode={}", applet_resource_user_id, -              mode); +    const auto activation_mode{rp.PopEnum<Controller_NPad::NpadHandheldActivationMode>()};      applet_resource->GetController<Controller_NPad>(HidController::NPad) -        .SetNpadHandheldActivationMode(Controller_NPad::NpadHandheldActivationMode{mode}); +        .SetNpadHandheldActivationMode(activation_mode); + +    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, activation_mode={}", +              applet_resource_user_id, activation_mode);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS); @@ -785,23 +918,24 @@ void Hid::GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {      IPC::ResponseBuilder rb{ctx, 4};      rb.Push(RESULT_SUCCESS); -    rb.Push<u64>( -        static_cast<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) -                             .GetNpadHandheldActivationMode())); +    rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad) +                    .GetNpadHandheldActivationMode());  }  void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto npad_1{rp.Pop<u32>()}; -    const auto npad_2{rp.Pop<u32>()}; +    const auto npad_id_1{rp.Pop<u32>()}; +    const auto npad_id_2{rp.Pop<u32>()};      const auto applet_resource_user_id{rp.Pop<u64>()}; -    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, npad_1={}, npad_2={}", -              applet_resource_user_id, npad_1, npad_2); +    const bool res = applet_resource->GetController<Controller_NPad>(HidController::NPad) +                         .SwapNpadAssignment(npad_id_1, npad_id_2); + +    LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", +              npad_id_1, npad_id_2, applet_resource_user_id); -    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);      IPC::ResponseBuilder rb{ctx, 2}; -    if (controller.SwapNpadAssignment(npad_1, npad_2)) { +    if (res) {          rb.Push(RESULT_SUCCESS);      } else {          LOG_ERROR(Service_HID, "Npads are not connected!"); @@ -811,144 +945,219 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {  void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto npad_id{rp.Pop<u32>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    struct Parameters { +        u32 npad_id{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; -    LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id, -                applet_resource_user_id); +    const auto parameters{rp.PopRaw<Parameters>()}; -    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); +    LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", +                parameters.npad_id, parameters.applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS); -    rb.Push<bool>(controller.IsUnintendedHomeButtonInputProtectionEnabled(npad_id)); +    rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad) +                .IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id));  }  void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto unintended_home_button_input_protection{rp.Pop<bool>()}; -    const auto npad_id{rp.Pop<u32>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    struct Parameters { +        bool unintended_home_button_input_protection{}; +        INSERT_PADDING_BYTES(3); +        u32 npad_id{}; +        u64 applet_resource_user_id{}; +    }; + +    const auto parameters{rp.PopRaw<Parameters>()}; + +    applet_resource->GetController<Controller_NPad>(HidController::NPad) +        .SetUnintendedHomeButtonInputProtectionEnabled( +            parameters.unintended_home_button_input_protection, parameters.npad_id);      LOG_WARNING(Service_HID,                  "(STUBBED) called, unintended_home_button_input_protection={}, npad_id={},"                  "applet_resource_user_id={}", -                npad_id, unintended_home_button_input_protection, applet_resource_user_id); - -    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); -    controller.SetUnintendedHomeButtonInputProtectionEnabled( -        unintended_home_button_input_protection, npad_id); +                parameters.unintended_home_button_input_protection, parameters.npad_id, +                parameters.applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS);  } -void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { +void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; + +    VibrationDeviceInfo vibration_device_info; + +    vibration_device_info.type = VibrationDeviceType::LinearResonantActuator; + +    switch (vibration_device_handle.device_index) { +    case Controller_NPad::DeviceIndex::Left: +        vibration_device_info.position = VibrationDevicePosition::Left; +        break; +    case Controller_NPad::DeviceIndex::Right: +        vibration_device_info.position = VibrationDevicePosition::Right; +        break; +    case Controller_NPad::DeviceIndex::None: +    default: +        UNREACHABLE_MSG("DeviceIndex should never be None!"); +        vibration_device_info.position = VibrationDevicePosition::None; +        break; +    } -    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); +    LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}", +              vibration_device_info.type, vibration_device_info.position); + +    IPC::ResponseBuilder rb{ctx, 4}; +    rb.Push(RESULT_SUCCESS); +    rb.PushRaw(vibration_device_info); +} + +void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    struct Parameters { +        Controller_NPad::DeviceHandle vibration_device_handle{}; +        Controller_NPad::VibrationValue vibration_value{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; + +    const auto parameters{rp.PopRaw<Parameters>()}; + +    applet_resource->GetController<Controller_NPad>(HidController::NPad) +        .VibrateController(parameters.vibration_device_handle, parameters.vibration_value); + +    LOG_DEBUG(Service_HID, +              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", +              parameters.vibration_device_handle.npad_type, +              parameters.vibration_device_handle.npad_id, +              parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); -    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(true);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS);  } -void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { +void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    struct Parameters { +        Controller_NPad::DeviceHandle vibration_device_handle{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; + +    const auto parameters{rp.PopRaw<Parameters>()}; + +    LOG_DEBUG(Service_HID, +              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", +              parameters.vibration_device_handle.npad_type, +              parameters.vibration_device_handle.npad_id, +              parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); + +    IPC::ResponseBuilder rb{ctx, 6}; +    rb.Push(RESULT_SUCCESS); +    rb.PushRaw(applet_resource->GetController<Controller_NPad>(HidController::NPad) +                   .GetLastVibration(parameters.vibration_device_handle)); +} + +void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {      LOG_DEBUG(Service_HID, "called"); -    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(false); -    IPC::ResponseBuilder rb{ctx, 2}; +    IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS); +    rb.PushIpcInterface<IActiveVibrationDeviceList>(applet_resource);  } -void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { +void Hid::PermitVibration(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto controller{rp.Pop<u32>()}; -    const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    const auto can_vibrate{rp.Pop<bool>()}; -    LOG_DEBUG(Service_HID, "called, controller={}, applet_resource_user_id={}", controller, -              applet_resource_user_id); +    Settings::values.vibration_enabled.SetValue(can_vibrate); + +    LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS); +} -    applet_resource->GetController<Controller_NPad>(HidController::NPad) -        .VibrateController({controller}, {vibration_values}); +void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) { +    LOG_DEBUG(Service_HID, "called"); + +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(RESULT_SUCCESS); +    rb.Push(Settings::values.vibration_enabled.GetValue());  }  void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx};      const auto applet_resource_user_id{rp.Pop<u64>()}; -    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - -    const auto controllers = ctx.ReadBuffer(0); +    const auto handles = ctx.ReadBuffer(0);      const auto vibrations = ctx.ReadBuffer(1); -    std::vector<u32> controller_list(controllers.size() / sizeof(u32)); -    std::vector<Controller_NPad::Vibration> vibration_list(vibrations.size() / -                                                           sizeof(Controller_NPad::Vibration)); +    std::vector<Controller_NPad::DeviceHandle> vibration_device_handles( +        handles.size() / sizeof(Controller_NPad::DeviceHandle)); +    std::vector<Controller_NPad::VibrationValue> vibration_values( +        vibrations.size() / sizeof(Controller_NPad::VibrationValue)); -    std::memcpy(controller_list.data(), controllers.data(), controllers.size()); -    std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size()); +    std::memcpy(vibration_device_handles.data(), handles.data(), handles.size()); +    std::memcpy(vibration_values.data(), vibrations.data(), vibrations.size());      applet_resource->GetController<Controller_NPad>(HidController::NPad) -        .VibrateController(controller_list, vibration_list); +        .VibrateControllers(vibration_device_handles, vibration_values); + +    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS);  } -void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { +void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto controller_id{rp.Pop<u32>()};      const auto applet_resource_user_id{rp.Pop<u64>()}; -    LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id, -              applet_resource_user_id); - -    IPC::ResponseBuilder rb{ctx, 6}; -    rb.Push(RESULT_SUCCESS); -    rb.PushRaw<Controller_NPad::Vibration>( -        applet_resource->GetController<Controller_NPad>(HidController::NPad).GetLastVibration()); -} +    applet_resource->GetController<Controller_NPad>(HidController::NPad) +        .SetPermitVibrationSession(true); -void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { -    LOG_DEBUG(Service_HID, "called"); +    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); -    IPC::ResponseBuilder rb{ctx, 4}; +    IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS); -    rb.Push<u32>(1); -    rb.Push<u32>(0);  } -void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { +void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { +    applet_resource->GetController<Controller_NPad>(HidController::NPad) +        .SetPermitVibrationSession(false); +      LOG_DEBUG(Service_HID, "called"); -    IPC::ResponseBuilder rb{ctx, 2, 0, 1}; +    IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS); -    rb.PushIpcInterface<IActiveVibrationDeviceList>();  } -void Hid::PermitVibration(Kernel::HLERequestContext& ctx) { +void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto can_vibrate{rp.Pop<bool>()}; -    Settings::values.vibration_enabled = can_vibrate; +    struct Parameters { +        Controller_NPad::DeviceHandle vibration_device_handle{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; -    LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate); +    const auto parameters{rp.PopRaw<Parameters>()}; -    IPC::ResponseBuilder rb{ctx, 2}; -    rb.Push(RESULT_SUCCESS); -} - -void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) { -    LOG_DEBUG(Service_HID, "called"); +    LOG_DEBUG(Service_HID, +              "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", +              parameters.vibration_device_handle.npad_type, +              parameters.vibration_device_handle.npad_id, +              parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS); -    rb.Push(Settings::values.vibration_enabled); +    rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad) +                .IsVibrationDeviceMounted(parameters.vibration_device_handle));  }  void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { @@ -964,11 +1173,19 @@ void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {  void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto handle{rp.Pop<u32>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    struct Parameters { +        Controller_NPad::DeviceHandle sixaxis_handle{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; -    LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, -                applet_resource_user_id); +    const auto parameters{rp.PopRaw<Parameters>()}; + +    LOG_WARNING( +        Service_HID, +        "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", +        parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, +        parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS); @@ -976,11 +1193,19 @@ void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {  void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto handle{rp.Pop<u32>()}; -    const auto applet_resource_user_id{rp.Pop<u64>()}; +    struct Parameters { +        Controller_NPad::DeviceHandle sixaxis_handle{}; +        INSERT_PADDING_WORDS(1); +        u64 applet_resource_user_id{}; +    }; -    LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, -                applet_resource_user_id); +    const auto parameters{rp.PopRaw<Parameters>()}; + +    LOG_WARNING( +        Service_HID, +        "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", +        parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, +        parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index fd0372b18..c8e4a4b55 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -86,17 +86,15 @@ public:  private:      void CreateAppletResource(Kernel::HLERequestContext& ctx); -    void ActivateXpad(Kernel::HLERequestContext& ctx); -    void GetXpadIDs(Kernel::HLERequestContext& ctx); -    void ActivateSixAxisSensor(Kernel::HLERequestContext& ctx); -    void DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx);      void ActivateDebugPad(Kernel::HLERequestContext& ctx);      void ActivateTouchScreen(Kernel::HLERequestContext& ctx);      void ActivateMouse(Kernel::HLERequestContext& ctx);      void ActivateKeyboard(Kernel::HLERequestContext& ctx);      void SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx); -    void ActivateGesture(Kernel::HLERequestContext& ctx); -    void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx); +    void ActivateXpad(Kernel::HLERequestContext& ctx); +    void GetXpadIDs(Kernel::HLERequestContext& ctx); +    void ActivateSixAxisSensor(Kernel::HLERequestContext& ctx); +    void DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx);      void StartSixAxisSensor(Kernel::HLERequestContext& ctx);      void StopSixAxisSensor(Kernel::HLERequestContext& ctx);      void EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx); @@ -104,6 +102,7 @@ private:      void GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);      void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);      void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx); +    void ActivateGesture(Kernel::HLERequestContext& ctx);      void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);      void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);      void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx); @@ -112,6 +111,7 @@ private:      void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx);      void DisconnectNpad(Kernel::HLERequestContext& ctx);      void GetPlayerLedPattern(Kernel::HLERequestContext& ctx); +    void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx);      void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx);      void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx);      void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx); @@ -125,15 +125,16 @@ private:      void SwapNpadAssignment(Kernel::HLERequestContext& ctx);      void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx);      void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx); -    void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx); -    void EndPermitVibrationSession(Kernel::HLERequestContext& ctx); +    void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx);      void SendVibrationValue(Kernel::HLERequestContext& ctx); -    void SendVibrationValues(Kernel::HLERequestContext& ctx);      void GetActualVibrationValue(Kernel::HLERequestContext& ctx); -    void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx);      void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx);      void PermitVibration(Kernel::HLERequestContext& ctx);      void IsVibrationPermitted(Kernel::HLERequestContext& ctx); +    void SendVibrationValues(Kernel::HLERequestContext& ctx); +    void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx); +    void EndPermitVibrationSession(Kernel::HLERequestContext& ctx); +    void IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx);      void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);      void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);      void StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); @@ -146,6 +147,22 @@ private:      void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);      void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); +    enum class VibrationDeviceType : u32 { +        LinearResonantActuator = 1, +    }; + +    enum class VibrationDevicePosition : u32 { +        None = 0, +        Left = 1, +        Right = 2, +    }; + +    struct VibrationDeviceInfo { +        VibrationDeviceType type{}; +        VibrationDevicePosition position{}; +    }; +    static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size."); +      std::shared_ptr<IAppletResource> applet_resource;      Core::System& system;  }; diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index eeaca44b6..65c209725 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -9,6 +9,7 @@  #include "common/alignment.h"  #include "common/hex_util.h"  #include "common/scope_exit.h" +#include "core/core.h"  #include "core/hle/ipc_helpers.h"  #include "core/hle/kernel/errors.h"  #include "core/hle/kernel/memory/page_table.h" diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp index dec96b771..49a42a9c9 100644 --- a/src/core/hle/service/lm/lm.cpp +++ b/src/core/hle/service/lm/lm.cpp @@ -7,6 +7,7 @@  #include "common/logging/log.h"  #include "common/scope_exit.h" +#include "core/core.h"  #include "core/hle/ipc_helpers.h"  #include "core/hle/service/lm/lm.h"  #include "core/hle/service/lm/manager.h" diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 58ee1f712..2594e6839 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp @@ -3,6 +3,7 @@  // Refer to the license.txt file included.  #include "common/logging/log.h" +#include "core/core.h"  #include "core/file_sys/control_metadata.h"  #include "core/file_sys/patch_manager.h"  #include "core/file_sys/vfs.h" @@ -29,8 +30,8 @@ IAccountProxyInterface::IAccountProxyInterface() : ServiceFramework{"IAccountPro  IAccountProxyInterface::~IAccountProxyInterface() = default; -IApplicationManagerInterface::IApplicationManagerInterface() -    : ServiceFramework{"IApplicationManagerInterface"} { +IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_) +    : ServiceFramework{"IApplicationManagerInterface"}, system{system_} {      // clang-format off      static const FunctionInfo functions[] = {          {0, nullptr, "ListApplicationRecord"}, @@ -298,7 +299,8 @@ void IApplicationManagerInterface::GetApplicationControlData(Kernel::HLERequestC      const auto size = ctx.GetWriteBufferSize(); -    const FileSys::PatchManager pm{title_id}; +    const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), +                                   system.GetContentProvider()};      const auto control = pm.GetControlMetadata();      std::vector<u8> out; @@ -538,14 +540,14 @@ IFactoryResetInterface::IFactoryResetInterface::IFactoryResetInterface()  IFactoryResetInterface::~IFactoryResetInterface() = default; -NS::NS(const char* name) : ServiceFramework{name} { +NS::NS(const char* name, Core::System& system_) : ServiceFramework{name}, system{system_} {      // clang-format off      static const FunctionInfo functions[] = {          {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"},          {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"},          {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"},          {7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"}, -        {7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"}, +        {7996, &NS::PushIApplicationManagerInterface, "GetApplicationManagerInterface"},          {7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"},          {7998, &NS::PushInterface<IContentManagementInterface>, "GetContentManagementInterface"},          {7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"}, @@ -558,7 +560,7 @@ NS::NS(const char* name) : ServiceFramework{name} {  NS::~NS() = default;  std::shared_ptr<IApplicationManagerInterface> NS::GetApplicationManagerInterface() const { -    return GetInterface<IApplicationManagerInterface>(); +    return GetInterface<IApplicationManagerInterface>(system);  }  class NS_DEV final : public ServiceFramework<NS_DEV> { @@ -678,11 +680,11 @@ public:  void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { -    std::make_shared<NS>("ns:am2")->InstallAsService(service_manager); -    std::make_shared<NS>("ns:ec")->InstallAsService(service_manager); -    std::make_shared<NS>("ns:rid")->InstallAsService(service_manager); -    std::make_shared<NS>("ns:rt")->InstallAsService(service_manager); -    std::make_shared<NS>("ns:web")->InstallAsService(service_manager); +    std::make_shared<NS>("ns:am2", system)->InstallAsService(service_manager); +    std::make_shared<NS>("ns:ec", system)->InstallAsService(service_manager); +    std::make_shared<NS>("ns:rid", system)->InstallAsService(service_manager); +    std::make_shared<NS>("ns:rt", system)->InstallAsService(service_manager); +    std::make_shared<NS>("ns:web", system)->InstallAsService(service_manager);      std::make_shared<NS_DEV>()->InstallAsService(service_manager);      std::make_shared<NS_SU>()->InstallAsService(service_manager); diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h index c2554b878..c90ccd755 100644 --- a/src/core/hle/service/ns/ns.h +++ b/src/core/hle/service/ns/ns.h @@ -6,6 +6,10 @@  #include "core/hle/service/service.h" +namespace Core { +class System; +} +  namespace Service {  namespace FileSystem { @@ -22,7 +26,7 @@ public:  class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> {  public: -    explicit IApplicationManagerInterface(); +    explicit IApplicationManagerInterface(Core::System& system_);      ~IApplicationManagerInterface() override;      ResultVal<u8> GetApplicationDesiredLanguage(u32 supported_languages); @@ -32,6 +36,8 @@ private:      void GetApplicationControlData(Kernel::HLERequestContext& ctx);      void GetApplicationDesiredLanguage(Kernel::HLERequestContext& ctx);      void ConvertApplicationLanguageToLanguageCode(Kernel::HLERequestContext& ctx); + +    Core::System& system;  };  class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> { @@ -72,13 +78,13 @@ public:  class NS final : public ServiceFramework<NS> {  public: -    explicit NS(const char* name); +    explicit NS(const char* name, Core::System& system_);      ~NS() override;      std::shared_ptr<IApplicationManagerInterface> GetApplicationManagerInterface() const;  private: -    template <typename T> +    template <typename T, typename... Args>      void PushInterface(Kernel::HLERequestContext& ctx) {          LOG_DEBUG(Service_NS, "called"); @@ -87,13 +93,23 @@ private:          rb.PushIpcInterface<T>();      } -    template <typename T> -    std::shared_ptr<T> GetInterface() const { +    void PushIApplicationManagerInterface(Kernel::HLERequestContext& ctx) { +        LOG_DEBUG(Service_NS, "called"); + +        IPC::ResponseBuilder rb{ctx, 2, 0, 1}; +        rb.Push(RESULT_SUCCESS); +        rb.PushIpcInterface<IApplicationManagerInterface>(system); +    } + +    template <typename T, typename... Args> +    std::shared_ptr<T> GetInterface(Args&&... args) const {          static_assert(std::is_base_of_v<Kernel::SessionRequestHandler, T>,                        "Not a base of ServiceFrameworkBase"); -        return std::make_shared<T>(); +        return std::make_shared<T>(std::forward<Args>(args)...);      } + +    Core::System& system;  };  /// Registers all NS services with the specified service manager. diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index 0240d6643..5681599ba 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h @@ -24,25 +24,37 @@ public:      explicit nvdevice(Core::System& system) : system{system} {}      virtual ~nvdevice() = default; -    union Ioctl { -        u32_le raw; -        BitField<0, 8, u32> cmd; -        BitField<8, 8, u32> group; -        BitField<16, 14, u32> length; -        BitField<30, 1, u32> is_in; -        BitField<31, 1, u32> is_out; -    }; +    /** +     * Handles an ioctl1 request. +     * @param command The ioctl command id. +     * @param input A buffer containing the input data for the ioctl. +     * @param output A buffer where the output data will be written to. +     * @returns The result code of the ioctl. +     */ +    virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, +                            std::vector<u8>& output) = 0; + +    /** +     * Handles an ioctl2 request. +     * @param command The ioctl command id. +     * @param input A buffer containing the input data for the ioctl. +     * @param inline_input A buffer containing the input data for the ioctl which has been inlined. +     * @param output A buffer where the output data will be written to. +     * @returns The result code of the ioctl. +     */ +    virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                            const std::vector<u8>& inline_input, std::vector<u8>& output) = 0;      /** -     * Handles an ioctl request. +     * Handles an ioctl3 request.       * @param command The ioctl command id.       * @param input A buffer containing the input data for the ioctl.       * @param output A buffer where the output data will be written to. +     * @param inline_output A buffer where the inlined output data will be written to.       * @returns The result code of the ioctl.       */ -    virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                      std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                      IoctlVersion version) = 0; +    virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                            std::vector<u8>& inline_output) = 0;  protected:      Core::System& system; diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 3f7b8e670..ce615c758 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -18,11 +18,22 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_de      : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}  nvdisp_disp0 ::~nvdisp_disp0() = default; -u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                        std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                        IoctlVersion version) { -    UNIMPLEMENTED_MSG("Unimplemented ioctl"); -    return 0; +NvResult nvdisp_disp0::Ioctl1(Ioctl command, const std::vector<u8>& input, +                              std::vector<u8>& output) { +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvdisp_disp0::Ioctl2(Ioctl command, const std::vector<u8>& input, +                              const std::vector<u8>& inline_input, std::vector<u8>& output) { +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvdisp_disp0::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                              std::vector<u8>& inline_output) { +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented;  }  void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index 6fcdeee84..55a33b7e4 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -20,9 +20,11 @@ public:      explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);      ~nvdisp_disp0() override; -    u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version) override; +    NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; +    NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output) override; +    NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                    std::vector<u8>& inline_output) override;      /// Performs a screen flip, drawing the buffer pointed to by the handle.      void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index f2529a12e..6b062e10e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -17,59 +17,77 @@  namespace Service::Nvidia::Devices { -namespace NvErrCodes { -constexpr u32 Success{}; -constexpr u32 OutOfMemory{static_cast<u32>(-12)}; -constexpr u32 InvalidInput{static_cast<u32>(-22)}; -} // namespace NvErrCodes -  nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)      : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}  nvhost_as_gpu::~nvhost_as_gpu() = default; -u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                         std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                         IoctlVersion version) { -    LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", -              command.raw, input.size(), output.size()); - -    switch (static_cast<IoctlCommand>(command.raw)) { -    case IoctlCommand::IocInitalizeExCommand: -        return InitalizeEx(input, output); -    case IoctlCommand::IocAllocateSpaceCommand: -        return AllocateSpace(input, output); -    case IoctlCommand::IocMapBufferExCommand: -        return MapBufferEx(input, output); -    case IoctlCommand::IocBindChannelCommand: -        return BindChannel(input, output); -    case IoctlCommand::IocGetVaRegionsCommand: -        return GetVARegions(input, output); -    case IoctlCommand::IocUnmapBufferCommand: -        return UnmapBuffer(input, output); -    case IoctlCommand::IocFreeSpaceCommand: -        return FreeSpace(input, output); +NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, +                               std::vector<u8>& output) { +    switch (command.group) { +    case 'A': +        switch (command.cmd) { +        case 0x1: +            return BindChannel(input, output); +        case 0x2: +            return AllocateSpace(input, output); +        case 0x3: +            return FreeSpace(input, output); +        case 0x5: +            return UnmapBuffer(input, output); +        case 0x6: +            return MapBufferEx(input, output); +        case 0x8: +            return GetVARegions(input, output); +        case 0x9: +            return InitalizeEx(input, output); +        case 0x14: +            return Remap(input, output); +        default: +            break; +        } +        break;      default:          break;      } -    if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand) { -        return Remap(input, output); -    } +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvhost_as_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input, +                               const std::vector<u8>& inline_input, std::vector<u8>& output) { +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} -    UNIMPLEMENTED_MSG("Unimplemented ioctl command"); -    return 0; +NvResult nvhost_as_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                               std::vector<u8>& inline_output) { +    switch (command.group) { +    case 'A': +        switch (command.cmd) { +        case 0x8: +            return GetVARegions(input, output, inline_output); +        default: +            break; +        } +        break; +    default: +        break; +    } +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented;  } -u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlInitalizeEx params{};      std::memcpy(¶ms, input.data(), input.size());      LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); -    return 0; +    return NvResult::Success;  } -u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlAllocSpace params{};      std::memcpy(¶ms, input.data(), input.size()); @@ -83,17 +101,17 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>&          params.offset = system.GPU().MemoryManager().Allocate(size, params.align);      } -    auto result{NvErrCodes::Success}; +    auto result = NvResult::Success;      if (!params.offset) {          LOG_CRITICAL(Service_NVDRV, "allocation failed for size {}", size); -        result = NvErrCodes::OutOfMemory; +        result = NvResult::InsufficientMemory;      }      std::memcpy(output.data(), ¶ms, output.size());      return result;  } -u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlFreeSpace params{};      std::memcpy(¶ms, input.data(), input.size()); @@ -104,15 +122,15 @@ u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& outp                                         static_cast<std::size_t>(params.pages) * params.page_size);      std::memcpy(output.data(), ¶ms, output.size()); -    return NvErrCodes::Success; +    return NvResult::Success;  } -u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {      const auto num_entries = input.size() / sizeof(IoctlRemapEntry);      LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries); -    auto result{NvErrCodes::Success}; +    auto result = NvResult::Success;      std::vector<IoctlRemapEntry> entries(num_entries);      std::memcpy(entries.data(), input.data(), input.size()); @@ -123,7 +141,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)          const auto object{nvmap_dev->GetObject(entry.nvmap_handle)};          if (!object) {              LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle); -            result = NvErrCodes::InvalidInput; +            result = NvResult::InvalidState;              break;          } @@ -134,7 +152,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)          if (!addr) {              LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!"); -            result = NvErrCodes::InvalidInput; +            result = NvResult::InvalidState;              break;          }      } @@ -143,7 +161,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)      return result;  } -u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlMapBufferEx params{};      std::memcpy(¶ms, input.data(), input.size()); @@ -157,7 +175,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou      if (!object) {          LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle);          std::memcpy(output.data(), ¶ms, output.size()); -        return NvErrCodes::InvalidInput; +        return NvResult::InvalidState;      }      // The real nvservices doesn't make a distinction between handles and ids, and @@ -184,16 +202,16 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou                               params.mapping_size, params.offset);                  std::memcpy(output.data(), ¶ms, output.size()); -                return NvErrCodes::InvalidInput; +                return NvResult::InvalidState;              }              std::memcpy(output.data(), ¶ms, output.size()); -            return NvErrCodes::Success; +            return NvResult::Success;          } else {              LOG_CRITICAL(Service_NVDRV, "address not mapped offset={}", params.offset);              std::memcpy(output.data(), ¶ms, output.size()); -            return NvErrCodes::InvalidInput; +            return NvResult::InvalidState;          }      } @@ -213,10 +231,10 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou          params.offset = gpu.MemoryManager().Map(physical_address, params.offset, size);      } -    auto result{NvErrCodes::Success}; +    auto result = NvResult::Success;      if (!params.offset) {          LOG_CRITICAL(Service_NVDRV, "failed to map size={}", size); -        result = NvErrCodes::InvalidInput; +        result = NvResult::InvalidState;      } else {          AddBufferMap(params.offset, size, physical_address, is_alloc);      } @@ -225,7 +243,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou      return result;  } -u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlUnmapBuffer params{};      std::memcpy(¶ms, input.data(), input.size()); @@ -238,20 +256,42 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou      }      std::memcpy(output.data(), ¶ms, output.size()); -    return NvErrCodes::Success; +    return NvResult::Success;  } -u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlBindChannel params{};      std::memcpy(¶ms, input.data(), input.size()); - -    LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); +    LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}", params.fd);      channel = params.fd; -    return 0; +    return NvResult::Success; +} + +NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { +    IoctlGetVaRegions params{}; +    std::memcpy(¶ms, input.data(), input.size()); + +    LOG_WARNING(Service_NVDRV, "(STUBBED) called, buf_addr={:X}, buf_size={:X}", params.buf_addr, +                params.buf_size); + +    params.buf_size = 0x30; +    params.regions[0].offset = 0x04000000; +    params.regions[0].page_size = 0x1000; +    params.regions[0].pages = 0x3fbfff; + +    params.regions[1].offset = 0x04000000; +    params.regions[1].page_size = 0x10000; +    params.regions[1].pages = 0x1bffff; + +    // TODO(ogniK): This probably can stay stubbed but should add support way way later + +    std::memcpy(output.data(), ¶ms, output.size()); +    return NvResult::Success;  } -u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output, +                                     std::vector<u8>& inline_output) {      IoctlGetVaRegions params{};      std::memcpy(¶ms, input.data(), input.size()); @@ -270,7 +310,8 @@ u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& o      // TODO(ogniK): This probably can stay stubbed but should add support way way later      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    std::memcpy(inline_output.data(), ¶ms.regions, inline_output.size()); +    return NvResult::Success;  }  std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gpu_addr) const { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index fcdb40d93..08035fa0e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -30,9 +30,11 @@ public:      explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);      ~nvhost_as_gpu() override; -    u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version) override; +    NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; +    NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output) override; +    NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                    std::vector<u8>& inline_output) override;  private:      class BufferMap final { @@ -74,32 +76,21 @@ private:          bool is_allocated{};      }; -    enum class IoctlCommand : u32_le { -        IocInitalizeExCommand = 0x40284109, -        IocAllocateSpaceCommand = 0xC0184102, -        IocRemapCommand = 0x00000014, -        IocMapBufferExCommand = 0xC0284106, -        IocBindChannelCommand = 0x40044101, -        IocGetVaRegionsCommand = 0xC0404108, -        IocUnmapBufferCommand = 0xC0084105, -        IocFreeSpaceCommand = 0xC0104103, -    }; -      struct IoctlInitalizeEx { -        u32_le big_page_size; // depends on GPU's available_big_page_sizes; 0=default -        s32_le as_fd;         // ignored; passes 0 -        u32_le flags;         // passes 0 -        u32_le reserved;      // ignored; passes 0 -        u64_le unk0; -        u64_le unk1; -        u64_le unk2; +        u32_le big_page_size{}; // depends on GPU's available_big_page_sizes; 0=default +        s32_le as_fd{};         // ignored; passes 0 +        u32_le flags{};         // passes 0 +        u32_le reserved{};      // ignored; passes 0 +        u64_le unk0{}; +        u64_le unk1{}; +        u64_le unk2{};      };      static_assert(sizeof(IoctlInitalizeEx) == 40, "IoctlInitalizeEx is incorrect size");      struct IoctlAllocSpace { -        u32_le pages; -        u32_le page_size; -        AddressSpaceFlags flags; +        u32_le pages{}; +        u32_le page_size{}; +        AddressSpaceFlags flags{};          INSERT_PADDING_WORDS(1);          union {              u64_le offset; @@ -109,70 +100,73 @@ private:      static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size");      struct IoctlFreeSpace { -        u64_le offset; -        u32_le pages; -        u32_le page_size; +        u64_le offset{}; +        u32_le pages{}; +        u32_le page_size{};      };      static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size");      struct IoctlRemapEntry { -        u16_le flags; -        u16_le kind; -        u32_le nvmap_handle; -        u32_le map_offset; -        u32_le offset; -        u32_le pages; +        u16_le flags{}; +        u16_le kind{}; +        u32_le nvmap_handle{}; +        u32_le map_offset{}; +        u32_le offset{}; +        u32_le pages{};      };      static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size");      struct IoctlMapBufferEx { -        AddressSpaceFlags flags; // bit0: fixed_offset, bit2: cacheable -        u32_le kind;             // -1 is default -        u32_le nvmap_handle; -        u32_le page_size; // 0 means don't care -        s64_le buffer_offset; -        u64_le mapping_size; -        s64_le offset; +        AddressSpaceFlags flags{}; // bit0: fixed_offset, bit2: cacheable +        u32_le kind{};             // -1 is default +        u32_le nvmap_handle{}; +        u32_le page_size{}; // 0 means don't care +        s64_le buffer_offset{}; +        u64_le mapping_size{}; +        s64_le offset{};      };      static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size");      struct IoctlUnmapBuffer { -        s64_le offset; +        s64_le offset{};      };      static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size");      struct IoctlBindChannel { -        u32_le fd; +        s32_le fd{};      };      static_assert(sizeof(IoctlBindChannel) == 4, "IoctlBindChannel is incorrect size");      struct IoctlVaRegion { -        u64_le offset; -        u32_le page_size; +        u64_le offset{}; +        u32_le page_size{};          INSERT_PADDING_WORDS(1); -        u64_le pages; +        u64_le pages{};      };      static_assert(sizeof(IoctlVaRegion) == 24, "IoctlVaRegion is incorrect size");      struct IoctlGetVaRegions { -        u64_le buf_addr; // (contained output user ptr on linux, ignored) -        u32_le buf_size; // forced to 2*sizeof(struct va_region) -        u32_le reserved; -        IoctlVaRegion regions[2]; +        u64_le buf_addr{}; // (contained output user ptr on linux, ignored) +        u32_le buf_size{}; // forced to 2*sizeof(struct va_region) +        u32_le reserved{}; +        IoctlVaRegion regions[2]{};      };      static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2,                    "IoctlGetVaRegions is incorrect size"); -    u32 channel{}; +    s32 channel{}; + +    NvResult InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult Remap(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult FreeSpace(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult BindChannel(const std::vector<u8>& input, std::vector<u8>& output); -    u32 InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output); -    u32 AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output); -    u32 Remap(const std::vector<u8>& input, std::vector<u8>& output); -    u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output); -    u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); -    u32 FreeSpace(const std::vector<u8>& input, std::vector<u8>& output); -    u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output); -    u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output, +                          std::vector<u8>& inline_output);      std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;      void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 8356a8139..d90cf90a8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -20,41 +20,54 @@ nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface,      : nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {}  nvhost_ctrl::~nvhost_ctrl() = default; -u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                       std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                       IoctlVersion version) { -    LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", -              command.raw, input.size(), output.size()); - -    switch (static_cast<IoctlCommand>(command.raw)) { -    case IoctlCommand::IocGetConfigCommand: -        return NvOsGetConfigU32(input, output); -    case IoctlCommand::IocCtrlEventWaitCommand: -        return IocCtrlEventWait(input, output, false, ctrl); -    case IoctlCommand::IocCtrlEventWaitAsyncCommand: -        return IocCtrlEventWait(input, output, true, ctrl); -    case IoctlCommand::IocCtrlEventRegisterCommand: -        return IocCtrlEventRegister(input, output); -    case IoctlCommand::IocCtrlEventUnregisterCommand: -        return IocCtrlEventUnregister(input, output); -    case IoctlCommand::IocCtrlClearEventWaitCommand: -        return IocCtrlClearEventWait(input, output); +NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { +    switch (command.group) { +    case 0x0: +        switch (command.cmd) { +        case 0x1b: +            return NvOsGetConfigU32(input, output); +        case 0x1c: +            return IocCtrlClearEventWait(input, output); +        case 0x1d: +            return IocCtrlEventWait(input, output, false); +        case 0x1e: +            return IocCtrlEventWait(input, output, true); +        case 0x1f: +            return IocCtrlEventRegister(input, output); +        case 0x20: +            return IocCtrlEventUnregister(input, output); +        } +        break;      default: -        UNIMPLEMENTED_MSG("Unimplemented ioctl"); -        return 0; +        break;      } + +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvhost_ctrl::Ioctl2(Ioctl command, const std::vector<u8>& input, +                             const std::vector<u8>& inline_input, std::vector<u8>& output) { +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvhost_ctrl::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                             std::vector<u8>& inline_output) { +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented;  } -u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) {      IocGetConfigParams params{};      std::memcpy(¶ms, input.data(), sizeof(params));      LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(),                params.param_str.data()); -    return 0x30006; // Returns error on production mode +    return NvResult::ConfigVarNotFound; // Returns error on production mode  } -u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, -                                  bool is_async, IoctlCtrl& ctrl) { +NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, +                                       bool is_async) {      IocCtrlEventWaitParams params{};      std::memcpy(¶ms, input.data(), sizeof(params));      LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}", @@ -126,10 +139,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&          params.value |= event_id;          event.event.writable->Clear();          gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); -        if (!is_async && ctrl.fresh_call) { -            ctrl.must_delay = true; -            ctrl.timeout = params.timeout; -            ctrl.event_id = event_id; +        if (!is_async) {              return NvResult::Timeout;          }          std::memcpy(output.data(), ¶ms, sizeof(params)); @@ -139,7 +149,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&      return NvResult::BadParameter;  } -u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) {      IocCtrlEventRegisterParams params{};      std::memcpy(¶ms, input.data(), sizeof(params));      const u32 event_id = params.user_event_id & 0x00FF; @@ -154,7 +164,8 @@ u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<      return NvResult::Success;  } -u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, +                                             std::vector<u8>& output) {      IocCtrlEventUnregisterParams params{};      std::memcpy(¶ms, input.data(), sizeof(params));      const u32 event_id = params.user_event_id & 0x00FF; @@ -169,7 +180,7 @@ u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vecto      return NvResult::Success;  } -u32 nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) {      IocCtrlEventSignalParams params{};      std::memcpy(¶ms, input.data(), sizeof(params)); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 24ad96cb9..c5aa1362a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -18,132 +18,113 @@ public:                           SyncpointManager& syncpoint_manager);      ~nvhost_ctrl() override; -    u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version) override; +    NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; +    NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output) override; +    NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                    std::vector<u8>& inline_output) override;  private: -    enum class IoctlCommand : u32_le { -        IocSyncptReadCommand = 0xC0080014, -        IocSyncptIncrCommand = 0x40040015, -        IocSyncptWaitCommand = 0xC00C0016, -        IocModuleMutexCommand = 0x40080017, -        IocModuleRegRDWRCommand = 0xC0180018, -        IocSyncptWaitexCommand = 0xC0100019, -        IocSyncptReadMaxCommand = 0xC008001A, -        IocGetConfigCommand = 0xC183001B, -        IocCtrlClearEventWaitCommand = 0xC004001C, -        IocCtrlEventWaitCommand = 0xC010001D, -        IocCtrlEventWaitAsyncCommand = 0xC010001E, -        IocCtrlEventRegisterCommand = 0xC004001F, -        IocCtrlEventUnregisterCommand = 0xC0040020, -        IocCtrlEventKillCommand = 0x40080021, -    };      struct IocSyncptReadParams { -        u32_le id; -        u32_le value; +        u32_le id{}; +        u32_le value{};      };      static_assert(sizeof(IocSyncptReadParams) == 8, "IocSyncptReadParams is incorrect size");      struct IocSyncptIncrParams { -        u32_le id; +        u32_le id{};      };      static_assert(sizeof(IocSyncptIncrParams) == 4, "IocSyncptIncrParams is incorrect size");      struct IocSyncptWaitParams { -        u32_le id; -        u32_le thresh; -        s32_le timeout; +        u32_le id{}; +        u32_le thresh{}; +        s32_le timeout{};      };      static_assert(sizeof(IocSyncptWaitParams) == 12, "IocSyncptWaitParams is incorrect size");      struct IocModuleMutexParams { -        u32_le id; -        u32_le lock; // (0 = unlock and 1 = lock) +        u32_le id{}; +        u32_le lock{}; // (0 = unlock and 1 = lock)      };      static_assert(sizeof(IocModuleMutexParams) == 8, "IocModuleMutexParams is incorrect size");      struct IocModuleRegRDWRParams { -        u32_le id; -        u32_le num_offsets; -        u32_le block_size; -        u32_le offsets; -        u32_le values; -        u32_le write; +        u32_le id{}; +        u32_le num_offsets{}; +        u32_le block_size{}; +        u32_le offsets{}; +        u32_le values{}; +        u32_le write{};      };      static_assert(sizeof(IocModuleRegRDWRParams) == 24, "IocModuleRegRDWRParams is incorrect size");      struct IocSyncptWaitexParams { -        u32_le id; -        u32_le thresh; -        s32_le timeout; -        u32_le value; +        u32_le id{}; +        u32_le thresh{}; +        s32_le timeout{}; +        u32_le value{};      };      static_assert(sizeof(IocSyncptWaitexParams) == 16, "IocSyncptWaitexParams is incorrect size");      struct IocSyncptReadMaxParams { -        u32_le id; -        u32_le value; +        u32_le id{}; +        u32_le value{};      };      static_assert(sizeof(IocSyncptReadMaxParams) == 8, "IocSyncptReadMaxParams is incorrect size");      struct IocGetConfigParams { -        std::array<char, 0x41> domain_str; -        std::array<char, 0x41> param_str; -        std::array<char, 0x101> config_str; +        std::array<char, 0x41> domain_str{}; +        std::array<char, 0x41> param_str{}; +        std::array<char, 0x101> config_str{};      };      static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size");      struct IocCtrlEventSignalParams { -        u32_le event_id; +        u32_le event_id{};      };      static_assert(sizeof(IocCtrlEventSignalParams) == 4,                    "IocCtrlEventSignalParams is incorrect size");      struct IocCtrlEventWaitParams { -        u32_le syncpt_id; -        u32_le threshold; -        s32_le timeout; -        u32_le value; +        u32_le syncpt_id{}; +        u32_le threshold{}; +        s32_le timeout{}; +        u32_le value{};      };      static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size");      struct IocCtrlEventWaitAsyncParams { -        u32_le syncpt_id; -        u32_le threshold; -        u32_le timeout; -        u32_le value; +        u32_le syncpt_id{}; +        u32_le threshold{}; +        u32_le timeout{}; +        u32_le value{};      };      static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16,                    "IocCtrlEventWaitAsyncParams is incorrect size");      struct IocCtrlEventRegisterParams { -        u32_le user_event_id; +        u32_le user_event_id{};      };      static_assert(sizeof(IocCtrlEventRegisterParams) == 4,                    "IocCtrlEventRegisterParams is incorrect size");      struct IocCtrlEventUnregisterParams { -        u32_le user_event_id; +        u32_le user_event_id{};      };      static_assert(sizeof(IocCtrlEventUnregisterParams) == 4,                    "IocCtrlEventUnregisterParams is incorrect size");      struct IocCtrlEventKill { -        u64_le user_events; +        u64_le user_events{};      };      static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size"); -    u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); - -    u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async, -                         IoctlCtrl& ctrl); - -    u32 IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output); - -    u32 IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output); - -    u32 IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async); +    NvResult IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output);      EventInterface& events_interface;      SyncpointManager& syncpoint_manager; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index fba89e7a6..2d7ea433c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -15,39 +15,66 @@ namespace Service::Nvidia::Devices {  nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {}  nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; -u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, -                           const std::vector<u8>& input2, std::vector<u8>& output, -                           std::vector<u8>& output2, IoctlCtrl& ctrl, IoctlVersion version) { -    LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", -              command.raw, input.size(), output.size()); - -    switch (static_cast<IoctlCommand>(command.raw)) { -    case IoctlCommand::IocGetCharacteristicsCommand: -        return GetCharacteristics(input, output, output2, version); -    case IoctlCommand::IocGetTPCMasksCommand: -        return GetTPCMasks(input, output, output2, version); -    case IoctlCommand::IocGetActiveSlotMaskCommand: -        return GetActiveSlotMask(input, output); -    case IoctlCommand::IocZcullGetCtxSizeCommand: -        return ZCullGetCtxSize(input, output); -    case IoctlCommand::IocZcullGetInfo: -        return ZCullGetInfo(input, output); -    case IoctlCommand::IocZbcSetTable: -        return ZBCSetTable(input, output); -    case IoctlCommand::IocZbcQueryTable: -        return ZBCQueryTable(input, output); -    case IoctlCommand::IocFlushL2: -        return FlushL2(input, output); -    case IoctlCommand::IocGetGpuTime: -        return GetGpuTime(input, output); +NvResult nvhost_ctrl_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, +                                 std::vector<u8>& output) { +    switch (command.group) { +    case 'G': +        switch (command.cmd) { +        case 0x1: +            return ZCullGetCtxSize(input, output); +        case 0x2: +            return ZCullGetInfo(input, output); +        case 0x3: +            return ZBCSetTable(input, output); +        case 0x4: +            return ZBCQueryTable(input, output); +        case 0x5: +            return GetCharacteristics(input, output); +        case 0x6: +            return GetTPCMasks(input, output); +        case 0x7: +            return FlushL2(input, output); +        case 0x14: +            return GetActiveSlotMask(input, output); +        case 0x1c: +            return GetGpuTime(input, output); +        default: +            break; +        } +        break; +    } +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvhost_ctrl_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input, +                                 const std::vector<u8>& inline_input, std::vector<u8>& output) { +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvhost_ctrl_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, +                                 std::vector<u8>& output, std::vector<u8>& inline_output) { +    switch (command.group) { +    case 'G': +        switch (command.cmd) { +        case 0x5: +            return GetCharacteristics(input, output, inline_output); +        case 0x6: +            return GetTPCMasks(input, output, inline_output); +        default: +            break; +        } +        break;      default: -        UNIMPLEMENTED_MSG("Unimplemented ioctl"); -        return 0; +        break;      } +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented;  } -u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, -                                        std::vector<u8>& output2, IoctlVersion version) { +NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, +                                             std::vector<u8>& output) {      LOG_DEBUG(Service_NVDRV, "called");      IoctlCharacteristics params{};      std::memcpy(¶ms, input.data(), input.size()); @@ -88,36 +115,83 @@ u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vecto      params.gc.gr_compbit_store_base_hw = 0x0;      params.gpu_characteristics_buf_size = 0xA0;      params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) +    std::memcpy(output.data(), ¶ms, output.size()); +    return NvResult::Success; +} -    if (version == IoctlVersion::Version3) { -        std::memcpy(output.data(), input.data(), output.size()); -        std::memcpy(output2.data(), ¶ms.gc, output2.size()); -    } else { -        std::memcpy(output.data(), ¶ms, output.size()); -    } -    return 0; +NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, +                                             std::vector<u8>& inline_output) { +    LOG_DEBUG(Service_NVDRV, "called"); +    IoctlCharacteristics params{}; +    std::memcpy(¶ms, input.data(), input.size()); +    params.gc.arch = 0x120; +    params.gc.impl = 0xb; +    params.gc.rev = 0xa1; +    params.gc.num_gpc = 0x1; +    params.gc.l2_cache_size = 0x40000; +    params.gc.on_board_video_memory_size = 0x0; +    params.gc.num_tpc_per_gpc = 0x2; +    params.gc.bus_type = 0x20; +    params.gc.big_page_size = 0x20000; +    params.gc.compression_page_size = 0x20000; +    params.gc.pde_coverage_bit_count = 0x1B; +    params.gc.available_big_page_sizes = 0x30000; +    params.gc.gpc_mask = 0x1; +    params.gc.sm_arch_sm_version = 0x503; +    params.gc.sm_arch_spa_version = 0x503; +    params.gc.sm_arch_warp_count = 0x80; +    params.gc.gpu_va_bit_count = 0x28; +    params.gc.reserved = 0x0; +    params.gc.flags = 0x55; +    params.gc.twod_class = 0x902D; +    params.gc.threed_class = 0xB197; +    params.gc.compute_class = 0xB1C0; +    params.gc.gpfifo_class = 0xB06F; +    params.gc.inline_to_memory_class = 0xA140; +    params.gc.dma_copy_class = 0xB0B5; +    params.gc.max_fbps_count = 0x1; +    params.gc.fbp_en_mask = 0x0; +    params.gc.max_ltc_per_fbp = 0x2; +    params.gc.max_lts_per_ltc = 0x1; +    params.gc.max_tex_per_tpc = 0x0; +    params.gc.max_gpc_count = 0x1; +    params.gc.rop_l2_en_mask_0 = 0x21D70; +    params.gc.rop_l2_en_mask_1 = 0x0; +    params.gc.chipname = 0x6230326D67; +    params.gc.gr_compbit_store_base_hw = 0x0; +    params.gpu_characteristics_buf_size = 0xA0; +    params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) + +    std::memcpy(output.data(), input.data(), output.size()); +    std::memcpy(inline_output.data(), ¶ms.gc, inline_output.size()); +    return NvResult::Success;  } -u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, -                                 std::vector<u8>& output2, IoctlVersion version) { +NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlGpuGetTpcMasksArgs params{};      std::memcpy(¶ms, input.data(), input.size());      LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);      if (params.mask_buffer_size != 0) {          params.tcp_mask = 3;      } +    std::memcpy(output.data(), ¶ms, output.size()); +    return NvResult::Success; +} -    if (version == IoctlVersion::Version3) { -        std::memcpy(output.data(), input.data(), output.size()); -        std::memcpy(output2.data(), ¶ms.tcp_mask, output2.size()); -    } else { -        std::memcpy(output.data(), ¶ms, output.size()); +NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, +                                      std::vector<u8>& inline_output) { +    IoctlGpuGetTpcMasksArgs params{}; +    std::memcpy(¶ms, input.data(), input.size()); +    LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); +    if (params.mask_buffer_size != 0) { +        params.tcp_mask = 3;      } - -    return 0; +    std::memcpy(output.data(), ¶ms, output.size()); +    std::memcpy(inline_output.data(), ¶ms.tcp_mask, inline_output.size()); +    return NvResult::Success;  } -u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) {      LOG_DEBUG(Service_NVDRV, "called");      IoctlActiveSlotMask params{}; @@ -127,10 +201,10 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector      params.slot = 0x07;      params.mask = 0x01;      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) {      LOG_DEBUG(Service_NVDRV, "called");      IoctlZcullGetCtxSize params{}; @@ -139,10 +213,10 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u      }      params.size = 0x1;      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) {      LOG_DEBUG(Service_NVDRV, "called");      IoctlNvgpuGpuZcullGetInfoArgs params{}; @@ -162,47 +236,47 @@ u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>&      params.subregion_height_align_pixels = 0x40;      params.subregion_count = 0x10;      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) {      LOG_WARNING(Service_NVDRV, "(STUBBED) called");      IoctlZbcSetTable params{};      std::memcpy(¶ms, input.data(), input.size());      // TODO(ogniK): What does this even actually do?      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) {      LOG_WARNING(Service_NVDRV, "(STUBBED) called");      IoctlZbcQueryTable params{};      std::memcpy(¶ms, input.data(), input.size());      // TODO : To implement properly      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) {      LOG_WARNING(Service_NVDRV, "(STUBBED) called");      IoctlFlushL2 params{};      std::memcpy(¶ms, input.data(), input.size());      // TODO : To implement properly      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) {      LOG_DEBUG(Service_NVDRV, "called");      IoctlGetGpuTime params{};      std::memcpy(¶ms, input.data(), input.size());      params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count());      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  }  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index ef60f72ce..137b88238 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h @@ -16,32 +16,13 @@ public:      explicit nvhost_ctrl_gpu(Core::System& system);      ~nvhost_ctrl_gpu() override; -    u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version) override; +    NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; +    NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output) override; +    NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                    std::vector<u8>& inline_output) override;  private: -    enum class IoctlCommand : u32_le { -        IocGetCharacteristicsCommand = 0xC0B04705, -        IocGetTPCMasksCommand = 0xC0184706, -        IocGetActiveSlotMaskCommand = 0x80084714, -        IocZcullGetCtxSizeCommand = 0x80044701, -        IocZcullGetInfo = 0x80284702, -        IocZbcSetTable = 0x402C4703, -        IocZbcQueryTable = 0xC0344704, -        IocFlushL2 = 0x40084707, -        IocInvalICache = 0x4008470D, -        IocSetMmudebugMode = 0x4008470E, -        IocSetSmDebugMode = 0x4010470F, -        IocWaitForPause = 0xC0084710, -        IocGetTcpExceptionEnStatus = 0x80084711, -        IocNumVsms = 0x80084712, -        IocVsmsMapping = 0xC0044713, -        IocGetErrorChannelUserData = 0xC008471B, -        IocGetGpuTime = 0xC010471C, -        IocGetCpuTimeCorrelationInfo = 0xC108471D, -    }; -      struct IoctlGpuCharacteristics {          u32_le arch;                       // 0x120 (NVGPU_GPU_ARCH_GM200)          u32_le impl;                       // 0xB (NVGPU_GPU_IMPL_GM20B) @@ -159,17 +140,21 @@ private:      };      static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); -    u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, -                           std::vector<u8>& output2, IoctlVersion version); -    u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, std::vector<u8>& output2, -                    IoctlVersion version); -    u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); -    u32 ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); -    u32 ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output); -    u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); -    u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); -    u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output); -    u32 GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, +                                std::vector<u8>& inline_output); + +    NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, +                         std::vector<u8>& inline_output); + +    NvResult GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult FlushL2(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output);  };  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 152019548..af8b3d9f1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -23,107 +23,132 @@ nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,  nvhost_gpu::~nvhost_gpu() = default; -u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                      std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                      IoctlVersion version) { -    LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", -              command.raw, input.size(), output.size()); - -    switch (static_cast<IoctlCommand>(command.raw)) { -    case IoctlCommand::IocSetNVMAPfdCommand: -        return SetNVMAPfd(input, output); -    case IoctlCommand::IocSetClientDataCommand: -        return SetClientData(input, output); -    case IoctlCommand::IocGetClientDataCommand: -        return GetClientData(input, output); -    case IoctlCommand::IocZCullBind: -        return ZCullBind(input, output); -    case IoctlCommand::IocSetErrorNotifierCommand: -        return SetErrorNotifier(input, output); -    case IoctlCommand::IocChannelSetPriorityCommand: -        return SetChannelPriority(input, output); -    case IoctlCommand::IocAllocGPFIFOEx2Command: -        return AllocGPFIFOEx2(input, output); -    case IoctlCommand::IocAllocObjCtxCommand: -        return AllocateObjectContext(input, output); -    case IoctlCommand::IocChannelGetWaitbaseCommand: -        return GetWaitbase(input, output); -    case IoctlCommand::IocChannelSetTimeoutCommand: -        return ChannelSetTimeout(input, output); -    case IoctlCommand::IocChannelSetTimeslice: -        return ChannelSetTimeslice(input, output); -    default: +NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { +    switch (command.group) { +    case 0x0: +        switch (command.cmd) { +        case 0x3: +            return GetWaitbase(input, output); +        default: +            break; +        } +        break; +    case 'H': +        switch (command.cmd) { +        case 0x1: +            return SetNVMAPfd(input, output); +        case 0x3: +            return ChannelSetTimeout(input, output); +        case 0x8: +            return SubmitGPFIFOBase(input, output, false); +        case 0x9: +            return AllocateObjectContext(input, output); +        case 0xb: +            return ZCullBind(input, output); +        case 0xc: +            return SetErrorNotifier(input, output); +        case 0xd: +            return SetChannelPriority(input, output); +        case 0x1a: +            return AllocGPFIFOEx2(input, output); +        case 0x1b: +            return SubmitGPFIFOBase(input, output, true); +        case 0x1d: +            return ChannelSetTimeslice(input, output); +        default: +            break; +        } +        break; +    case 'G': +        switch (command.cmd) { +        case 0x14: +            return SetClientData(input, output); +        case 0x15: +            return GetClientData(input, output); +        default: +            break; +        }          break;      } +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +}; -    if (command.group == NVGPU_IOCTL_MAGIC) { -        if (command.cmd == NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO) { -            return SubmitGPFIFO(input, output); -        } -        if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) { -            return KickoffPB(input, output, input2, version); +NvResult nvhost_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input, +                            const std::vector<u8>& inline_input, std::vector<u8>& output) { +    switch (command.group) { +    case 'H': +        switch (command.cmd) { +        case 0x1b: +            return SubmitGPFIFOBase(input, inline_input, output);          } +        break;      } +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} -    UNIMPLEMENTED_MSG("Unimplemented ioctl"); -    return 0; -}; +NvResult nvhost_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                            std::vector<u8>& inline_output) { +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} -u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlSetNvmapFD params{};      std::memcpy(¶ms, input.data(), input.size());      LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);      nvmap_fd = params.nvmap_fd; -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) {      LOG_DEBUG(Service_NVDRV, "called");      IoctlClientData params{};      std::memcpy(¶ms, input.data(), input.size());      user_data = params.data; -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) {      LOG_DEBUG(Service_NVDRV, "called");      IoctlClientData params{};      std::memcpy(¶ms, input.data(), input.size());      params.data = user_data;      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) {      std::memcpy(&zcull_params, input.data(), input.size());      LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,                zcull_params.mode);      std::memcpy(output.data(), &zcull_params, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlSetErrorNotifier params{};      std::memcpy(¶ms, input.data(), input.size());      LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,                  params.size, params.mem);      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) {      std::memcpy(&channel_priority, input.data(), input.size());      LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlAllocGpfifoEx2 params{};      std::memcpy(¶ms, input.data(), input.size());      LOG_WARNING(Service_NVDRV, @@ -137,10 +162,10 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou      params.fence_out = channel_fence;      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlAllocObjCtx params{};      std::memcpy(¶ms, input.data(), input.size());      LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, @@ -148,7 +173,7 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<      params.obj_id = 0x0;      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  }  static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) { @@ -192,8 +217,8 @@ static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(Fence      return result;  } -u32 nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, -                                 Tegra::CommandList&& entries) { +NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, +                                      Tegra::CommandList&& entries) {      LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,                params.num_entries, params.flags.raw); @@ -214,7 +239,6 @@ u32 nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& out          params.fence_out.value = syncpoint_manager.GetSyncpointMax(params.fence_out.id);      } -    entries.RefreshIntegrityChecks(gpu);      gpu.PushGPUEntries(std::move(entries));      if (params.flags.add_increment.Value()) { @@ -228,69 +252,70 @@ u32 nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& out      }      std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output, +                                      bool kickoff) {      if (input.size() < sizeof(IoctlSubmitGpfifo)) {          UNIMPLEMENTED(); +        return NvResult::InvalidSize;      }      IoctlSubmitGpfifo params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); -      Tegra::CommandList entries(params.num_entries); -    std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)], -                params.num_entries * sizeof(Tegra::CommandListHeader)); + +    if (kickoff) { +        system.Memory().ReadBlock(params.address, entries.command_lists.data(), +                                  params.num_entries * sizeof(Tegra::CommandListHeader)); +    } else { +        std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)], +                    params.num_entries * sizeof(Tegra::CommandListHeader)); +    }      return SubmitGPFIFOImpl(params, output, std::move(entries));  } -u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, -                          const std::vector<u8>& input2, IoctlVersion version) { +NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, +                                      const std::vector<u8>& input_inline, +                                      std::vector<u8>& output) {      if (input.size() < sizeof(IoctlSubmitGpfifo)) {          UNIMPLEMENTED(); +        return NvResult::InvalidSize;      }      IoctlSubmitGpfifo params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); -      Tegra::CommandList entries(params.num_entries); -    if (version == IoctlVersion::Version2) { -        std::memcpy(entries.command_lists.data(), input2.data(), -                    params.num_entries * sizeof(Tegra::CommandListHeader)); -    } else { -        system.Memory().ReadBlock(params.address, entries.command_lists.data(), -                                  params.num_entries * sizeof(Tegra::CommandListHeader)); -    } - +    std::memcpy(entries.command_lists.data(), input_inline.data(), input_inline.size());      return SubmitGPFIFOImpl(params, output, std::move(entries));  } -u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlGetWaitbase params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));      LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);      params.value = 0; // Seems to be hard coded at 0      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlChannelSetTimeout params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout));      LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlSetTimeslice params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice));      LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice);      channel_timeslice = params.timeslice; -    return 0; +    return NvResult::Success;  }  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index a252fc06d..e0298b4fe 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -20,43 +20,19 @@ class SyncpointManager;  namespace Service::Nvidia::Devices {  class nvmap; -constexpr u32 NVGPU_IOCTL_MAGIC('H'); -constexpr u32 NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO(0x8); -constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b); -  class nvhost_gpu final : public nvdevice {  public:      explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,                          SyncpointManager& syncpoint_manager);      ~nvhost_gpu() override; -    u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version) override; +    NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; +    NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output) override; +    NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                    std::vector<u8>& inline_output) override;  private: -    enum class IoctlCommand : u32_le { -        IocSetNVMAPfdCommand = 0x40044801, -        IocAllocGPFIFOCommand = 0x40084805, -        IocSetClientDataCommand = 0x40084714, -        IocGetClientDataCommand = 0x80084715, -        IocZCullBind = 0xc010480b, -        IocSetErrorNotifierCommand = 0xC018480C, -        IocChannelSetPriorityCommand = 0x4004480D, -        IocEnableCommand = 0x0000480E, -        IocDisableCommand = 0x0000480F, -        IocPreemptCommand = 0x00004810, -        IocForceResetCommand = 0x00004811, -        IocEventIdControlCommand = 0x40084812, -        IocGetErrorNotificationCommand = 0xC0104817, -        IocAllocGPFIFOExCommand = 0x40204818, -        IocAllocGPFIFOEx2Command = 0xC020481A, -        IocAllocObjCtxCommand = 0xC0104809, -        IocChannelGetWaitbaseCommand = 0xC0080003, -        IocChannelSetTimeoutCommand = 0x40044803, -        IocChannelSetTimeslice = 0xC004481D, -    }; -      enum class CtxObjects : u32_le {          Ctx2D = 0x902D,          Ctx3D = 0xB197, @@ -67,63 +43,63 @@ private:      };      struct IoctlSetNvmapFD { -        u32_le nvmap_fd; +        s32_le nvmap_fd{};      };      static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");      struct IoctlChannelSetTimeout { -        u32_le timeout; +        u32_le timeout{};      };      static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size");      struct IoctlAllocGPFIFO { -        u32_le num_entries; -        u32_le flags; +        u32_le num_entries{}; +        u32_le flags{};      };      static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size");      struct IoctlClientData { -        u64_le data; +        u64_le data{};      };      static_assert(sizeof(IoctlClientData) == 8, "IoctlClientData is incorrect size");      struct IoctlZCullBind { -        u64_le gpu_va; -        u32_le mode; // 0=global, 1=no_ctxsw, 2=separate_buffer, 3=part_of_regular_buf +        u64_le gpu_va{}; +        u32_le mode{}; // 0=global, 1=no_ctxsw, 2=separate_buffer, 3=part_of_regular_buf          INSERT_PADDING_WORDS(1);      };      static_assert(sizeof(IoctlZCullBind) == 16, "IoctlZCullBind is incorrect size");      struct IoctlSetErrorNotifier { -        u64_le offset; -        u64_le size; -        u32_le mem; // nvmap object handle +        u64_le offset{}; +        u64_le size{}; +        u32_le mem{}; // nvmap object handle          INSERT_PADDING_WORDS(1);      };      static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size");      struct IoctlChannelSetPriority { -        u32_le priority; +        u32_le priority{};      };      static_assert(sizeof(IoctlChannelSetPriority) == 4,                    "IoctlChannelSetPriority is incorrect size");      struct IoctlSetTimeslice { -        u32_le timeslice; +        u32_le timeslice{};      };      static_assert(sizeof(IoctlSetTimeslice) == 4, "IoctlSetTimeslice is incorrect size");      struct IoctlEventIdControl { -        u32_le cmd; // 0=disable, 1=enable, 2=clear -        u32_le id; +        u32_le cmd{}; // 0=disable, 1=enable, 2=clear +        u32_le id{};      };      static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size");      struct IoctlGetErrorNotification { -        u64_le timestamp; -        u32_le info32; -        u16_le info16; -        u16_le status; // always 0xFFFF +        u64_le timestamp{}; +        u32_le info32{}; +        u16_le info16{}; +        u16_le status{}; // always 0xFFFF      };      static_assert(sizeof(IoctlGetErrorNotification) == 16,                    "IoctlGetErrorNotification is incorrect size"); @@ -131,39 +107,39 @@ private:      static_assert(sizeof(Fence) == 8, "Fence is incorrect size");      struct IoctlAllocGpfifoEx { -        u32_le num_entries; -        u32_le flags; -        u32_le unk0; -        u32_le unk1; -        u32_le unk2; -        u32_le unk3; -        u32_le unk4; -        u32_le unk5; +        u32_le num_entries{}; +        u32_le flags{}; +        u32_le unk0{}; +        u32_le unk1{}; +        u32_le unk2{}; +        u32_le unk3{}; +        u32_le unk4{}; +        u32_le unk5{};      };      static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size");      struct IoctlAllocGpfifoEx2 { -        u32_le num_entries; // in -        u32_le flags;       // in -        u32_le unk0;        // in (1 works) -        Fence fence_out;    // out -        u32_le unk1;        // in -        u32_le unk2;        // in -        u32_le unk3;        // in +        u32_le num_entries{}; // in +        u32_le flags{};       // in +        u32_le unk0{};        // in (1 works) +        Fence fence_out{};    // out +        u32_le unk1{};        // in +        u32_le unk2{};        // in +        u32_le unk3{};        // in      };      static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size");      struct IoctlAllocObjCtx { -        u32_le class_num; // 0x902D=2d, 0xB197=3d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA, -                          // 0xB06F=channel_gpfifo -        u32_le flags; -        u64_le obj_id; // (ignored) used for FREE_OBJ_CTX ioctl, which is not supported +        u32_le class_num{}; // 0x902D=2d, 0xB197=3d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA, +                            // 0xB06F=channel_gpfifo +        u32_le flags{}; +        u64_le obj_id{}; // (ignored) used for FREE_OBJ_CTX ioctl, which is not supported      };      static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size");      struct IoctlSubmitGpfifo { -        u64_le address;     // pointer to gpfifo entry structs -        u32_le num_entries; // number of fence objects being submitted +        u64_le address{};     // pointer to gpfifo entry structs +        u32_le num_entries{}; // number of fence objects being submitted          union {              u32_le raw;              BitField<0, 1, u32_le> add_wait;      // append a wait sync_point to the list @@ -172,7 +148,7 @@ private:              BitField<4, 1, u32_le> suppress_wfi;  // suppress wait for interrupt              BitField<8, 1, u32_le> increment;     // increment the returned fence          } flags; -        Fence fence_out; // returned new fence object for others to wait on +        Fence fence_out{}; // returned new fence object for others to wait on          u32 AddIncrementValue() const {              return flags.add_increment.Value() << 1; @@ -182,33 +158,34 @@ private:                    "IoctlSubmitGpfifo is incorrect size");      struct IoctlGetWaitbase { -        u32 unknown; // seems to be ignored? Nintendo added this -        u32 value; +        u32 unknown{}; // seems to be ignored? Nintendo added this +        u32 value{};      };      static_assert(sizeof(IoctlGetWaitbase) == 8, "IoctlGetWaitbase is incorrect size"); -    u32_le nvmap_fd{}; +    s32_le nvmap_fd{};      u64_le user_data{};      IoctlZCullBind zcull_params{};      u32_le channel_priority{};      u32_le channel_timeslice{}; -    u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); -    u32 SetClientData(const std::vector<u8>& input, std::vector<u8>& output); -    u32 GetClientData(const std::vector<u8>& input, std::vector<u8>& output); -    u32 ZCullBind(const std::vector<u8>& input, std::vector<u8>& output); -    u32 SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output); -    u32 SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output); -    u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); -    u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); -    u32 SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, -                         Tegra::CommandList&& entries); -    u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output); -    u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, -                  const std::vector<u8>& input2, IoctlVersion version); -    u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); -    u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); -    u32 ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult SetClientData(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult GetClientData(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult ZCullBind(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, +                              Tegra::CommandList&& entries); +    NvResult SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output, +                              bool kickoff = false); +    NvResult SubmitGPFIFOBase(const std::vector<u8>& input, const std::vector<u8>& input_inline, +                              std::vector<u8>& output); +    NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output);      std::shared_ptr<nvmap> nvmap_dev;      SyncpointManager& syncpoint_manager; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index b6df48360..d8735491c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -15,46 +15,58 @@ nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_de      : nvhost_nvdec_common(system, std::move(nvmap_dev)) {}  nvhost_nvdec::~nvhost_nvdec() = default; -u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                        std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                        IoctlVersion version) { -    LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", -              command.raw, input.size(), output.size()); - -    switch (static_cast<IoctlCommand>(command.raw)) { -    case IoctlCommand::IocSetNVMAPfdCommand: -        return SetNVMAPfd(input); -    case IoctlCommand::IocSubmit: -        return Submit(input, output); -    case IoctlCommand::IocGetSyncpoint: -        return GetSyncpoint(input, output); -    case IoctlCommand::IocGetWaitbase: -        return GetWaitbase(input, output); -    case IoctlCommand::IocMapBuffer: -    case IoctlCommand::IocMapBuffer2: -    case IoctlCommand::IocMapBuffer3: -    case IoctlCommand::IocMapBufferEx: -        return MapBuffer(input, output); -    case IoctlCommand::IocUnmapBufferEx: { -        // This command is sent when the video stream has ended, flush all video contexts -        // This is usually sent in the folowing order: vic, nvdec, vic. -        // Inform the GPU to clear any remaining nvdec buffers when this is detected. -        LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); -        Tegra::ChCommandHeaderList cmdlist(1); -        cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F}; -        system.GPU().PushCommandBuffer(cmdlist); -        [[fallthrough]]; // fallthrough to unmap buffers -    }; -    case IoctlCommand::IocUnmapBuffer: -    case IoctlCommand::IocUnmapBuffer2: -    case IoctlCommand::IocUnmapBuffer3: -        return UnmapBuffer(input, output); -    case IoctlCommand::IocSetSubmitTimeout: -        return SetSubmitTimeout(input, output); +NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input, +                              std::vector<u8>& output) { +    switch (command.group) { +    case 0x0: +        switch (command.cmd) { +        case 0x1: +            return Submit(input, output); +        case 0x2: +            return GetSyncpoint(input, output); +        case 0x3: +            return GetWaitbase(input, output); +        case 0x7: +            return SetSubmitTimeout(input, output); +        case 0x9: +            return MapBuffer(input, output); +        case 0xa: { +            if (command.length == 0x1c) { +                LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); +                Tegra::ChCommandHeaderList cmdlist(1); +                cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F}; +                system.GPU().PushCommandBuffer(cmdlist); +            } +            return UnmapBuffer(input, output); +        } +        default: +            break; +        } +        break; +    case 'H': +        switch (command.cmd) { +        case 0x1: +            return SetNVMAPfd(input); +        default: +            break; +        } +        break;      } -    UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw); -    return 0; +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvhost_nvdec::Ioctl2(Ioctl command, const std::vector<u8>& input, +                              const std::vector<u8>& inline_input, std::vector<u8>& output) { +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvhost_nvdec::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                              std::vector<u8>& inline_output) { +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented;  }  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 102777ddd..79b8b6de1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -14,26 +14,11 @@ public:      explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);      ~nvhost_nvdec() override; -    u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version) override; - -private: -    enum class IoctlCommand : u32_le { -        IocSetNVMAPfdCommand = 0x40044801, -        IocSubmit = 0xC0400001, -        IocGetSyncpoint = 0xC0080002, -        IocGetWaitbase = 0xC0080003, -        IocMapBuffer = 0xC01C0009, -        IocMapBuffer2 = 0xC16C0009, -        IocMapBuffer3 = 0xC15C0009, -        IocMapBufferEx = 0xC0A40009, -        IocUnmapBuffer = 0xC0A4000A, -        IocUnmapBuffer2 = 0xC16C000A, -        IocUnmapBufferEx = 0xC01C000A, -        IocUnmapBuffer3 = 0xC15C000A, -        IocSetSubmitTimeout = 0x40040007, -    }; +    NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; +    NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output) override; +    NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                    std::vector<u8>& inline_output) override;  };  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index 30f03f845..b49cecb42 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -36,26 +36,20 @@ std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::s  }  } // Anonymous namespace -namespace NvErrCodes { -constexpr u32 Success{}; -[[maybe_unused]] constexpr u32 OutOfMemory{static_cast<u32>(-12)}; -constexpr u32 InvalidInput{static_cast<u32>(-22)}; -} // namespace NvErrCodes -  nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)      : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}  nvhost_nvdec_common::~nvhost_nvdec_common() = default; -u32 nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) { +NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {      IoctlSetNvmapFD params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlSetNvmapFD));      LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);      nvmap_fd = params.nvmap_fd; -    return 0; +    return NvResult::Success;  } -u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlSubmit params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit));      LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count); @@ -83,12 +77,12 @@ u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& o      for (const auto& cmd_buffer : command_buffers) {          auto object = nvmap_dev->GetObject(cmd_buffer.memory_id); -        ASSERT_OR_EXECUTE(object, return NvErrCodes::InvalidInput;); +        ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;);          const auto map = FindBufferMap(object->dma_map_addr);          if (!map) {              LOG_ERROR(Service_NVDRV, "Tried to submit an invalid offset 0x{:X} dma 0x{:X}",                        object->addr, object->dma_map_addr); -            return 0; +            return NvResult::Success;          }          Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);          gpu.MemoryManager().ReadBlock(map->StartAddr() + cmd_buffer.offset, cmdlist.data(), @@ -105,10 +99,10 @@ u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& o      offset = WriteVectors(output, syncpt_increments, offset);      offset = WriteVectors(output, wait_checks, offset); -    return NvErrCodes::Success; +    return NvResult::Success;  } -u32 nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlGetSyncpoint params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint));      LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param); @@ -118,18 +112,18 @@ u32 nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<      params.value = 0;      std::memcpy(output.data(), ¶ms, sizeof(IoctlGetSyncpoint)); -    return NvErrCodes::Success; +    return NvResult::Success;  } -u32 nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlGetWaitbase params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));      params.value = 0; // Seems to be hard coded at 0      std::memcpy(output.data(), ¶ms, sizeof(IoctlGetWaitbase)); -    return 0; +    return NvResult::Success;  } -u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlMapBuffer params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));      std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); @@ -143,7 +137,7 @@ u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>          if (!object) {              LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);              std::memcpy(output.data(), ¶ms, output.size()); -            return NvErrCodes::InvalidInput; +            return NvResult::InvalidState;          }          if (object->dma_map_addr == 0) {              // NVDEC and VIC memory is in the 32-bit address space @@ -165,10 +159,10 @@ u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>      std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(),                  cmd_buffer_handles.size() * sizeof(MapBufferEntry)); -    return NvErrCodes::Success; +    return NvResult::Success;  } -u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlMapBuffer params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));      std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); @@ -181,7 +175,7 @@ u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u          if (!object) {              LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);              std::memcpy(output.data(), ¶ms, output.size()); -            return NvErrCodes::InvalidInput; +            return NvResult::InvalidState;          }          if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) {              gpu.MemoryManager().Unmap(object->dma_map_addr, *size); @@ -193,13 +187,14 @@ u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u          object->dma_map_addr = 0;      }      std::memset(output.data(), 0, output.size()); -    return NvErrCodes::Success; +    return NvResult::Success;  } -u32 nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input, +                                               std::vector<u8>& output) {      std::memcpy(&submit_timeout, input.data(), input.size());      LOG_WARNING(Service_NVDRV, "(STUBBED) called"); -    return NvErrCodes::Success; +    return NvResult::Success;  }  std::optional<nvhost_nvdec_common::BufferMap> nvhost_nvdec_common::FindBufferMap( diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index c249c5349..86ba3a4d1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -18,9 +18,37 @@ public:      explicit nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);      ~nvhost_nvdec_common() override; -    virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                      std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                      IoctlVersion version) = 0; +    /** +     * Handles an ioctl1 request. +     * @param command The ioctl command id. +     * @param input A buffer containing the input data for the ioctl. +     * @param output A buffer where the output data will be written to. +     * @returns The result code of the ioctl. +     */ +    virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, +                            std::vector<u8>& output) = 0; + +    /** +     * Handles an ioctl2 request. +     * @param command The ioctl command id. +     * @param input A buffer containing the input data for the ioctl. +     * @param inline_input A buffer containing the input data for the ioctl which has been inlined. +     * @param output A buffer where the output data will be written to. +     * @returns The result code of the ioctl. +     */ +    virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                            const std::vector<u8>& inline_input, std::vector<u8>& output) = 0; + +    /** +     * Handles an ioctl3 request. +     * @param command The ioctl command id. +     * @param input A buffer containing the input data for the ioctl. +     * @param output A buffer where the output data will be written to. +     * @param inline_output A buffer where the inlined output data will be written to. +     * @returns The result code of the ioctl. +     */ +    virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                            std::vector<u8>& inline_output) = 0;  protected:      class BufferMap final { @@ -63,102 +91,102 @@ protected:      };      struct IoctlSetNvmapFD { -        u32_le nvmap_fd; +        s32_le nvmap_fd{};      };      static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");      struct IoctlSubmitCommandBuffer { -        u32_le id; -        u32_le offset; -        u32_le count; +        u32_le id{}; +        u32_le offset{}; +        u32_le count{};      };      static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC,                    "IoctlSubmitCommandBuffer is incorrect size");      struct IoctlSubmit { -        u32_le cmd_buffer_count; -        u32_le relocation_count; -        u32_le syncpoint_count; -        u32_le fence_count; +        u32_le cmd_buffer_count{}; +        u32_le relocation_count{}; +        u32_le syncpoint_count{}; +        u32_le fence_count{};      };      static_assert(sizeof(IoctlSubmit) == 0x10, "IoctlSubmit has incorrect size");      struct CommandBuffer { -        s32 memory_id; -        u32 offset; -        s32 word_count; +        s32 memory_id{}; +        u32 offset{}; +        s32 word_count{};      };      static_assert(sizeof(CommandBuffer) == 0xC, "CommandBuffer has incorrect size");      struct Reloc { -        s32 cmdbuffer_memory; -        s32 cmdbuffer_offset; -        s32 target; -        s32 target_offset; +        s32 cmdbuffer_memory{}; +        s32 cmdbuffer_offset{}; +        s32 target{}; +        s32 target_offset{};      };      static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size");      struct SyncptIncr { -        u32 id; -        u32 increments; +        u32 id{}; +        u32 increments{};      };      static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size");      struct Fence { -        u32 id; -        u32 value; +        u32 id{}; +        u32 value{};      };      static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size");      struct IoctlGetSyncpoint {          // Input -        u32_le param; +        u32_le param{};          // Output -        u32_le value; +        u32_le value{};      };      static_assert(sizeof(IoctlGetSyncpoint) == 8, "IocGetIdParams has wrong size");      struct IoctlGetWaitbase { -        u32_le unknown; // seems to be ignored? Nintendo added this -        u32_le value; +        u32_le unknown{}; // seems to be ignored? Nintendo added this +        u32_le value{};      };      static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size");      struct IoctlMapBuffer { -        u32_le num_entries; -        u32_le data_address; // Ignored by the driver. -        u32_le attach_host_ch_das; +        u32_le num_entries{}; +        u32_le data_address{}; // Ignored by the driver. +        u32_le attach_host_ch_das{};      };      static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");      struct IocGetIdParams {          // Input -        u32_le param; +        u32_le param{};          // Output -        u32_le value; +        u32_le value{};      };      static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");      // Used for mapping and unmapping command buffers      struct MapBufferEntry { -        u32_le map_handle; -        u32_le map_address; +        u32_le map_handle{}; +        u32_le map_address{};      };      static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");      /// Ioctl command implementations -    u32 SetNVMAPfd(const std::vector<u8>& input); -    u32 Submit(const std::vector<u8>& input, std::vector<u8>& output); -    u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output); -    u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); -    u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output); -    u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); -    u32 SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult SetNVMAPfd(const std::vector<u8>& input); +    NvResult Submit(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult MapBuffer(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output);      std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;      void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);      std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr); -    u32_le nvmap_fd{}; +    s32_le nvmap_fd{};      u32_le submit_timeout{};      std::shared_ptr<nvmap> nvmap_dev; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index 96e7b7dab..2d06955c0 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp @@ -13,28 +13,44 @@ namespace Service::Nvidia::Devices {  nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {}  nvhost_nvjpg::~nvhost_nvjpg() = default; -u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                        std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                        IoctlVersion version) { -    LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", -              command.raw, input.size(), output.size()); - -    switch (static_cast<IoctlCommand>(command.raw)) { -    case IoctlCommand::IocSetNVMAPfdCommand: -        return SetNVMAPfd(input, output); +NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector<u8>& input, +                              std::vector<u8>& output) { +    switch (command.group) { +    case 'H': +        switch (command.cmd) { +        case 0x1: +            return SetNVMAPfd(input, output); +        default: +            break; +        } +        break; +    default: +        break;      } -    UNIMPLEMENTED_MSG("Unimplemented ioctl"); -    return 0; +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented;  } -u32 nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvjpg::Ioctl2(Ioctl command, const std::vector<u8>& input, +                              const std::vector<u8>& inline_input, std::vector<u8>& output) { +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvhost_nvjpg::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                              std::vector<u8>& inline_output) { +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlSetNvmapFD params{};      std::memcpy(¶ms, input.data(), input.size());      LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);      nvmap_fd = params.nvmap_fd; -    return 0; +    return NvResult::Success;  }  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 98dcac52f..43948d18d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h @@ -16,23 +16,21 @@ public:      explicit nvhost_nvjpg(Core::System& system);      ~nvhost_nvjpg() override; -    u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version) override; +    NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; +    NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output) override; +    NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                    std::vector<u8>& inline_output) override;  private: -    enum class IoctlCommand : u32_le { -        IocSetNVMAPfdCommand = 0x40044801, -    }; -      struct IoctlSetNvmapFD { -        u32_le nvmap_fd; +        s32_le nvmap_fd{};      };      static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); -    u32_le nvmap_fd{}; +    s32_le nvmap_fd{}; -    u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);  };  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 60db54d00..805fe86ae 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -15,36 +15,50 @@ nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)  nvhost_vic::~nvhost_vic() = default; -u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                      std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                      IoctlVersion version) { -    LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", -              command.raw, input.size(), output.size()); - -    switch (static_cast<IoctlCommand>(command.raw)) { -    case IoctlCommand::IocSetNVMAPfdCommand: -        return SetNVMAPfd(input); -    case IoctlCommand::IocSubmit: -        return Submit(input, output); -    case IoctlCommand::IocGetSyncpoint: -        return GetSyncpoint(input, output); -    case IoctlCommand::IocGetWaitbase: -        return GetWaitbase(input, output); -    case IoctlCommand::IocMapBuffer: -    case IoctlCommand::IocMapBuffer2: -    case IoctlCommand::IocMapBuffer3: -    case IoctlCommand::IocMapBuffer4: -    case IoctlCommand::IocMapBufferEx: -        return MapBuffer(input, output); -    case IoctlCommand::IocUnmapBuffer: -    case IoctlCommand::IocUnmapBuffer2: -    case IoctlCommand::IocUnmapBuffer3: -    case IoctlCommand::IocUnmapBufferEx: -        return UnmapBuffer(input, output); +NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { +    switch (command.group) { +    case 0x0: +        switch (command.cmd) { +        case 0x1: +            return Submit(input, output); +        case 0x2: +            return GetSyncpoint(input, output); +        case 0x3: +            return GetWaitbase(input, output); +        case 0x9: +            return MapBuffer(input, output); +        case 0xa: +            return UnmapBuffer(input, output); +        default: +            break; +        } +        break; +    case 'H': +        switch (command.cmd) { +        case 0x1: +            return SetNVMAPfd(input); +        default: +            break; +        } +        break; +    default: +        break;      } -    UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw); -    return 0; +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvhost_vic::Ioctl2(Ioctl command, const std::vector<u8>& input, +                            const std::vector<u8>& inline_input, std::vector<u8>& output) { +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvhost_vic::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                            std::vector<u8>& inline_output) { +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented;  }  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index f975b190c..b2e11f4d4 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h @@ -13,25 +13,11 @@ class nvhost_vic final : public nvhost_nvdec_common {  public:      explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);      ~nvhost_vic(); -    u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version) override; -private: -    enum class IoctlCommand : u32_le { -        IocSetNVMAPfdCommand = 0x40044801, -        IocSubmit = 0xC0400001, -        IocGetSyncpoint = 0xC0080002, -        IocGetWaitbase = 0xC0080003, -        IocMapBuffer = 0xC01C0009, -        IocMapBuffer2 = 0xC0340009, -        IocMapBuffer3 = 0xC0140009, -        IocMapBuffer4 = 0xC00C0009, -        IocMapBufferEx = 0xC03C0009, -        IocUnmapBuffer = 0xC03C000A, -        IocUnmapBuffer2 = 0xC034000A, -        IocUnmapBuffer3 = 0xC00C000A, -        IocUnmapBufferEx = 0xC01C000A, -    }; +    NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; +    NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output) override; +    NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                    std::vector<u8>& inline_output) override;  };  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 9436e16ad..4015a2740 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -11,13 +11,6 @@  namespace Service::Nvidia::Devices { -namespace NvErrCodes { -enum { -    OperationNotPermitted = -1, -    InvalidValue = -22, -}; -} -  nvmap::nvmap(Core::System& system) : nvdevice(system) {      // Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to      // represent this. @@ -26,6 +19,46 @@ nvmap::nvmap(Core::System& system) : nvdevice(system) {  nvmap::~nvmap() = default; +NvResult nvmap::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { +    switch (command.group) { +    case 0x1: +        switch (command.cmd) { +        case 0x1: +            return IocCreate(input, output); +        case 0x3: +            return IocFromId(input, output); +        case 0x4: +            return IocAlloc(input, output); +        case 0x5: +            return IocFree(input, output); +        case 0x9: +            return IocParam(input, output); +        case 0xe: +            return IocGetId(input, output); +        default: +            break; +        } +        break; +    default: +        break; +    } + +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvmap::Ioctl2(Ioctl command, const std::vector<u8>& input, +                       const std::vector<u8>& inline_input, std::vector<u8>& output) { +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvmap::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                       std::vector<u8>& inline_output) { +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} +  VAddr nvmap::GetObjectAddress(u32 handle) const {      auto object = GetObject(handle);      ASSERT(object); @@ -33,28 +66,6 @@ VAddr nvmap::GetObjectAddress(u32 handle) const {      return object->addr;  } -u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                 IoctlVersion version) { -    switch (static_cast<IoctlCommand>(command.raw)) { -    case IoctlCommand::Create: -        return IocCreate(input, output); -    case IoctlCommand::Alloc: -        return IocAlloc(input, output); -    case IoctlCommand::GetId: -        return IocGetId(input, output); -    case IoctlCommand::FromId: -        return IocFromId(input, output); -    case IoctlCommand::Param: -        return IocParam(input, output); -    case IoctlCommand::Free: -        return IocFree(input, output); -    } - -    UNIMPLEMENTED_MSG("Unimplemented ioctl"); -    return 0; -} -  u32 nvmap::CreateObject(u32 size) {      // Create a new nvmap object and obtain a handle to it.      auto object = std::make_shared<Object>(); @@ -70,35 +81,35 @@ u32 nvmap::CreateObject(u32 size) {      return handle;  } -u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {      IocCreateParams params;      std::memcpy(¶ms, input.data(), sizeof(params));      LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size);      if (!params.size) {          LOG_ERROR(Service_NVDRV, "Size is 0"); -        return static_cast<u32>(NvErrCodes::InvalidValue); +        return NvResult::BadValue;      }      params.handle = CreateObject(params.size);      std::memcpy(output.data(), ¶ms, sizeof(params)); -    return 0; +    return NvResult::Success;  } -u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {      IocAllocParams params;      std::memcpy(¶ms, input.data(), sizeof(params));      LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr);      if (!params.handle) {          LOG_ERROR(Service_NVDRV, "Handle is 0"); -        return static_cast<u32>(NvErrCodes::InvalidValue); +        return NvResult::BadValue;      }      if ((params.align - 1) & params.align) {          LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align); -        return static_cast<u32>(NvErrCodes::InvalidValue); +        return NvResult::BadValue;      }      const u32 min_alignment = 0x1000; @@ -109,12 +120,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {      auto object = GetObject(params.handle);      if (!object) {          LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); -        return static_cast<u32>(NvErrCodes::InvalidValue); +        return NvResult::BadValue;      }      if (object->status == Object::Status::Allocated) {          LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle); -        return static_cast<u32>(NvErrCodes::OperationNotPermitted); +        return NvResult::InsufficientMemory;      }      object->flags = params.flags; @@ -124,10 +135,10 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {      object->status = Object::Status::Allocated;      std::memcpy(output.data(), ¶ms, sizeof(params)); -    return 0; +    return NvResult::Success;  } -u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {      IocGetIdParams params;      std::memcpy(¶ms, input.data(), sizeof(params)); @@ -135,22 +146,22 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {      if (!params.handle) {          LOG_ERROR(Service_NVDRV, "Handle is zero"); -        return static_cast<u32>(NvErrCodes::InvalidValue); +        return NvResult::BadValue;      }      auto object = GetObject(params.handle);      if (!object) {          LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); -        return static_cast<u32>(NvErrCodes::OperationNotPermitted); +        return NvResult::BadValue;      }      params.id = object->id;      std::memcpy(output.data(), ¶ms, sizeof(params)); -    return 0; +    return NvResult::Success;  } -u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {      IocFromIdParams params;      std::memcpy(¶ms, input.data(), sizeof(params)); @@ -160,13 +171,13 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {                              [&](const auto& entry) { return entry.second->id == params.id; });      if (itr == handles.end()) {          LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); -        return static_cast<u32>(NvErrCodes::InvalidValue); +        return NvResult::BadValue;      }      auto& object = itr->second;      if (object->status != Object::Status::Allocated) {          LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); -        return static_cast<u32>(NvErrCodes::InvalidValue); +        return NvResult::BadValue;      }      itr->second->refcount++; @@ -175,10 +186,10 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {      params.handle = itr->first;      std::memcpy(output.data(), ¶ms, sizeof(params)); -    return 0; +    return NvResult::Success;  } -u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {      enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };      IocParamParams params; @@ -189,12 +200,12 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {      auto object = GetObject(params.handle);      if (!object) {          LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); -        return static_cast<u32>(NvErrCodes::InvalidValue); +        return NvResult::BadValue;      }      if (object->status != Object::Status::Allocated) {          LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); -        return static_cast<u32>(NvErrCodes::OperationNotPermitted); +        return NvResult::BadValue;      }      switch (static_cast<ParamTypes>(params.param)) { @@ -216,10 +227,10 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {      }      std::memcpy(output.data(), ¶ms, sizeof(params)); -    return 0; +    return NvResult::Success;  } -u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {      // TODO(Subv): These flags are unconfirmed.      enum FreeFlags {          Freed = 0, @@ -234,14 +245,14 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {      auto itr = handles.find(params.handle);      if (itr == handles.end()) {          LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); -        return static_cast<u32>(NvErrCodes::InvalidValue); +        return NvResult::BadValue;      }      if (!itr->second->refcount) {          LOG_ERROR(              Service_NVDRV,              "There is no references to this object. The object is already freed. handle={:08X}",              params.handle); -        return static_cast<u32>(NvErrCodes::InvalidValue); +        return NvResult::BadValue;      }      itr->second->refcount--; @@ -261,7 +272,7 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {      handles.erase(params.handle);      std::memcpy(output.data(), ¶ms, sizeof(params)); -    return 0; +    return NvResult::Success;  }  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 04b9ef540..4484bd79f 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -19,13 +19,15 @@ public:      explicit nvmap(Core::System& system);      ~nvmap() override; +    NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; +    NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output) override; +    NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                    std::vector<u8>& inline_output) override; +      /// Returns the allocated address of an nvmap object given its handle.      VAddr GetObjectAddress(u32 handle) const; -    u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version) override; -      /// Represents an nvmap object.      struct Object {          enum class Status { Created, Allocated }; @@ -58,76 +60,68 @@ private:      /// Mapping of currently allocated handles to the objects they represent.      std::unordered_map<u32, std::shared_ptr<Object>> handles; -    enum class IoctlCommand : u32 { -        Create = 0xC0080101, -        FromId = 0xC0080103, -        Alloc = 0xC0200104, -        Free = 0xC0180105, -        Param = 0xC00C0109, -        GetId = 0xC008010E, -    };      struct IocCreateParams {          // Input -        u32_le size; +        u32_le size{};          // Output -        u32_le handle; +        u32_le handle{};      };      static_assert(sizeof(IocCreateParams) == 8, "IocCreateParams has wrong size");      struct IocFromIdParams {          // Input -        u32_le id; +        u32_le id{};          // Output -        u32_le handle; +        u32_le handle{};      };      static_assert(sizeof(IocFromIdParams) == 8, "IocFromIdParams has wrong size");      struct IocAllocParams {          // Input -        u32_le handle; -        u32_le heap_mask; -        u32_le flags; -        u32_le align; -        u8 kind; +        u32_le handle{}; +        u32_le heap_mask{}; +        u32_le flags{}; +        u32_le align{}; +        u8 kind{};          INSERT_PADDING_BYTES(7); -        u64_le addr; +        u64_le addr{};      };      static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size");      struct IocFreeParams { -        u32_le handle; +        u32_le handle{};          INSERT_PADDING_BYTES(4); -        u64_le address; -        u32_le size; -        u32_le flags; +        u64_le address{}; +        u32_le size{}; +        u32_le flags{};      };      static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size");      struct IocParamParams {          // Input -        u32_le handle; -        u32_le param; +        u32_le handle{}; +        u32_le param{};          // Output -        u32_le result; +        u32_le result{};      };      static_assert(sizeof(IocParamParams) == 12, "IocParamParams has wrong size");      struct IocGetIdParams {          // Output -        u32_le id; +        u32_le id{};          // Input -        u32_le handle; +        u32_le handle{};      };      static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");      u32 CreateObject(u32 size); -    u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output); -    u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output); -    u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output); -    u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output); -    u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output); -    u32 IocFree(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult IocCreate(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult IocAlloc(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult IocGetId(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult IocFromId(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult IocParam(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult IocFree(const std::vector<u8>& input, std::vector<u8>& output);  };  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index 88fbfa9b0..f6c38e853 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp @@ -23,124 +23,170 @@ void NVDRV::SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) {  void NVDRV::Open(Kernel::HLERequestContext& ctx) {      LOG_DEBUG(Service_NVDRV, "called"); +    if (!is_initialized) { +        ServiceError(ctx, NvResult::NotInitialized); +        LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); +        return; +    } +      const auto& buffer = ctx.ReadBuffer(); -    std::string device_name(buffer.begin(), buffer.end()); +    const std::string device_name(buffer.begin(), buffer.end()); +    DeviceFD fd = nvdrv->Open(device_name); -    u32 fd = nvdrv->Open(device_name);      IPC::ResponseBuilder rb{ctx, 4};      rb.Push(RESULT_SUCCESS); -    rb.Push<u32>(fd); -    rb.Push<u32>(0); +    rb.Push<DeviceFD>(fd); +    rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed); +} + +void NVDRV::ServiceError(Kernel::HLERequestContext& ctx, NvResult result) { +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(RESULT_SUCCESS); +    rb.PushEnum(result);  } -void NVDRV::IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version) { +void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    u32 fd = rp.Pop<u32>(); -    u32 command = rp.Pop<u32>(); - -    /// Ioctl 3 has 2 outputs, first in the input params, second is the result -    std::vector<u8> output(ctx.GetWriteBufferSize(0)); -    std::vector<u8> output2; -    if (version == IoctlVersion::Version3) { -        output2.resize((ctx.GetWriteBufferSize(1))); +    const auto fd = rp.Pop<DeviceFD>(); +    const auto command = rp.PopRaw<Ioctl>(); +    LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); + +    if (!is_initialized) { +        ServiceError(ctx, NvResult::NotInitialized); +        LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); +        return;      } -    /// Ioctl2 has 2 inputs. It's used to pass data directly instead of providing a pointer. -    /// KickOfPB uses this -    auto input = ctx.ReadBuffer(0); +    // Check device +    std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0)); +    const auto input_buffer = ctx.ReadBuffer(0); -    std::vector<u8> input2; -    if (version == IoctlVersion::Version2) { -        input2 = ctx.ReadBuffer(1); -    } +    const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer); -    IoctlCtrl ctrl{}; - -    u32 result = nvdrv->Ioctl(fd, command, input, input2, output, output2, ctrl, version); - -    if (ctrl.must_delay) { -        ctrl.fresh_call = false; -        ctx.SleepClientThread( -            "NVServices::DelayedResponse", ctrl.timeout, -            [=, this](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx_, -                      Kernel::ThreadWakeupReason reason) { -                IoctlCtrl ctrl2{ctrl}; -                std::vector<u8> tmp_output = output; -                std::vector<u8> tmp_output2 = output2; -                const u32 ioctl_result = nvdrv->Ioctl(fd, command, input, input2, tmp_output, -                                                      tmp_output2, ctrl2, version); -                ctx_.WriteBuffer(tmp_output, 0); -                if (version == IoctlVersion::Version3) { -                    ctx_.WriteBuffer(tmp_output2, 1); -                } -                IPC::ResponseBuilder rb{ctx_, 3}; -                rb.Push(RESULT_SUCCESS); -                rb.Push(ioctl_result); -            }, -            nvdrv->GetEventWriteable(ctrl.event_id)); -    } else { -        ctx.WriteBuffer(output); -        if (version == IoctlVersion::Version3) { -            ctx.WriteBuffer(output2, 1); -        } +    if (command.is_out != 0) { +        ctx.WriteBuffer(output_buffer);      } +      IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS); -    rb.Push(result); -} - -void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) { -    LOG_DEBUG(Service_NVDRV, "called"); -    IoctlBase(ctx, IoctlVersion::Version1); +    rb.PushEnum(nv_result);  }  void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) { -    LOG_DEBUG(Service_NVDRV, "called"); -    IoctlBase(ctx, IoctlVersion::Version2); +    IPC::RequestParser rp{ctx}; +    const auto fd = rp.Pop<DeviceFD>(); +    const auto command = rp.PopRaw<Ioctl>(); +    LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); + +    if (!is_initialized) { +        ServiceError(ctx, NvResult::NotInitialized); +        LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); +        return; +    } + +    const auto input_buffer = ctx.ReadBuffer(0); +    const auto input_inlined_buffer = ctx.ReadBuffer(1); +    std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0)); + +    const auto nv_result = +        nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer); + +    if (command.is_out != 0) { +        ctx.WriteBuffer(output_buffer); +    } + +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(RESULT_SUCCESS); +    rb.PushEnum(nv_result);  }  void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) { -    LOG_DEBUG(Service_NVDRV, "called"); -    IoctlBase(ctx, IoctlVersion::Version3); +    IPC::RequestParser rp{ctx}; +    const auto fd = rp.Pop<DeviceFD>(); +    const auto command = rp.PopRaw<Ioctl>(); +    LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); + +    if (!is_initialized) { +        ServiceError(ctx, NvResult::NotInitialized); +        LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); +        return; +    } + +    const auto input_buffer = ctx.ReadBuffer(0); +    std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0)); +    std::vector<u8> output_buffer_inline(ctx.GetWriteBufferSize(1)); + +    const auto nv_result = +        nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline); + +    if (command.is_out != 0) { +        ctx.WriteBuffer(output_buffer, 0); +        ctx.WriteBuffer(output_buffer_inline, 1); +    } + +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(RESULT_SUCCESS); +    rb.PushEnum(nv_result);  }  void NVDRV::Close(Kernel::HLERequestContext& ctx) {      LOG_DEBUG(Service_NVDRV, "called"); -    IPC::RequestParser rp{ctx}; -    u32 fd = rp.Pop<u32>(); +    if (!is_initialized) { +        ServiceError(ctx, NvResult::NotInitialized); +        LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); +        return; +    } -    auto result = nvdrv->Close(fd); +    IPC::RequestParser rp{ctx}; +    const auto fd = rp.Pop<DeviceFD>(); +    const auto result = nvdrv->Close(fd); -    IPC::ResponseBuilder rb{ctx, 2}; -    rb.Push(result); +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(RESULT_SUCCESS); +    rb.PushEnum(result);  }  void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {      LOG_WARNING(Service_NVDRV, "(STUBBED) called"); +    is_initialized = true; +      IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS); -    rb.Push<u32>(0); +    rb.PushEnum(NvResult::Success);  }  void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    u32 fd = rp.Pop<u32>(); -    // TODO(Blinkhawk): Figure the meaning of the flag at bit 16 -    u32 event_id = rp.Pop<u32>() & 0x000000FF; +    const auto fd = rp.Pop<DeviceFD>(); +    const auto event_id = rp.Pop<u32>() & 0x00FF;      LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); -    IPC::ResponseBuilder rb{ctx, 3, 1}; -    rb.Push(RESULT_SUCCESS); +    if (!is_initialized) { +        ServiceError(ctx, NvResult::NotInitialized); +        LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); +        return; +    } + +    const auto nv_result = nvdrv->VerifyFD(fd); +    if (nv_result != NvResult::Success) { +        LOG_ERROR(Service_NVDRV, "Invalid FD specified DeviceFD={}!", fd); +        ServiceError(ctx, nv_result); +        return; +    } +      if (event_id < MaxNvEvents) { +        IPC::ResponseBuilder rb{ctx, 3, 1}; +        rb.Push(RESULT_SUCCESS);          auto event = nvdrv->GetEvent(event_id);          event->Clear();          rb.PushCopyObjects(event); -        rb.Push<u32>(NvResult::Success); +        rb.PushEnum(NvResult::Success);      } else { -        rb.Push<u32>(0); -        rb.Push<u32>(NvResult::BadParameter); +        IPC::ResponseBuilder rb{ctx, 3}; +        rb.Push(RESULT_SUCCESS); +        rb.PushEnum(NvResult::BadParameter);      }  } @@ -151,7 +197,7 @@ void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) {      IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS); -    rb.Push<u32>(0); +    rb.PushEnum(NvResult::Success);  }  void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) { @@ -164,8 +210,9 @@ void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ct  void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) {      LOG_WARNING(Service_NVDRV, "(STUBBED) called"); -    IPC::ResponseBuilder rb{ctx, 2}; +    IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS); +    rb.PushEnum(NvResult::Success);  }  void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) { @@ -181,7 +228,7 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)      : ServiceFramework(name), nvdrv(std::move(nvdrv)) {      static const FunctionInfo functions[] = {          {0, &NVDRV::Open, "Open"}, -        {1, &NVDRV::Ioctl, "Ioctl"}, +        {1, &NVDRV::Ioctl1, "Ioctl"},          {2, &NVDRV::Close, "Close"},          {3, &NVDRV::Initialize, "Initialize"},          {4, &NVDRV::QueryEvent, "QueryEvent"}, diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index 72e17a728..e05f905ae 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h @@ -23,7 +23,7 @@ public:  private:      void Open(Kernel::HLERequestContext& ctx); -    void Ioctl(Kernel::HLERequestContext& ctx); +    void Ioctl1(Kernel::HLERequestContext& ctx);      void Ioctl2(Kernel::HLERequestContext& ctx);      void Ioctl3(Kernel::HLERequestContext& ctx);      void Close(Kernel::HLERequestContext& ctx); @@ -33,11 +33,13 @@ private:      void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx);      void GetStatus(Kernel::HLERequestContext& ctx);      void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); -    void IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version); + +    void ServiceError(Kernel::HLERequestContext& ctx, NvResult result);      std::shared_ptr<Module> nvdrv;      u64 pid{}; +    bool is_initialized{};  };  } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h index 529b03471..3294bc0e7 100644 --- a/src/core/hle/service/nvdrv/nvdata.h +++ b/src/core/hle/service/nvdrv/nvdata.h @@ -1,12 +1,16 @@  #pragma once  #include <array> +#include "common/bit_field.h"  #include "common/common_types.h"  namespace Service::Nvidia {  constexpr u32 MaxSyncPoints = 192;  constexpr u32 MaxNvEvents = 64; +using DeviceFD = s32; + +constexpr DeviceFD INVALID_NVDRV_FD = -1;  struct Fence {      s32 id; @@ -20,11 +24,61 @@ struct MultiFence {      std::array<Fence, 4> fences;  }; -enum NvResult : u32 { -    Success = 0, -    BadParameter = 4, -    Timeout = 5, -    ResourceError = 15, +enum class NvResult : u32 { +    Success = 0x0, +    NotImplemented = 0x1, +    NotSupported = 0x2, +    NotInitialized = 0x3, +    BadParameter = 0x4, +    Timeout = 0x5, +    InsufficientMemory = 0x6, +    ReadOnlyAttribute = 0x7, +    InvalidState = 0x8, +    InvalidAddress = 0x9, +    InvalidSize = 0xA, +    BadValue = 0xB, +    AlreadyAllocated = 0xD, +    Busy = 0xE, +    ResourceError = 0xF, +    CountMismatch = 0x10, +    OverFlow = 0x11, +    InsufficientTransferMemory = 0x1000, +    InsufficientVideoMemory = 0x10000, +    BadSurfaceColorScheme = 0x10001, +    InvalidSurface = 0x10002, +    SurfaceNotSupported = 0x10003, +    DispInitFailed = 0x20000, +    DispAlreadyAttached = 0x20001, +    DispTooManyDisplays = 0x20002, +    DispNoDisplaysAttached = 0x20003, +    DispModeNotSupported = 0x20004, +    DispNotFound = 0x20005, +    DispAttachDissallowed = 0x20006, +    DispTypeNotSupported = 0x20007, +    DispAuthenticationFailed = 0x20008, +    DispNotAttached = 0x20009, +    DispSamePwrState = 0x2000A, +    DispEdidFailure = 0x2000B, +    DispDsiReadAckError = 0x2000C, +    DispDsiReadInvalidResp = 0x2000D, +    FileWriteFailed = 0x30000, +    FileReadFailed = 0x30001, +    EndOfFile = 0x30002, +    FileOperationFailed = 0x30003, +    DirOperationFailed = 0x30004, +    EndOfDirList = 0x30005, +    ConfigVarNotFound = 0x30006, +    InvalidConfigVar = 0x30007, +    LibraryNotFound = 0x30008, +    SymbolNotFound = 0x30009, +    MemoryMapFailed = 0x3000A, +    IoctlFailed = 0x3000F, +    AccessDenied = 0x30010, +    DeviceNotFound = 0x30011, +    KernelDriverNotFound = 0x30012, +    FileNotFound = 0x30013, +    PathAlreadyExists = 0x30014, +    ModuleNotPresent = 0xA000E,  };  enum class EventState { @@ -34,21 +88,13 @@ enum class EventState {      Busy = 3,  }; -enum class IoctlVersion : u32 { -    Version1, -    Version2, -    Version3, -}; - -struct IoctlCtrl { -    // First call done to the servioce for services that call itself again after a call. -    bool fresh_call{true}; -    // Tells the Ioctl Wrapper that it must delay the IPC response and send the thread to sleep -    bool must_delay{}; -    // Timeout for the delay -    s64 timeout{}; -    // NV Event Id -    s32 event_id{-1}; +union Ioctl { +    u32_le raw; +    BitField<0, 8, u32> cmd; +    BitField<8, 8, u32> group; +    BitField<16, 14, u32> length; +    BitField<30, 1, u32> is_in; +    BitField<31, 1, u32> is_out;  };  } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index a46755cdc..bdbbedd0d 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -5,6 +5,7 @@  #include <utility>  #include <fmt/format.h> +#include "core/core.h"  #include "core/hle/ipc_helpers.h"  #include "core/hle/kernel/readable_event.h"  #include "core/hle/kernel/writable_event.h" @@ -61,36 +62,101 @@ Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} {  Module::~Module() = default; -u32 Module::Open(const std::string& device_name) { -    ASSERT_MSG(devices.find(device_name) != devices.end(), "Trying to open unknown device {}", -               device_name); +NvResult Module::VerifyFD(DeviceFD fd) const { +    if (fd < 0) { +        LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); +        return NvResult::InvalidState; +    } + +    if (open_files.find(fd) == open_files.end()) { +        LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); +        return NvResult::NotImplemented; +    } + +    return NvResult::Success; +} + +DeviceFD Module::Open(const std::string& device_name) { +    if (devices.find(device_name) == devices.end()) { +        LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name); +        return INVALID_NVDRV_FD; +    }      auto device = devices[device_name]; -    const u32 fd = next_fd++; +    const DeviceFD fd = next_fd++;      open_files[fd] = std::move(device);      return fd;  } -u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2, -                  std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                  IoctlVersion version) { -    auto itr = open_files.find(fd); -    ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); +NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +                        std::vector<u8>& output) { +    if (fd < 0) { +        LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); +        return NvResult::InvalidState; +    } -    auto& device = itr->second; -    return device->ioctl({command}, input, input2, output, output2, ctrl, version); +    const auto itr = open_files.find(fd); + +    if (itr == open_files.end()) { +        LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); +        return NvResult::NotImplemented; +    } + +    return itr->second->Ioctl1(command, input, output);  } -ResultCode Module::Close(u32 fd) { -    auto itr = open_files.find(fd); -    ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); +NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +                        const std::vector<u8>& inline_input, std::vector<u8>& output) { +    if (fd < 0) { +        LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); +        return NvResult::InvalidState; +    } + +    const auto itr = open_files.find(fd); + +    if (itr == open_files.end()) { +        LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); +        return NvResult::NotImplemented; +    } + +    return itr->second->Ioctl2(command, input, inline_input, output); +} + +NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +                        std::vector<u8>& output, std::vector<u8>& inline_output) { +    if (fd < 0) { +        LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); +        return NvResult::InvalidState; +    } + +    const auto itr = open_files.find(fd); + +    if (itr == open_files.end()) { +        LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); +        return NvResult::NotImplemented; +    } + +    return itr->second->Ioctl3(command, input, output, inline_output); +} + +NvResult Module::Close(DeviceFD fd) { +    if (fd < 0) { +        LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); +        return NvResult::InvalidState; +    } + +    const auto itr = open_files.find(fd); + +    if (itr == open_files.end()) { +        LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); +        return NvResult::NotImplemented; +    }      open_files.erase(itr); -    // TODO(flerovium): return correct result code if operation failed. -    return RESULT_SUCCESS; +    return NvResult::Success;  }  void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index f3d863dac..7654bb026 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -112,14 +112,23 @@ public:          return std::static_pointer_cast<T>(itr->second);      } +    NvResult VerifyFD(DeviceFD fd) const; +      /// Opens a device node and returns a file descriptor to it. -    u32 Open(const std::string& device_name); +    DeviceFD Open(const std::string& device_name); +      /// Sends an ioctl command to the specified file descriptor. -    u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version); +    NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +                    std::vector<u8>& output); + +    NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output); + +    NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +                    std::vector<u8>& output, std::vector<u8>& inline_output); +      /// Closes a device file descriptor and returns operation success. -    ResultCode Close(u32 fd); +    NvResult Close(DeviceFD fd);      void SignalSyncpt(const u32 syncpoint_id, const u32 value); @@ -132,10 +141,10 @@ private:      SyncpointManager syncpoint_manager;      /// Id to use for the next open file descriptor. -    u32 next_fd = 1; +    DeviceFD next_fd = 1;      /// Mapping of file descriptors to the devices they reference. -    std::unordered_map<u32, std::shared_ptr<Devices::nvdevice>> open_files; +    std::unordered_map<DeviceFD, std::shared_ptr<Devices::nvdevice>> open_files;      /// Mapping of device node names to their implementation.      std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; diff --git a/src/core/hle/service/olsc/olsc.cpp b/src/core/hle/service/olsc/olsc.cpp new file mode 100644 index 000000000..aad4ca706 --- /dev/null +++ b/src/core/hle/service/olsc/olsc.cpp @@ -0,0 +1,69 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/service/olsc/olsc.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::OLSC { + +class OLSC final : public ServiceFramework<OLSC> { +public: +    explicit OLSC() : ServiceFramework{"olsc:u"} { +        // clang-format off +        static const FunctionInfo functions[] = { +            {0, &OLSC::Initialize, "Initialize"}, +            {10, nullptr, "VerifySaveDataBackupLicenseAsync"}, +            {13, nullptr, "GetSaveDataBackupSetting"}, +            {14, &OLSC::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"}, +            {15, nullptr, "SetCustomData"}, +            {16, nullptr, "DeleteSaveDataBackupSetting"}, +            {18, nullptr, "GetSaveDataBackupInfoCache"}, +            {19, nullptr, "UpdateSaveDataBackupInfoCacheAsync"}, +            {22, nullptr, "DeleteSaveDataBackupAsync"}, +            {25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"}, +            {26, nullptr, "DownloadSaveDataBackupAsync"}, +            {9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"}, +            {9013, nullptr, "GetSaveDataBackupSettingForDebug"}, +            {9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"}, +            {9015, nullptr, "SetCustomDataForDebug"}, +            {9016, nullptr, "DeleteSaveDataBackupSettingForDebug"}, +            {9018, nullptr, "GetSaveDataBackupInfoCacheForDebug"}, +            {9019, nullptr, "UpdateSaveDataBackupInfoCacheAsyncForDebug"}, +            {9022, nullptr, "DeleteSaveDataBackupAsyncForDebug"}, +            {9025, nullptr, "ListDownloadableSaveDataBackupInfoAsyncForDebug"}, +            {9026, nullptr, "DownloadSaveDataBackupAsyncForDebug"}, +        }; +        // clang-format on + +        RegisterHandlers(functions); +    } + +private: +    void Initialize(Kernel::HLERequestContext& ctx) { +        LOG_WARNING(Service_OLSC, "(STUBBED) called"); + +        initialized = true; + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } + +    void SetSaveDataBackupSettingEnabled(Kernel::HLERequestContext& ctx) { +        LOG_WARNING(Service_OLSC, "(STUBBED) called"); + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } + +    bool initialized{}; +}; + +void InstallInterfaces(SM::ServiceManager& service_manager) { +    std::make_shared<OLSC>()->InstallAsService(service_manager); +} + +} // namespace Service::OLSC diff --git a/src/core/hle/service/olsc/olsc.h b/src/core/hle/service/olsc/olsc.h new file mode 100644 index 000000000..edee4376b --- /dev/null +++ b/src/core/hle/service/olsc/olsc.h @@ -0,0 +1,16 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::OLSC { + +/// Registers all SSL services with the specified service manager. +void InstallInterfaces(SM::ServiceManager& service_manager); + +} // namespace Service::OLSC diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index f43122ad2..a771a51b4 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp @@ -2,6 +2,7 @@  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. +#include "core/core.h"  #include "core/hle/ipc_helpers.h"  #include "core/hle/kernel/kernel.h"  #include "core/hle/kernel/process.h" diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index cde3312da..b9ef86b72 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp @@ -4,6 +4,7 @@  #include "common/hex_util.h"  #include "common/logging/log.h" +#include "core/core.h"  #include "core/hle/ipc_helpers.h"  #include "core/hle/kernel/process.h"  #include "core/hle/service/acc/profile_manager.h" diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index ba9159ee0..fb4979af2 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -51,6 +51,7 @@  #include "core/hle/service/ns/ns.h"  #include "core/hle/service/nvdrv/nvdrv.h"  #include "core/hle/service/nvflinger/nvflinger.h" +#include "core/hle/service/olsc/olsc.h"  #include "core/hle/service/pcie/pcie.h"  #include "core/hle/service/pctl/module.h"  #include "core/hle/service/pcv/pcv.h" @@ -187,17 +188,19 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co      return RESULT_SUCCESS;  } -/// Initialize ServiceManager -void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) { +/// Initialize Services +Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) +    : nv_flinger{std::make_unique<NVFlinger::NVFlinger>(system)} { +      // 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>(system); +      system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);      SM::ServiceManager::InstallInterfaces(sm, system.Kernel());      Account::InstallInterfaces(system); -    AM::InstallInterfaces(*sm, nv_flinger, system); +    AM::InstallInterfaces(*sm, *nv_flinger, system);      AOC::InstallInterfaces(*sm, system);      APM::InstallInterfaces(system);      Audio::InstallInterfaces(*sm, system); @@ -231,6 +234,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {      NPNS::InstallInterfaces(*sm);      NS::InstallInterfaces(*sm, system);      Nvidia::InstallInterfaces(*sm, *nv_flinger, system); +    OLSC::InstallInterfaces(*sm);      PCIe::InstallInterfaces(*sm);      PCTL::InstallInterfaces(*sm);      PCV::InstallInterfaces(*sm); @@ -244,14 +248,10 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {      SSL::InstallInterfaces(*sm);      Time::InstallInterfaces(system);      USB::InstallInterfaces(*sm); -    VI::InstallInterfaces(*sm, nv_flinger); +    VI::InstallInterfaces(*sm, *nv_flinger);      WLAN::InstallInterfaces(*sm); - -    LOG_DEBUG(Service, "initialized OK");  } -/// Shutdown ServiceManager -void Shutdown() { -    LOG_DEBUG(Service, "shutdown OK"); -} +Services::~Services() = default; +  } // namespace Service diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index a01ef3353..ed4792289 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -29,7 +29,11 @@ namespace Service {  namespace FileSystem {  class FileSystemController; -} // namespace FileSystem +} + +namespace NVFlinger { +class NVFlinger; +}  namespace SM {  class ServiceManager; @@ -181,10 +185,17 @@ private:      }  }; -/// Initialize ServiceManager -void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system); +/** + * The purpose of this class is to own any objects that need to be shared across the other service + * implementations. Will be torn down when the global system instance is shutdown. + */ +class Services final { +public: +    explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system); +    ~Services(); -/// Shutdown ServiceManager -void Shutdown(); +private: +    std::unique_ptr<NVFlinger::NVFlinger> nv_flinger; +};  } // namespace Service diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 5b0e371fe..86bd604f4 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -492,8 +492,8 @@ private:  class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {  public: -    explicit IHOSBinderDriver(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) -        : ServiceFramework("IHOSBinderDriver"), nv_flinger(std::move(nv_flinger)) { +    explicit IHOSBinderDriver(NVFlinger::NVFlinger& nv_flinger) +        : ServiceFramework("IHOSBinderDriver"), nv_flinger(nv_flinger) {          static const FunctionInfo functions[] = {              {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},              {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, @@ -530,8 +530,8 @@ private:          LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id,                    static_cast<u32>(transaction), flags); -        const auto guard = nv_flinger->Lock(); -        auto& buffer_queue = nv_flinger->FindBufferQueue(id); +        const auto guard = nv_flinger.Lock(); +        auto& buffer_queue = nv_flinger.FindBufferQueue(id);          switch (transaction) {          case TransactionId::Connect: { @@ -570,8 +570,8 @@ private:                      [=, this](std::shared_ptr<Kernel::Thread> thread,                                Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) {                          // Repeat TransactParcel DequeueBuffer when a buffer is available -                        const auto guard = nv_flinger->Lock(); -                        auto& buffer_queue = nv_flinger->FindBufferQueue(id); +                        const auto guard = nv_flinger.Lock(); +                        auto& buffer_queue = nv_flinger.FindBufferQueue(id);                          auto result = buffer_queue.DequeueBuffer(width, height);                          ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer."); @@ -676,7 +676,7 @@ private:          LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); -        const auto& buffer_queue = nv_flinger->FindBufferQueue(id); +        const auto& buffer_queue = nv_flinger.FindBufferQueue(id);          // TODO(Subv): Find out what this actually is.          IPC::ResponseBuilder rb{ctx, 2, 1}; @@ -684,8 +684,8 @@ private:          rb.PushCopyObjects(buffer_queue.GetBufferWaitEvent());      } -    std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; -}; // namespace VI +    NVFlinger::NVFlinger& nv_flinger; +};  class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {  public: @@ -771,7 +771,7 @@ private:          IPC::ResponseBuilder rb{ctx, 6};          rb.Push(RESULT_SUCCESS); -        if (Settings::values.use_docked_mode) { +        if (Settings::values.use_docked_mode.GetValue()) {              rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *                      static_cast<u32>(Settings::values.resolution_factor.GetValue()));              rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) * @@ -790,8 +790,8 @@ private:  class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {  public: -    explicit IManagerDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) -        : ServiceFramework("IManagerDisplayService"), nv_flinger(std::move(nv_flinger)) { +    explicit IManagerDisplayService(NVFlinger::NVFlinger& nv_flinger) +        : ServiceFramework("IManagerDisplayService"), nv_flinger(nv_flinger) {          // clang-format off          static const FunctionInfo functions[] = {              {200, nullptr, "AllocateProcessHeapBlock"}, @@ -893,7 +893,7 @@ private:                      "(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}",                      unknown, display, aruid); -        const auto layer_id = nv_flinger->CreateLayer(display); +        const auto layer_id = nv_flinger.CreateLayer(display);          if (!layer_id) {              LOG_ERROR(Service_VI, "Layer not found! display=0x{:016X}", display);              IPC::ResponseBuilder rb{ctx, 2}; @@ -930,12 +930,12 @@ private:          rb.Push(RESULT_SUCCESS);      } -    std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; +    NVFlinger::NVFlinger& nv_flinger;  };  class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {  public: -    explicit IApplicationDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); +    explicit IApplicationDisplayService(NVFlinger::NVFlinger& nv_flinger);  private:      enum class ConvertedScaleMode : u64 { @@ -1010,7 +1010,7 @@ private:          ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); -        const auto display_id = nv_flinger->OpenDisplay(name); +        const auto display_id = nv_flinger.OpenDisplay(name);          if (!display_id) {              LOG_ERROR(Service_VI, "Display not found! display_name={}", name);              IPC::ResponseBuilder rb{ctx, 2}; @@ -1110,7 +1110,7 @@ private:          LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid); -        const auto display_id = nv_flinger->OpenDisplay(display_name); +        const auto display_id = nv_flinger.OpenDisplay(display_name);          if (!display_id) {              LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id);              IPC::ResponseBuilder rb{ctx, 2}; @@ -1118,7 +1118,7 @@ private:              return;          } -        const auto buffer_queue_id = nv_flinger->FindBufferQueueId(*display_id, layer_id); +        const auto buffer_queue_id = nv_flinger.FindBufferQueueId(*display_id, layer_id);          if (!buffer_queue_id) {              LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id);              IPC::ResponseBuilder rb{ctx, 2}; @@ -1138,7 +1138,7 @@ private:          LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id); -        nv_flinger->CloseLayer(layer_id); +        nv_flinger.CloseLayer(layer_id);          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS); @@ -1154,7 +1154,7 @@ private:          // TODO(Subv): What's the difference between a Stray and a Managed layer? -        const auto layer_id = nv_flinger->CreateLayer(display_id); +        const auto layer_id = nv_flinger.CreateLayer(display_id);          if (!layer_id) {              LOG_ERROR(Service_VI, "Layer not found! layer_id={}", *layer_id);              IPC::ResponseBuilder rb{ctx, 2}; @@ -1162,7 +1162,7 @@ private:              return;          } -        const auto buffer_queue_id = nv_flinger->FindBufferQueueId(display_id, *layer_id); +        const auto buffer_queue_id = nv_flinger.FindBufferQueueId(display_id, *layer_id);          if (!buffer_queue_id) {              LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id);              IPC::ResponseBuilder rb{ctx, 2}; @@ -1193,7 +1193,7 @@ private:          LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id); -        const auto vsync_event = nv_flinger->FindVsyncEvent(display_id); +        const auto vsync_event = nv_flinger.FindVsyncEvent(display_id);          if (!vsync_event) {              LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id);              IPC::ResponseBuilder rb{ctx, 2}; @@ -1258,12 +1258,11 @@ private:          }      } -    std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; +    NVFlinger::NVFlinger& nv_flinger;  }; -IApplicationDisplayService::IApplicationDisplayService( -    std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) -    : ServiceFramework("IApplicationDisplayService"), nv_flinger(std::move(nv_flinger)) { +IApplicationDisplayService::IApplicationDisplayService(NVFlinger::NVFlinger& nv_flinger) +    : ServiceFramework("IApplicationDisplayService"), nv_flinger(nv_flinger) {      static const FunctionInfo functions[] = {          {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"},          {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"}, @@ -1304,8 +1303,7 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) {      return false;  } -void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, -                                   std::shared_ptr<NVFlinger::NVFlinger> nv_flinger, +void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, NVFlinger::NVFlinger& nv_flinger,                                     Permission permission) {      IPC::RequestParser rp{ctx};      const auto policy = rp.PopEnum<Policy>(); @@ -1319,11 +1317,10 @@ void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx,      IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS); -    rb.PushIpcInterface<IApplicationDisplayService>(std::move(nv_flinger)); +    rb.PushIpcInterface<IApplicationDisplayService>(nv_flinger);  } -void InstallInterfaces(SM::ServiceManager& service_manager, -                       std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) { +void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nv_flinger) {      std::make_shared<VI_M>(nv_flinger)->InstallAsService(service_manager);      std::make_shared<VI_S>(nv_flinger)->InstallAsService(service_manager);      std::make_shared<VI_U>(nv_flinger)->InstallAsService(service_manager); diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index 6b66f8b81..5229fa753 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h @@ -43,12 +43,11 @@ enum class Policy {  };  namespace detail { -void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, -                           std::shared_ptr<NVFlinger::NVFlinger> nv_flinger, Permission permission); +void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, NVFlinger::NVFlinger& nv_flinger, +                           Permission permission);  } // namespace detail  /// Registers all VI services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager, -                       std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); +void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nv_flinger);  } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp index 06070087f..41da3ee93 100644 --- a/src/core/hle/service/vi/vi_m.cpp +++ b/src/core/hle/service/vi/vi_m.cpp @@ -8,8 +8,7 @@  namespace Service::VI { -VI_M::VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) -    : ServiceFramework{"vi:m"}, nv_flinger{std::move(nv_flinger)} { +VI_M::VI_M(NVFlinger::NVFlinger& nv_flinger) : ServiceFramework{"vi:m"}, nv_flinger{nv_flinger} {      static const FunctionInfo functions[] = {          {2, &VI_M::GetDisplayService, "GetDisplayService"},          {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h index 290e06689..ee2489874 100644 --- a/src/core/hle/service/vi/vi_m.h +++ b/src/core/hle/service/vi/vi_m.h @@ -18,13 +18,13 @@ namespace Service::VI {  class VI_M final : public ServiceFramework<VI_M> {  public: -    explicit VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); +    explicit VI_M(NVFlinger::NVFlinger& nv_flinger);      ~VI_M() override;  private:      void GetDisplayService(Kernel::HLERequestContext& ctx); -    std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; +    NVFlinger::NVFlinger& nv_flinger;  };  } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_s.cpp b/src/core/hle/service/vi/vi_s.cpp index 57c596cc4..6acb51e2a 100644 --- a/src/core/hle/service/vi/vi_s.cpp +++ b/src/core/hle/service/vi/vi_s.cpp @@ -8,8 +8,7 @@  namespace Service::VI { -VI_S::VI_S(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) -    : ServiceFramework{"vi:s"}, nv_flinger{std::move(nv_flinger)} { +VI_S::VI_S(NVFlinger::NVFlinger& nv_flinger) : ServiceFramework{"vi:s"}, nv_flinger{nv_flinger} {      static const FunctionInfo functions[] = {          {1, &VI_S::GetDisplayService, "GetDisplayService"},          {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, diff --git a/src/core/hle/service/vi/vi_s.h b/src/core/hle/service/vi/vi_s.h index 47804dc0b..6790673ab 100644 --- a/src/core/hle/service/vi/vi_s.h +++ b/src/core/hle/service/vi/vi_s.h @@ -18,13 +18,13 @@ namespace Service::VI {  class VI_S final : public ServiceFramework<VI_S> {  public: -    explicit VI_S(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); +    explicit VI_S(NVFlinger::NVFlinger& nv_flinger);      ~VI_S() override;  private:      void GetDisplayService(Kernel::HLERequestContext& ctx); -    std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; +    NVFlinger::NVFlinger& nv_flinger;  };  } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_u.cpp b/src/core/hle/service/vi/vi_u.cpp index 6b7329345..44e00a4f6 100644 --- a/src/core/hle/service/vi/vi_u.cpp +++ b/src/core/hle/service/vi/vi_u.cpp @@ -8,8 +8,7 @@  namespace Service::VI { -VI_U::VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) -    : ServiceFramework{"vi:u"}, nv_flinger{std::move(nv_flinger)} { +VI_U::VI_U(NVFlinger::NVFlinger& nv_flinger) : ServiceFramework{"vi:u"}, nv_flinger{nv_flinger} {      static const FunctionInfo functions[] = {          {0, &VI_U::GetDisplayService, "GetDisplayService"},          {1, nullptr, "GetDisplayServiceWithProxyNameExchange"}, diff --git a/src/core/hle/service/vi/vi_u.h b/src/core/hle/service/vi/vi_u.h index 19bdb73b0..b59f986f0 100644 --- a/src/core/hle/service/vi/vi_u.h +++ b/src/core/hle/service/vi/vi_u.h @@ -18,13 +18,13 @@ namespace Service::VI {  class VI_U final : public ServiceFramework<VI_U> {  public: -    explicit VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); +    explicit VI_U(NVFlinger::NVFlinger& nv_flinger);      ~VI_U() override;  private:      void GetDisplayService(Kernel::HLERequestContext& ctx); -    std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; +    NVFlinger::NVFlinger& nv_flinger;  };  } // namespace Service::VI diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 394a1bf26..2002dc4f2 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -114,7 +114,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect      }      if (override_update) { -        const FileSys::PatchManager patch_manager(metadata.GetTitleID()); +        const FileSys::PatchManager patch_manager( +            metadata.GetTitleID(), system.GetFileSystemController(), system.GetContentProvider());          dir = patch_manager.PatchExeFS(dir);      } @@ -160,7 +161,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect      modules.clear();      const VAddr base_address{process.PageTable().GetCodeRegionStart()};      VAddr next_load_addr{base_address}; -    const FileSys::PatchManager pm{metadata.GetTitleID()}; +    const FileSys::PatchManager pm{metadata.GetTitleID(), system.GetFileSystemController(), +                                   system.GetContentProvider()};      for (const auto& module : static_modules) {          const FileSys::VirtualFile module_file{dir->GetFile(module)};          if (!module_file) { diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 9bc3a8840..d91c15561 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -10,6 +10,7 @@  #include "common/file_util.h"  #include "common/logging/log.h"  #include "common/string_util.h" +#include "core/core.h"  #include "core/hle/kernel/process.h"  #include "core/loader/deconstructed_rom_directory.h"  #include "core/loader/elf.h" @@ -194,15 +195,15 @@ AppLoader::~AppLoader() = default;  /**   * Get a loader for a file with a specific type - * @param file The file to load - * @param type The type of the file - * @param file the file to retrieve the loader for - * @param type the file type + * @param system The system context to use. + * @param file   The file to retrieve the loader for + * @param type   The file type + * @param program_index Specifies the index within the container of the program to launch.   * @return std::unique_ptr<AppLoader> a pointer to a loader object;  nullptr for unsupported type   */ -static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileType type) { +static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::VirtualFile file, +                                                FileType type, std::size_t program_index) {      switch (type) { -      // Standard ELF file format.      case FileType::ELF:          return std::make_unique<AppLoader_ELF>(std::move(file)); @@ -221,7 +222,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT      // NX XCI (nX Card Image) file format.      case FileType::XCI: -        return std::make_unique<AppLoader_XCI>(std::move(file)); +        return std::make_unique<AppLoader_XCI>(std::move(file), system.GetFileSystemController(), +                                               system.GetContentProvider(), program_index);      // NX NAX (NintendoAesXts) file format.      case FileType::NAX: @@ -229,7 +231,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT      // NX NSP (Nintendo Submission Package) file format      case FileType::NSP: -        return std::make_unique<AppLoader_NSP>(std::move(file)); +        return std::make_unique<AppLoader_NSP>(std::move(file), system.GetFileSystemController(), +                                               system.GetContentProvider(), program_index);      // NX KIP (Kernel Internal Process) file format      case FileType::KIP: @@ -244,20 +247,22 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT      }  } -std::unique_ptr<AppLoader> GetLoader(FileSys::VirtualFile file) { +std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, +                                     std::size_t program_index) {      FileType type = IdentifyFile(file); -    FileType filename_type = GuessFromFilename(file->GetName()); +    const FileType filename_type = GuessFromFilename(file->GetName());      // Special case: 00 is either a NCA or NAX.      if (type != filename_type && !(file->GetName() == "00" && type == FileType::NAX)) {          LOG_WARNING(Loader, "File {} has a different type than its extension.", file->GetName()); -        if (FileType::Unknown == type) +        if (FileType::Unknown == type) {              type = filename_type; +        }      }      LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type)); -    return GetFileLoader(std::move(file), type); +    return GetFileLoader(system, std::move(file), type, program_index);  }  } // namespace Loader diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index ac60b097a..36e79e71d 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -290,9 +290,14 @@ protected:  /**   * Identifies a bootable file and return a suitable loader - * @param file The bootable file - * @return the best loader for this file + * + * @param system The system context. + * @param file   The bootable file. + * @param program_index Specifies the index within the container of the program to launch. + * + * @return the best loader for this file.   */ -std::unique_ptr<AppLoader> GetLoader(FileSys::VirtualFile file); +std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, +                                     std::size_t program_index = 0);  } // namespace Loader diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 497f438a1..aa85c1a29 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -149,7 +149,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::S      // Apply cheats if they exist and the program has a valid title ID      if (pm) {          system.SetCurrentProcessBuildID(nso_header.build_id); -        const auto cheats = pm->CreateCheatList(system, nso_header.build_id); +        const auto cheats = pm->CreateCheatList(nso_header.build_id);          if (!cheats.empty()) {              system.RegisterCheatList(cheats, nso_header.build_id, load_base, image_size);          } diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index 15e528fa8..928f64c8c 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp @@ -21,26 +21,34 @@  namespace Loader { -AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file) -    : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file)), +AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file, +                             const Service::FileSystem::FileSystemController& fsc, +                             const FileSys::ContentProvider& content_provider, +                             std::size_t program_index) +    : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file, program_index)),        title_id(nsp->GetProgramTitleID()) { -    if (nsp->GetStatus() != ResultStatus::Success) +    if (nsp->GetStatus() != ResultStatus::Success) {          return; +    }      if (nsp->IsExtractedType()) {          secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS());      } else {          const auto control_nca =              nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Control); -        if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) +        if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) {              return; +        } -        std::tie(nacp_file, icon_file) = -            FileSys::PatchManager(nsp->GetProgramTitleID()).ParseControlNCA(*control_nca); +        std::tie(nacp_file, icon_file) = [this, &content_provider, &control_nca, &fsc] { +            const FileSys::PatchManager pm{nsp->GetProgramTitleID(), fsc, content_provider}; +            return pm.ParseControlNCA(*control_nca); +        }(); -        if (title_id == 0) +        if (title_id == 0) {              return; +        }          secondary_loader = std::make_unique<AppLoader_NCA>(              nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program)); diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h index b27deb686..f0518ac47 100644 --- a/src/core/loader/nsp.h +++ b/src/core/loader/nsp.h @@ -9,15 +9,16 @@  #include "core/file_sys/vfs.h"  #include "core/loader/loader.h" -namespace Core { -class System; -} -  namespace FileSys { +class ContentProvider;  class NACP;  class NSP;  } // namespace FileSys +namespace Service::FileSystem { +class FileSystemController; +} +  namespace Loader {  class AppLoader_NCA; @@ -25,7 +26,10 @@ class AppLoader_NCA;  /// Loads an XCI file  class AppLoader_NSP final : public AppLoader {  public: -    explicit AppLoader_NSP(FileSys::VirtualFile file); +    explicit AppLoader_NSP(FileSys::VirtualFile file, +                           const Service::FileSystem::FileSystemController& fsc, +                           const FileSys::ContentProvider& content_provider, +                           std::size_t program_index);      ~AppLoader_NSP() override;      /** diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 25e83af0f..aaa250cea 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp @@ -20,18 +20,25 @@  namespace Loader { -AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file) -    : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)), +AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file, +                             const Service::FileSystem::FileSystemController& fsc, +                             const FileSys::ContentProvider& content_provider, +                             std::size_t program_index) +    : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file, program_index)),        nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) { -    if (xci->GetStatus() != ResultStatus::Success) +    if (xci->GetStatus() != ResultStatus::Success) {          return; +    }      const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control); -    if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) +    if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) {          return; +    } -    std::tie(nacp_file, icon_file) = -        FileSys::PatchManager(xci->GetProgramTitleID()).ParseControlNCA(*control_nca); +    std::tie(nacp_file, icon_file) = [this, &content_provider, &control_nca, &fsc] { +        const FileSys::PatchManager pm{xci->GetProgramTitleID(), fsc, content_provider}; +        return pm.ParseControlNCA(*control_nca); +    }();  }  AppLoader_XCI::~AppLoader_XCI() = default; diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index 04aea286f..764dc8328 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h @@ -9,15 +9,16 @@  #include "core/file_sys/vfs.h"  #include "core/loader/loader.h" -namespace Core { -class System; -} -  namespace FileSys { +class ContentProvider;  class NACP;  class XCI;  } // namespace FileSys +namespace Service::FileSystem { +class FileSystemController; +} +  namespace Loader {  class AppLoader_NCA; @@ -25,7 +26,10 @@ class AppLoader_NCA;  /// Loads an XCI file  class AppLoader_XCI final : public AppLoader {  public: -    explicit AppLoader_XCI(FileSys::VirtualFile file); +    explicit AppLoader_XCI(FileSys::VirtualFile file, +                           const Service::FileSystem::FileSystemController& fsc, +                           const FileSys::ContentProvider& content_provider, +                           std::size_t program_index);      ~AppLoader_XCI() override;      /** diff --git a/src/core/settings.cpp b/src/core/settings.cpp index a99d3cf5a..aadbc3932 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -49,13 +49,14 @@ void LogSettings() {      };      LOG_INFO(Config, "yuzu Configuration:"); -    log_setting("Controls_UseDockedMode", values.use_docked_mode); +    log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue());      log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0));      log_setting("System_CurrentUser", values.current_user);      log_setting("System_LanguageIndex", values.language_index.GetValue());      log_setting("System_RegionIndex", values.region_index.GetValue());      log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());      log_setting("Core_UseMultiCore", values.use_multi_core.GetValue()); +    log_setting("CPU_Accuracy", values.cpu_accuracy);      log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue());      log_setting("Renderer_UseFrameLimit", values.use_frame_limit.GetValue());      log_setting("Renderer_FrameLimit", values.frame_limit.GetValue()); @@ -144,6 +145,12 @@ void RestoreGlobalState() {      values.rng_seed.SetGlobal(true);      values.custom_rtc.SetGlobal(true);      values.sound_index.SetGlobal(true); + +    // Controls +    values.players.SetGlobal(true); +    values.use_docked_mode.SetGlobal(true); +    values.vibration_enabled.SetGlobal(true); +    values.motion_enabled.SetGlobal(true);  }  void Sanitize() { diff --git a/src/core/settings.h b/src/core/settings.h index 28616a574..1143aba5d 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -65,6 +65,38 @@ private:      Type local{};  }; +/** + * The InputSetting class allows for getting a reference to either the global or local members. + * This is required as we cannot easily modify the values of user-defined types within containers + * using the SetValue() member function found in the Setting class. The primary purpose of this + * class is to store an array of 10 PlayerInput structs for both the global and local (per-game) + * setting and allows for easily accessing and modifying both settings. + */ +template <typename Type> +class InputSetting final { +public: +    InputSetting() = default; +    explicit InputSetting(Type val) : global{val} {} +    ~InputSetting() = default; +    void SetGlobal(bool to_global) { +        use_global = to_global; +    } +    bool UsingGlobal() const { +        return use_global; +    } +    Type& GetValue(bool need_global = false) { +        if (use_global || need_global) { +            return global; +        } +        return local; +    } + +private: +    bool use_global = true; +    Type global{}; +    Type local{}; +}; +  struct TouchFromButtonMap {      std::string name;      std::vector<std::string> buttons; @@ -133,9 +165,18 @@ struct Values {      Setting<s32> sound_index;      // Controls -    std::array<PlayerInput, 10> players; +    InputSetting<std::array<PlayerInput, 10>> players; + +    Setting<bool> use_docked_mode; -    bool use_docked_mode; +    Setting<bool> vibration_enabled; +    Setting<bool> enable_accurate_vibrations; + +    Setting<bool> motion_enabled; +    std::string motion_device; +    std::string udp_input_address; +    u16 udp_input_port; +    u8 udp_pad_index;      bool mouse_enabled;      std::string mouse_device; @@ -149,20 +190,15 @@ struct Values {      ButtonsRaw debug_pad_buttons;      AnalogsRaw debug_pad_analogs; -    bool vibration_enabled; - -    bool motion_enabled; -    std::string motion_device; -    std::string touch_device;      TouchscreenInput touchscreen; -    std::atomic_bool is_device_reload_pending{true}; +      bool use_touch_from_button; +    std::string touch_device;      int touch_from_button_map_index; -    std::string udp_input_address; -    u16 udp_input_port; -    u8 udp_pad_index;      std::vector<TouchFromButtonMap> touch_from_button_maps; +    std::atomic_bool is_device_reload_pending{true}; +      // Data Storage      bool use_virtual_sd;      bool gamecard_inserted; @@ -179,6 +215,7 @@ struct Values {      bool reporting_services;      bool quest_flag;      bool disable_macro_jit; +    bool extended_logging;      // Misceallaneous      std::string log_filter; diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index ebc19e18a..d11b15f38 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -147,7 +147,9 @@ TelemetrySession::~TelemetrySession() {      }  } -void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) { +void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader, +                                      const Service::FileSystem::FileSystemController& fsc, +                                      const FileSys::ContentProvider& content_provider) {      // Log one-time top-level information      AddField(Telemetry::FieldType::None, "TelemetryId", GetTelemetryId()); @@ -167,7 +169,10 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {          app_loader.ReadTitle(name);          if (name.empty()) { -            const auto metadata = FileSys::PatchManager(program_id).GetControlMetadata(); +            const auto metadata = [&content_provider, &fsc, program_id] { +                const FileSys::PatchManager pm{program_id, fsc, content_provider}; +                return pm.GetControlMetadata(); +            }();              if (metadata.first != nullptr) {                  name = metadata.first->GetApplicationName();              } @@ -213,7 +218,7 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {               Settings::values.use_assembly_shaders.GetValue());      AddField(field_type, "Renderer_UseAsynchronousShaders",               Settings::values.use_asynchronous_shaders.GetValue()); -    AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode); +    AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode.GetValue());  }  bool TelemetrySession::SubmitTestcase() { diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h index 66789d4bd..6f3d45bea 100644 --- a/src/core/telemetry_session.h +++ b/src/core/telemetry_session.h @@ -7,10 +7,18 @@  #include <string>  #include "common/telemetry.h" +namespace FileSys { +class ContentProvider; +} +  namespace Loader {  class AppLoader;  } +namespace Service::FileSystem { +class FileSystemController; +} +  namespace Core {  /** @@ -40,10 +48,14 @@ public:       *   - Title file format       *   - Miscellaneous settings values.       * -     * @param app_loader The application loader to use to retrieve -     *                   title-specific information. +     * @param app_loader       The application loader to use to retrieve +     *                         title-specific information. +     * @param fsc              Filesystem controller to use to retrieve info. +     * @param content_provider Content provider to use to retrieve info.       */ -    void AddInitialInfo(Loader::AppLoader& app_loader); +    void AddInitialInfo(Loader::AppLoader& app_loader, +                        const Service::FileSystem::FileSystemController& fsc, +                        const FileSys::ContentProvider& content_provider);      /**       * Wrapper around the Telemetry::FieldCollection::AddField method. | 
