diff options
author | Fernando Sahmkow <fsahmkow27@gmail.com> | 2023-12-24 18:20:02 +0100 |
---|---|---|
committer | Liam <byteslice@airmail.cc> | 2024-01-19 03:12:30 +0100 |
commit | 7a9d1ad2f873003e6aad637e8749b77b91247da3 (patch) | |
tree | e167a5d5ad73dbd78dc4b5c165b12a1220a167f4 /src/core/hle/service/nvdrv | |
parent | Core: Initial implementation of device memory mapping (diff) | |
download | yuzu-7a9d1ad2f873003e6aad637e8749b77b91247da3.tar yuzu-7a9d1ad2f873003e6aad637e8749b77b91247da3.tar.gz yuzu-7a9d1ad2f873003e6aad637e8749b77b91247da3.tar.bz2 yuzu-7a9d1ad2f873003e6aad637e8749b77b91247da3.tar.lz yuzu-7a9d1ad2f873003e6aad637e8749b77b91247da3.tar.xz yuzu-7a9d1ad2f873003e6aad637e8749b77b91247da3.tar.zst yuzu-7a9d1ad2f873003e6aad637e8749b77b91247da3.zip |
Diffstat (limited to 'src/core/hle/service/nvdrv')
29 files changed, 227 insertions, 72 deletions
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; }; |