diff options
Diffstat (limited to 'src/core/hle')
33 files changed, 252 insertions, 83 deletions
| diff --git a/src/core/hle/service/hle_ipc.h b/src/core/hle/service/hle_ipc.h index 440737db5..d550a11b7 100644 --- a/src/core/hle/service/hle_ipc.h +++ b/src/core/hle/service/hle_ipc.h @@ -19,6 +19,8 @@  #include "core/hle/ipc.h"  #include "core/hle/kernel/k_handle_table.h"  #include "core/hle/kernel/svc_common.h" +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_handle_table.h"  union Result; @@ -41,6 +43,8 @@ class KernelCore;  class KHandleTable;  class KProcess;  class KServerSession; +template <typename T> +class KScopedAutoObject;  class KThread;  } // namespace Kernel @@ -373,6 +377,10 @@ public:          return nullptr;      } +    Kernel::KScopedAutoObject<Kernel::KAutoObject> GetObjectFromHandle(u32 handle) { +        return GetClientHandleTable().GetObjectForIpc(handle, thread); +    } +      [[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const {          return manager.lock();      } diff --git a/src/core/hle/service/nvdrv/core/container.cpp b/src/core/hle/service/nvdrv/core/container.cpp index 37ca24f5d..7c2231fe6 100644 --- a/src/core/hle/service/nvdrv/core/container.cpp +++ b/src/core/hle/service/nvdrv/core/container.cpp @@ -2,19 +2,30 @@  // SPDX-FileCopyrightText: 2022 Skyline Team and Contributors  // SPDX-License-Identifier: GPL-3.0-or-later +#include <atomic> +#include <deque> +#include <mutex> + +#include "core/hle/kernel/k_process.h"  #include "core/hle/service/nvdrv/core/container.h"  #include "core/hle/service/nvdrv/core/nvmap.h"  #include "core/hle/service/nvdrv/core/syncpoint_manager.h" +#include "core/memory.h"  #include "video_core/host1x/host1x.h"  namespace Service::Nvidia::NvCore {  struct ContainerImpl {      explicit ContainerImpl(Tegra::Host1x::Host1x& host1x_) -        : file{host1x_}, manager{host1x_}, device_file_data{} {} +        : host1x{host1x_}, file{host1x_}, manager{host1x_}, device_file_data{} {} +    Tegra::Host1x::Host1x& host1x;      NvMap file;      SyncpointManager manager;      Container::Host1xDeviceFileData device_file_data; +    std::deque<Session> sessions; +    size_t new_ids{}; +    std::deque<size_t> id_pool; +    std::mutex session_guard;  };  Container::Container(Tegra::Host1x::Host1x& host1x_) { @@ -23,6 +34,37 @@ Container::Container(Tegra::Host1x::Host1x& host1x_) {  Container::~Container() = default; +size_t Container::OpenSession(Kernel::KProcess* process) { +    std::scoped_lock lk(impl->session_guard); +    size_t new_id{}; +    auto* memory_interface = &process->GetMemory(); +    auto& smmu = impl->host1x.MemoryManager(); +    auto smmu_id = smmu.RegisterProcess(memory_interface); +    if (!impl->id_pool.empty()) { +        new_id = impl->id_pool.front(); +        impl->id_pool.pop_front(); +        impl->sessions[new_id] = Session{new_id, process, smmu_id}; +    } else { +        impl->sessions.emplace_back(new_id, process, smmu_id); +        new_id = impl->new_ids++; +    } +    LOG_CRITICAL(Debug, "Created Session {}", new_id); +    return new_id; +} + +void Container::CloseSession(size_t id) { +    std::scoped_lock lk(impl->session_guard); +    auto& smmu = impl->host1x.MemoryManager(); +    smmu.UnregisterProcess(impl->sessions[id].smmu_id); +    impl->id_pool.emplace_front(id); +    LOG_CRITICAL(Debug, "Closed Session {}", id); +} + +Session* Container::GetSession(size_t id) { +    std::atomic_thread_fence(std::memory_order_acquire); +    return &impl->sessions[id]; +} +  NvMap& Container::GetNvMapFile() {      return impl->file;  } diff --git a/src/core/hle/service/nvdrv/core/container.h b/src/core/hle/service/nvdrv/core/container.h index b4b63ac90..a1fd20199 100644 --- a/src/core/hle/service/nvdrv/core/container.h +++ b/src/core/hle/service/nvdrv/core/container.h @@ -10,6 +10,10 @@  #include "core/hle/service/nvdrv/nvdata.h" +namespace Kernel { +class KProcess; +} +  namespace Tegra::Host1x {  class Host1x;  } // namespace Tegra::Host1x @@ -21,11 +25,22 @@ class SyncpointManager;  struct ContainerImpl; +struct Session { +    size_t id; +    Kernel::KProcess* process; +    size_t smmu_id; +}; +  class Container {  public:      explicit Container(Tegra::Host1x::Host1x& host1x);      ~Container(); +    size_t OpenSession(Kernel::KProcess* process); +    void CloseSession(size_t id); + +    Session* GetSession(size_t id); +      NvMap& GetNvMapFile();      const NvMap& GetNvMapFile() const; diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index 0ca05257e..fd6c9aa0c 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -18,8 +18,6 @@ NvMap::Handle::Handle(u64 size_, Id id_)  }  NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress) { -    std::scoped_lock lock(mutex); -      // Handles cannot be allocated twice      if (allocated) {          return NvResult::AccessDenied; @@ -79,10 +77,11 @@ void NvMap::UnmapHandle(Handle& handle_description) {      }      // Free and unmap the handle from the SMMU -    host1x.MemoryManager().Unmap(static_cast<GPUVAddr>(handle_description.pin_virt_address), -                                 handle_description.aligned_size); -    host1x.Allocator().Free(handle_description.pin_virt_address, -                            static_cast<u32>(handle_description.aligned_size)); +    auto& smmu = host1x.MemoryManager(); +    smmu.Unmap(static_cast<DAddr>(handle_description.pin_virt_address), +               handle_description.aligned_size); +    smmu.Free(handle_description.pin_virt_address, +              static_cast<size_t>(handle_description.aligned_size));      handle_description.pin_virt_address = 0;  } @@ -133,7 +132,32 @@ VAddr NvMap::GetHandleAddress(Handle::Id handle) {      }  } -u32 NvMap::PinHandle(NvMap::Handle::Id handle) { +NvResult NvMap::AllocateHandle(Handle::Id handle, Handle::Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, size_t session_id) { +    auto handle_description{GetHandle(handle)}; +    if (!handle_description) [[unlikely]] { +        return NvResult::BadParameter; +    } + +    if (handle_description->allocated) [[unlikely]] { +        return NvResult::InsufficientMemory; +    } + +    std::scoped_lock lock(handle_description->mutex); +    NvResult result = handle_description->Alloc(pFlags, pAlign, pKind, pAddress); +    if (result != NvResult::Success) { +        return result; +    } +    auto& smmu = host1x.MemoryManager(); +    size_t total_size = static_cast<size_t>(handle_description->aligned_size); +    handle_description->d_address = smmu.Allocate(total_size); +    if (handle_description->d_address == 0) { +        return NvResult::InsufficientMemory; +    } +    smmu.Map(handle_description->d_address, handle_description->address, total_size, session_id); +    return NvResult::Success; +} + +u32 NvMap::PinHandle(NvMap::Handle::Id handle, size_t session_id) {      auto handle_description{GetHandle(handle)};      if (!handle_description) [[unlikely]] {          return 0; @@ -157,11 +181,10 @@ u32 NvMap::PinHandle(NvMap::Handle::Id handle) {          }          // If not then allocate some space and map it -        u32 address{}; -        auto& smmu_allocator = host1x.Allocator(); -        auto& smmu_memory_manager = host1x.MemoryManager(); -        while ((address = smmu_allocator.Allocate( -                    static_cast<u32>(handle_description->aligned_size))) == 0) { +        DAddr address{}; +        auto& smmu = host1x.MemoryManager(); +        while ((address = smmu.AllocatePinned( +                    static_cast<size_t>(handle_description->aligned_size))) == 0) {              // Free handles until the allocation succeeds              std::scoped_lock queueLock(unmap_queue_lock);              if (auto freeHandleDesc{unmap_queue.front()}) { @@ -175,9 +198,9 @@ u32 NvMap::PinHandle(NvMap::Handle::Id handle) {              }          } -        smmu_memory_manager.Map(static_cast<GPUVAddr>(address), handle_description->address, -                                handle_description->aligned_size); -        handle_description->pin_virt_address = address; +        smmu.Map(address, handle_description->address, handle_description->aligned_size, +                 session_id); +        handle_description->pin_virt_address = static_cast<u32>(address);      }      handle_description->pins++; @@ -236,6 +259,11 @@ std::optional<NvMap::FreeInfo> NvMap::FreeHandle(Handle::Id handle, bool interna                      std::scoped_lock queueLock(unmap_queue_lock);                      UnmapHandle(*handle_description);                  } +                if (handle_description->allocated) { +                    auto& smmu = host1x.MemoryManager(); +                    smmu.Free(handle_description->d_address, handle_description->aligned_size); +                    smmu.Unmap(handle_description->d_address, handle_description->aligned_size); +                }                  handle_description->pins = 0;              } diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index a8e573890..7c3110d91 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -61,8 +61,10 @@ public:          } flags{};          static_assert(sizeof(Flags) == sizeof(u32)); -        u64 address{}; //!< The memory location in the guest's AS that this handle corresponds to, -                       //!< this can also be in the nvdrv tmem +        VAddr address{};   //!< The memory location in the guest's AS that this handle corresponds to, +                           //!< this can also be in the nvdrv tmem +        DAddr d_address{}; //!< The memory location in the device's AS that this handle corresponds to, +                           //!< this can also be in the nvdrv tmem          bool is_shared_mem_mapped{}; //!< If this nvmap has been mapped with the MapSharedMem IPC                                       //!< call @@ -125,7 +127,15 @@ public:       * number of calls to `UnpinHandle`       * @return The SMMU virtual address that the handle has been mapped to       */ -    u32 PinHandle(Handle::Id handle); +    u32 PinHandle(Handle::Id handle, size_t session_id); + +    /** +     * @brief Maps a handle into the SMMU address space +     * @note This operation is refcounted, the number of calls to this must eventually match the +     * number of calls to `UnpinHandle` +     * @return The SMMU virtual address that the handle has been mapped to +     */ +    NvResult AllocateHandle(Handle::Id handle, Handle::Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, size_t session_id);      /**       * @brief When this has been called an equal number of times to `PinHandle` for the supplied diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index a04538d5d..ff91aabcb 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h @@ -62,7 +62,7 @@ public:       * Called once a device is opened       * @param fd The device fd       */ -    virtual void OnOpen(DeviceFD fd) = 0; +    virtual void OnOpen(size_t session_id, DeviceFD fd) = 0;      /**       * Called once a device is closed diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 05a43d8dc..0ff41c6b2 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -35,7 +35,7 @@ NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in      return NvResult::NotImplemented;  } -void nvdisp_disp0::OnOpen(DeviceFD fd) {} +void nvdisp_disp0::OnOpen(size_t session_id, DeviceFD fd) {}  void nvdisp_disp0::OnClose(DeviceFD fd) {}  void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index daee05fe8..4e32ec191 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -32,7 +32,7 @@ public:      NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,                      std::span<u8> inline_output) override; -    void OnOpen(DeviceFD fd) override; +    void OnOpen(size_t session_id, DeviceFD fd) override;      void OnClose(DeviceFD fd) override;      /// Performs a screen flip, drawing the buffer pointed to by the handle. 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 6b3639008..c92a7b2f6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -86,7 +86,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i      return NvResult::NotImplemented;  } -void nvhost_as_gpu::OnOpen(DeviceFD fd) {} +void nvhost_as_gpu::OnOpen(size_t session_id, DeviceFD fd) {}  void nvhost_as_gpu::OnClose(DeviceFD fd) {}  NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { 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 79a21683d..0dd279f88 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -55,7 +55,7 @@ public:      NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,                      std::span<u8> inline_output) override; -    void OnOpen(DeviceFD fd) override; +    void OnOpen(size_t session_id, DeviceFD fd) override;      void OnClose(DeviceFD fd) override;      Kernel::KEvent* QueryEvent(u32 event_id) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index b8dd34e24..c4033cf1b 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -76,7 +76,7 @@ NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inp      return NvResult::NotImplemented;  } -void nvhost_ctrl::OnOpen(DeviceFD fd) {} +void nvhost_ctrl::OnOpen(size_t session_id, DeviceFD fd) {}  void nvhost_ctrl::OnClose(DeviceFD fd) {} diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 992124b60..84f419f16 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -32,7 +32,7 @@ public:      NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,                      std::span<u8> inline_output) override; -    void OnOpen(DeviceFD fd) override; +    void OnOpen(size_t session_id, DeviceFD fd) override;      void OnClose(DeviceFD fd) override;      Kernel::KEvent* QueryEvent(u32 event_id) override; 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 3e0c96456..75276c37c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -82,7 +82,7 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8>      return NvResult::NotImplemented;  } -void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {} +void nvhost_ctrl_gpu::OnOpen(size_t session_id, DeviceFD fd) {}  void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {}  NvResult nvhost_ctrl_gpu::GetCharacteristics1(IoctlCharacteristics& params) { 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 d170299bd..6147e37cc 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h @@ -28,7 +28,7 @@ public:      NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,                      std::span<u8> inline_output) override; -    void OnOpen(DeviceFD fd) override; +    void OnOpen(size_t session_id, DeviceFD fd) override;      void OnClose(DeviceFD fd) override;      Kernel::KEvent* QueryEvent(u32 event_id) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index b0395c2f0..0929c7128 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -120,7 +120,7 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu      return NvResult::NotImplemented;  } -void nvhost_gpu::OnOpen(DeviceFD fd) {} +void nvhost_gpu::OnOpen(size_t session_id, DeviceFD fd) {}  void nvhost_gpu::OnClose(DeviceFD fd) {}  NvResult nvhost_gpu::SetNVMAPfd(IoctlSetNvmapFD& params) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 88fd228ff..f5a396c40 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -47,7 +47,7 @@ public:      NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,                      std::span<u8> inline_output) override; -    void OnOpen(DeviceFD fd) override; +    void OnOpen(size_t session_id, DeviceFD fd) override;      void OnClose(DeviceFD fd) override;      Kernel::KEvent* QueryEvent(u32 event_id) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index f43914e1b..63228518e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -35,7 +35,7 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in          case 0x7:              return WrapFixed(this, &nvhost_nvdec::SetSubmitTimeout, input, output);          case 0x9: -            return WrapFixedVariable(this, &nvhost_nvdec::MapBuffer, input, output); +            return WrapFixedVariable(this, &nvhost_nvdec::MapBuffer, input, output, fd);          case 0xa:              return WrapFixedVariable(this, &nvhost_nvdec::UnmapBuffer, input, output);          default: @@ -68,9 +68,10 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in      return NvResult::NotImplemented;  } -void nvhost_nvdec::OnOpen(DeviceFD fd) { +void nvhost_nvdec::OnOpen(size_t session_id, DeviceFD fd) {      LOG_INFO(Service_NVDRV, "NVDEC video stream started");      system.SetNVDECActive(true); +    sessions[fd] = session_id;  }  void nvhost_nvdec::OnClose(DeviceFD fd) { @@ -81,6 +82,10 @@ void nvhost_nvdec::OnClose(DeviceFD fd) {          system.GPU().ClearCdmaInstance(iter->second);      }      system.SetNVDECActive(false); +    auto it = sessions.find(fd); +    if (it != sessions.end()) { +        sessions.erase(it); +    }  }  } // 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 ad2233c49..1fb27b814 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -20,7 +20,7 @@ public:      NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,                      std::span<u8> inline_output) override; -    void OnOpen(DeviceFD fd) override; +    void OnOpen(size_t session_id, DeviceFD fd) override;      void OnClose(DeviceFD fd) override;  }; 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 74c701b95..9ab0ae4d8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -133,10 +133,10 @@ NvResult nvhost_nvdec_common::GetWaitbase(IoctlGetWaitbase& params) {      return NvResult::Success;  } -NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries) { +NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries, DeviceFD fd) {      const size_t num_entries = std::min(params.num_entries, static_cast<u32>(entries.size()));      for (size_t i = 0; i < num_entries; i++) { -        entries[i].map_address = nvmap.PinHandle(entries[i].map_handle); +        entries[i].map_address = nvmap.PinHandle(entries[i].map_handle, sessions[fd]);      }      return NvResult::Success; 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 7ce748e18..b44b17a82 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -5,6 +5,8 @@  #include <deque>  #include <vector> +#include <unordered_map> +  #include "common/common_types.h"  #include "common/swap.h"  #include "core/hle/service/nvdrv/core/syncpoint_manager.h" @@ -111,7 +113,7 @@ protected:      NvResult Submit(IoctlSubmit& params, std::span<u8> input, DeviceFD fd);      NvResult GetSyncpoint(IoctlGetSyncpoint& params);      NvResult GetWaitbase(IoctlGetWaitbase& params); -    NvResult MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries); +    NvResult MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries, DeviceFD fd);      NvResult UnmapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries);      NvResult SetSubmitTimeout(u32 timeout); @@ -125,6 +127,7 @@ protected:      NvCore::NvMap& nvmap;      NvCore::ChannelType channel_type;      std::array<u32, MaxSyncPoints> device_syncpoints{}; +    std::unordered_map<DeviceFD, size_t> sessions;  };  }; // namespace Devices  } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index 9e6b86458..1c88b39ab 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp @@ -44,7 +44,7 @@ NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in      return NvResult::NotImplemented;  } -void nvhost_nvjpg::OnOpen(DeviceFD fd) {} +void nvhost_nvjpg::OnOpen(size_t session_id, DeviceFD fd) {}  void nvhost_nvjpg::OnClose(DeviceFD fd) {}  NvResult nvhost_nvjpg::SetNVMAPfd(IoctlSetNvmapFD& params) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 790c97f6a..3e33dffef 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h @@ -22,7 +22,7 @@ public:      NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,                      std::span<u8> inline_output) override; -    void OnOpen(DeviceFD fd) override; +    void OnOpen(size_t session_id, DeviceFD fd) override;      void OnClose(DeviceFD fd) override;  private: diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 87f8d7c22..d4c93ea5d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -33,7 +33,7 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu          case 0x3:              return WrapFixed(this, &nvhost_vic::GetWaitbase, input, output);          case 0x9: -            return WrapFixedVariable(this, &nvhost_vic::MapBuffer, input, output); +            return WrapFixedVariable(this, &nvhost_vic::MapBuffer, input, output, fd);          case 0xa:              return WrapFixedVariable(this, &nvhost_vic::UnmapBuffer, input, output);          default: @@ -68,7 +68,9 @@ NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu      return NvResult::NotImplemented;  } -void nvhost_vic::OnOpen(DeviceFD fd) {} +void nvhost_vic::OnOpen(size_t session_id, DeviceFD fd) { +        sessions[fd] = session_id; +}  void nvhost_vic::OnClose(DeviceFD fd) {      auto& host1x_file = core.Host1xDeviceFile(); @@ -76,6 +78,10 @@ void nvhost_vic::OnClose(DeviceFD fd) {      if (iter != host1x_file.fd_to_id.end()) {          system.GPU().ClearCdmaInstance(iter->second);      } +    auto it = sessions.find(fd); +    if (it != sessions.end()) { +        sessions.erase(it); +    }  }  } // 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 cadbcb0a5..d70df0f20 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h @@ -19,7 +19,7 @@ public:      NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,                      std::span<u8> inline_output) override; -    void OnOpen(DeviceFD fd) override; +    void OnOpen(size_t session_id, DeviceFD fd) override;      void OnClose(DeviceFD fd) 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 71b2e62ec..2b107f009 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -36,9 +36,9 @@ NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,          case 0x3:              return WrapFixed(this, &nvmap::IocFromId, input, output);          case 0x4: -            return WrapFixed(this, &nvmap::IocAlloc, input, output); +            return WrapFixed(this, &nvmap::IocAlloc, input, output, fd);          case 0x5: -            return WrapFixed(this, &nvmap::IocFree, input, output); +            return WrapFixed(this, &nvmap::IocFree, input, output, fd);          case 0x9:              return WrapFixed(this, &nvmap::IocParam, input, output);          case 0xe: @@ -67,8 +67,15 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, st      return NvResult::NotImplemented;  } -void nvmap::OnOpen(DeviceFD fd) {} -void nvmap::OnClose(DeviceFD fd) {} +void nvmap::OnOpen(size_t session_id, DeviceFD fd) { +    sessions[fd] = session_id; +} +void nvmap::OnClose(DeviceFD fd) { +    auto it = sessions.find(fd); +    if (it != sessions.end()) { +        sessions.erase(it); +    } +}  NvResult nvmap::IocCreate(IocCreateParams& params) {      LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size); @@ -87,7 +94,7 @@ NvResult nvmap::IocCreate(IocCreateParams& params) {      return NvResult::Success;  } -NvResult nvmap::IocAlloc(IocAllocParams& params) { +NvResult nvmap::IocAlloc(IocAllocParams& params, DeviceFD fd) {      LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address);      if (!params.handle) { @@ -116,15 +123,15 @@ NvResult nvmap::IocAlloc(IocAllocParams& params) {          return NvResult::InsufficientMemory;      } -    const auto result = -        handle_description->Alloc(params.flags, params.align, params.kind, params.address); +    const auto result = file.AllocateHandle(params.handle, params.flags, params.align, params.kind, +                                            params.address, sessions[fd]);      if (result != NvResult::Success) {          LOG_CRITICAL(Service_NVDRV, "Object failed to allocate, handle={:08X}", params.handle);          return result;      }      bool is_out_io{}; -    ASSERT(system.ApplicationProcess() -               ->GetPageTable() +    auto process = container.GetSession(sessions[fd])->process; +    ASSERT(process->GetPageTable()                 .LockForMapDeviceAddressSpace(&is_out_io, handle_description->address,                                               handle_description->size,                                               Kernel::KMemoryPermission::None, true, false) @@ -224,7 +231,7 @@ NvResult nvmap::IocParam(IocParamParams& params) {      return NvResult::Success;  } -NvResult nvmap::IocFree(IocFreeParams& params) { +NvResult nvmap::IocFree(IocFreeParams& params, DeviceFD fd) {      LOG_DEBUG(Service_NVDRV, "called");      if (!params.handle) { @@ -233,9 +240,9 @@ NvResult nvmap::IocFree(IocFreeParams& params) {      }      if (auto freeInfo{file.FreeHandle(params.handle, false)}) { +        auto process = container.GetSession(sessions[fd])->process;          if (freeInfo->can_unlock) { -            ASSERT(system.ApplicationProcess() -                       ->GetPageTable() +            ASSERT(process->GetPageTable()                         .UnlockForDeviceAddressSpace(freeInfo->address, freeInfo->size)                         .IsSuccess());          } diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 049c11028..ea5df2a9c 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -33,7 +33,7 @@ public:      NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,                      std::span<u8> inline_output) override; -    void OnOpen(DeviceFD fd) override; +    void OnOpen(size_t session_id, DeviceFD fd) override;      void OnClose(DeviceFD fd) override;      enum class HandleParameterType : u32_le { @@ -100,11 +100,11 @@ public:      static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");      NvResult IocCreate(IocCreateParams& params); -    NvResult IocAlloc(IocAllocParams& params); +    NvResult IocAlloc(IocAllocParams& params, DeviceFD fd);      NvResult IocGetId(IocGetIdParams& params);      NvResult IocFromId(IocFromIdParams& params);      NvResult IocParam(IocParamParams& params); -    NvResult IocFree(IocFreeParams& params); +    NvResult IocFree(IocFreeParams& params, DeviceFD fd);  private:      /// Id to use for the next handle that is created. @@ -115,6 +115,7 @@ private:      NvCore::Container& container;      NvCore::NvMap& file; +    std::unordered_map<DeviceFD, size_t> sessions;  };  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 9e46ee8dd..5191341db 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -45,13 +45,22 @@ void EventInterface::FreeEvent(Kernel::KEvent* event) {  void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) {      auto server_manager = std::make_unique<ServerManager>(system);      auto module = std::make_shared<Module>(system); -    server_manager->RegisterNamedService("nvdrv", std::make_shared<NVDRV>(system, module, "nvdrv")); -    server_manager->RegisterNamedService("nvdrv:a", -                                         std::make_shared<NVDRV>(system, module, "nvdrv:a")); -    server_manager->RegisterNamedService("nvdrv:s", -                                         std::make_shared<NVDRV>(system, module, "nvdrv:s")); -    server_manager->RegisterNamedService("nvdrv:t", -                                         std::make_shared<NVDRV>(system, module, "nvdrv:t")); +    const auto NvdrvInterfaceFactoryForApplication = [&, module] { +        return std::make_shared<NVDRV>(system, module, "nvdrv"); +    }; +    const auto NvdrvInterfaceFactoryForApplets = [&, module] { +        return std::make_shared<NVDRV>(system, module, "nvdrv:a"); +    }; +    const auto NvdrvInterfaceFactoryForSysmodules = [&, module] { +        return std::make_shared<NVDRV>(system, module, "nvdrv:a"); +    }; +    const auto NvdrvInterfaceFactory = [&, module] { +        return std::make_shared<NVDRV>(system, module, "nvdrv:t"); +    }; +    server_manager->RegisterNamedService("nvdrv", NvdrvInterfaceFactoryForApplication); +    server_manager->RegisterNamedService("nvdrv:a", NvdrvInterfaceFactoryForApplets); +    server_manager->RegisterNamedService("nvdrv:s", NvdrvInterfaceFactoryForSysmodules); +    server_manager->RegisterNamedService("nvdrv:t", NvdrvInterfaceFactory);      server_manager->RegisterNamedService("nvmemp", std::make_shared<NVMEMP>(system));      nvnflinger.SetNVDrvInstance(module);      ServerManager::RunServer(std::move(server_manager)); @@ -113,7 +122,7 @@ NvResult Module::VerifyFD(DeviceFD fd) const {      return NvResult::Success;  } -DeviceFD Module::Open(const std::string& device_name) { +DeviceFD Module::Open(const std::string& device_name, size_t session_id) {      auto it = builders.find(device_name);      if (it == builders.end()) {          LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name); @@ -124,7 +133,7 @@ DeviceFD Module::Open(const std::string& device_name) {      auto& builder = it->second;      auto device = builder(fd)->second; -    device->OnOpen(fd); +    device->OnOpen(session_id, fd);      return fd;  } diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index d8622b3ca..d7648fb15 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -77,7 +77,7 @@ public:      NvResult VerifyFD(DeviceFD fd) const;      /// Opens a device node and returns a file descriptor to it. -    DeviceFD Open(const std::string& device_name); +    DeviceFD Open(const std::string& device_name, size_t session_id);      /// Sends an ioctl command to the specified file descriptor.      NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output); @@ -93,6 +93,10 @@ public:      NvResult QueryEvent(DeviceFD fd, u32 event_id, Kernel::KEvent*& event); +    NvCore::Container& GetContainer() { +        return container; +    } +  private:      friend class EventInterface;      friend class Service::Nvnflinger::Nvnflinger; diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp index c8a880e84..492ad849a 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp +++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp @@ -3,14 +3,18 @@  // SPDX-License-Identifier: GPL-3.0-or-later  #include "common/logging/log.h" +#include "common/scope_exit.h"  #include "core/core.h"  #include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_process.h"  #include "core/hle/kernel/k_readable_event.h"  #include "core/hle/service/ipc_helpers.h"  #include "core/hle/service/nvdrv/nvdata.h"  #include "core/hle/service/nvdrv/nvdrv.h"  #include "core/hle/service/nvdrv/nvdrv_interface.h" +#pragma optimize("", off) +  namespace Service::Nvidia {  void NVDRV::Open(HLERequestContext& ctx) { @@ -37,7 +41,7 @@ void NVDRV::Open(HLERequestContext& ctx) {          return;      } -    DeviceFD fd = nvdrv->Open(device_name); +    DeviceFD fd = nvdrv->Open(device_name, session_id);      rb.Push<DeviceFD>(fd);      rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed); @@ -150,12 +154,29 @@ void NVDRV::Close(HLERequestContext& ctx) {  void NVDRV::Initialize(HLERequestContext& ctx) {      LOG_WARNING(Service_NVDRV, "(STUBBED) called"); +    IPC::ResponseBuilder rb{ctx, 3}; +    SCOPE_EXIT({ +        rb.Push(ResultSuccess); +        rb.PushEnum(NvResult::Success); +    }); -    is_initialized = true; +    if (is_initialized) { +        // No need to initialize again +        return; +    } -    IPC::ResponseBuilder rb{ctx, 3}; -    rb.Push(ResultSuccess); -    rb.PushEnum(NvResult::Success); +    IPC::RequestParser rp{ctx}; +    const auto process_handle{ctx.GetCopyHandle(0)}; +    // The transfer memory is lent to nvdrv as a work buffer since nvdrv is +    // unable to allocate as much memory on its own. For HLE it's unnecessary to handle it +    [[maybe_unused]] const auto transfer_memory_handle{ctx.GetCopyHandle(1)}; +    [[maybe_unused]] const auto transfer_memory_size = rp.Pop<u32>(); + +    auto& container = nvdrv->GetContainer(); +    auto process = ctx.GetObjectFromHandle(process_handle); +    session_id = container.OpenSession(process->DynamicCast<Kernel::KProcess*>()); + +    is_initialized = true;  }  void NVDRV::QueryEvent(HLERequestContext& ctx) { @@ -242,6 +263,9 @@ NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char*      RegisterHandlers(functions);  } -NVDRV::~NVDRV() = default; +NVDRV::~NVDRV() { +    auto& container = nvdrv->GetContainer(); +    container.CloseSession(session_id); +}  } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.h b/src/core/hle/service/nvdrv/nvdrv_interface.h index 6e98115dc..e7237c881 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.h +++ b/src/core/hle/service/nvdrv/nvdrv_interface.h @@ -35,6 +35,7 @@ private:      u64 pid{};      bool is_initialized{}; +    size_t session_id{};      Common::ScratchBuffer<u8> output_buffer;      Common::ScratchBuffer<u8> inline_output_buffer;  }; diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp index 2fef6cc1a..d36eff4ec 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp @@ -87,19 +87,19 @@ Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap,      R_SUCCEED();  } -Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle) { +Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Nvidia::DeviceFD nvmap_fd) {      // Free the handle.      Nvidia::Devices::nvmap::IocFreeParams free_params{          .handle = handle,      }; -    R_UNLESS(nvmap.IocFree(free_params) == Nvidia::NvResult::Success, VI::ResultOperationFailed); +    R_UNLESS(nvmap.IocFree(free_params, nvmap_fd) == Nvidia::NvResult::Success, VI::ResultOperationFailed);      // We succeeded.      R_SUCCEED();  }  Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::ProcessAddress buffer, -                        u32 size) { +                        u32 size, Nvidia::DeviceFD nvmap_fd) {      // Assign the allocated memory to the handle.      Nvidia::Devices::nvmap::IocAllocParams alloc_params{          .handle = handle, @@ -109,16 +109,15 @@ Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::Proce          .kind = 0,          .address = GetInteger(buffer),      }; -    R_UNLESS(nvmap.IocAlloc(alloc_params) == Nvidia::NvResult::Success, VI::ResultOperationFailed); +    R_UNLESS(nvmap.IocAlloc(alloc_params, nvmap_fd) == Nvidia::NvResult::Success, VI::ResultOperationFailed);      // We succeeded.      R_SUCCEED();  } -Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, +Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, Nvidia::DeviceFD nvmap_fd,                                 Common::ProcessAddress buffer, u32 size) {      // Get the nvmap device. -    auto nvmap_fd = nvdrv.Open("/dev/nvmap");      auto nvmap = nvdrv.GetDevice<Nvidia::Devices::nvmap>(nvmap_fd);      ASSERT(nvmap != nullptr); @@ -127,11 +126,11 @@ Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv,      // Ensure we maintain a clean state on failure.      ON_RESULT_FAILURE { -        ASSERT(R_SUCCEEDED(FreeNvMapHandle(*nvmap, *out_handle))); +        ASSERT(R_SUCCEEDED(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd)));      };      // Assign the allocated memory to the handle. -    R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size)); +    R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size, nvmap_fd));  }  constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888; @@ -197,8 +196,12 @@ Result FbShareBufferManager::Initialize(u64* out_buffer_id, u64* out_layer_id, u                                             std::addressof(m_buffer_page_group), m_system,                                             SharedBufferSize)); +    auto& container = m_nvdrv->GetContainer(); +    m_session_id = container.OpenSession(m_system.ApplicationProcess()); +    m_nvmap_fd = m_nvdrv->Open("/dev/nvmap", m_session_id); +      // Create an nvmap handle for the buffer and assign the memory to it. -    R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, map_address, +    R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, m_nvmap_fd, map_address,                                    SharedBufferSize));      // Record the display id. diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h index c809c01b4..4b1a3d430 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h @@ -6,6 +6,7 @@  #include "common/math_util.h"  #include "core/hle/service/nvnflinger/nvnflinger.h"  #include "core/hle/service/nvnflinger/ui/fence.h" +#include "core/hle/service/nvdrv/nvdata.h"  namespace Kernel {  class KPageGroup; @@ -53,13 +54,15 @@ private:      u64 m_layer_id = 0;      u32 m_buffer_nvmap_handle = 0;      SharedMemoryPoolLayout m_pool_layout = {}; - +    Nvidia::DeviceFD m_nvmap_fd = {}; +    size_t m_session_id = {};      std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group;      std::mutex m_guard;      Core::System& m_system;      Nvnflinger& m_flinger;      std::shared_ptr<Nvidia::Module> m_nvdrv; +  };  } // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index 0469110e8..e4b38ae0b 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp @@ -126,7 +126,7 @@ void Nvnflinger::ShutdownLayers() {  void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {      nvdrv = std::move(instance); -    disp_fd = nvdrv->Open("/dev/nvdisp_disp0"); +    disp_fd = nvdrv->Open("/dev/nvdisp_disp0", 0);  }  std::optional<u64> Nvnflinger::OpenDisplay(std::string_view name) { | 
