summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/nvdrv
diff options
context:
space:
mode:
authorFernando Sahmkow <fsahmkow27@gmail.com>2023-12-24 18:20:02 +0100
committerLiam <byteslice@airmail.cc>2024-01-19 03:12:30 +0100
commit7a9d1ad2f873003e6aad637e8749b77b91247da3 (patch)
treee167a5d5ad73dbd78dc4b5c165b12a1220a167f4 /src/core/hle/service/nvdrv
parentCore: Initial implementation of device memory mapping (diff)
downloadyuzu-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')
-rw-r--r--src/core/hle/service/nvdrv/core/container.cpp44
-rw-r--r--src/core/hle/service/nvdrv/core/container.h15
-rw-r--r--src/core/hle/service/nvdrv/core/nvmap.cpp58
-rw-r--r--src/core/hle/service/nvdrv/core/nvmap.h16
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp9
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp31
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h7
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp27
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h6
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.cpp36
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.h1
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;
};