summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Liam2023-10-24 10:28:03 -0400
committerGravatar Liam2023-10-25 13:05:55 -0400
commit6256e3ca8e74d7f97e4dabc3e9b24de1a0d8df3c (patch)
treeefaa6e20bca5c592b7f7ccc3b2821f4b18a225e2 /src
parentMerge pull request #11876 from liamwhite/apiversion (diff)
downloadyuzu-6256e3ca8e74d7f97e4dabc3e9b24de1a0d8df3c.tar.gz
yuzu-6256e3ca8e74d7f97e4dabc3e9b24de1a0d8df3c.tar.xz
yuzu-6256e3ca8e74d7f97e4dabc3e9b24de1a0d8df3c.zip
nvdrv: add ioctl command serialization, convert nvhost_as_gpu
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/nvdrv/devices/ioctl_serialization.h107
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp78
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h20
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp6
5 files changed, 152 insertions, 71 deletions
diff --git a/src/core/hle/service/nvdrv/devices/ioctl_serialization.h b/src/core/hle/service/nvdrv/devices/ioctl_serialization.h
new file mode 100644
index 000000000..c560974f1
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/ioctl_serialization.h
@@ -0,0 +1,107 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <span>
7#include <vector>
8
9#include "common/concepts.h"
10#include "core/hle/service/nvdrv/devices/nvdevice.h"
11
12namespace Service::Nvidia::Devices {
13
14struct Ioctl1Traits {
15 template <typename T, typename R, typename A>
16 static T GetClassImpl(R (T::*)(A));
17
18 template <typename T, typename R, typename A>
19 static A GetArgImpl(R (T::*)(A));
20};
21
22struct Ioctl23Traits {
23 template <typename T, typename R, typename A, typename B>
24 static T GetClassImpl(R (T::*)(A, B));
25
26 template <typename T, typename R, typename A, typename B>
27 static A GetArgImpl(R (T::*)(A, B));
28};
29
30template <typename T>
31struct ContainerType {
32 using ValueType = T;
33};
34
35template <Common::IsContiguousContainer T>
36struct ContainerType<T> {
37 using ValueType = T::value_type;
38};
39
40template <typename InnerArg, typename F, typename Self, typename... Rest>
41NvResult Wrap(std::span<const u8> input, std::span<u8> output, Self* self, F&& callable,
42 Rest&&... rest) {
43 using Arg = ContainerType<InnerArg>::ValueType;
44 constexpr bool ArgumentIsContainer = Common::IsContiguousContainer<InnerArg>;
45
46 // Verify that the input and output sizes are valid.
47 const size_t in_params = input.size() / sizeof(Arg);
48 const size_t out_params = output.size() / sizeof(Arg);
49 if (in_params * sizeof(Arg) != input.size()) {
50 return NvResult::InvalidSize;
51 }
52 if (out_params * sizeof(Arg) != output.size()) {
53 return NvResult::InvalidSize;
54 }
55 if (in_params == 0 && out_params == 0 && !ArgumentIsContainer) {
56 return NvResult::InvalidSize;
57 }
58
59 // Copy inputs, if needed.
60 std::vector<Arg> params(std::max(in_params, out_params));
61 if (in_params > 0) {
62 std::memcpy(params.data(), input.data(), input.size());
63 }
64
65 // Perform the call.
66 NvResult result;
67 if constexpr (ArgumentIsContainer) {
68 result = (self->*callable)(params, std::forward<Rest>(rest)...);
69 } else {
70 result = (self->*callable)(params.front(), std::forward<Rest>(rest)...);
71 }
72
73 // Copy outputs, if needed.
74 if (out_params > 0) {
75 std::memcpy(output.data(), params.data(), output.size());
76 }
77
78 return result;
79}
80
81template <typename F>
82NvResult nvdevice::Wrap1(F&& callable, std::span<const u8> input, std::span<u8> output) {
83 using Self = decltype(Ioctl1Traits::GetClassImpl(callable));
84 using InnerArg = std::remove_reference_t<decltype(Ioctl1Traits::GetArgImpl(callable))>;
85
86 return Wrap<InnerArg>(input, output, static_cast<Self*>(this), callable);
87}
88
89template <typename F>
90NvResult nvdevice::Wrap2(F&& callable, std::span<const u8> input, std::span<const u8> inline_input,
91 std::span<u8> output) {
92 using Self = decltype(Ioctl23Traits::GetClassImpl(callable));
93 using InnerArg = std::remove_reference_t<decltype(Ioctl23Traits::GetArgImpl(callable))>;
94
95 return Wrap<InnerArg>(input, output, static_cast<Self*>(this), callable, inline_input);
96}
97
98template <typename F>
99NvResult nvdevice::Wrap3(F&& callable, std::span<const u8> input, std::span<u8> output,
100 std::span<u8> inline_output) {
101 using Self = decltype(Ioctl23Traits::GetClassImpl(callable));
102 using InnerArg = std::remove_reference_t<decltype(Ioctl23Traits::GetArgImpl(callable))>;
103
104 return Wrap<InnerArg>(input, output, static_cast<Self*>(this), callable, inline_output);
105}
106
107} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h
index a04538d5d..af766f320 100644
--- a/src/core/hle/service/nvdrv/devices/nvdevice.h
+++ b/src/core/hle/service/nvdrv/devices/nvdevice.h
@@ -75,6 +75,18 @@ public:
75 } 75 }
76 76
77protected: 77protected:
78 template <typename F>
79 NvResult Wrap1(F&& callable, std::span<const u8> input, std::span<u8> output);
80
81 template <typename F>
82 NvResult Wrap2(F&& callable, std::span<const u8> input, std::span<const u8> inline_input,
83 std::span<u8> output);
84
85 template <typename F>
86 NvResult Wrap3(F&& callable, std::span<const u8> input, std::span<u8> output,
87 std::span<u8> inline_output);
88
89protected:
78 Core::System& system; 90 Core::System& system;
79}; 91};
80 92
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 7d7bb8687..484001071 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -11,6 +11,7 @@
11#include "core/core.h" 11#include "core/core.h"
12#include "core/hle/service/nvdrv/core/container.h" 12#include "core/hle/service/nvdrv/core/container.h"
13#include "core/hle/service/nvdrv/core/nvmap.h" 13#include "core/hle/service/nvdrv/core/nvmap.h"
14#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
14#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" 15#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h"
15#include "core/hle/service/nvdrv/devices/nvhost_gpu.h" 16#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
16#include "core/hle/service/nvdrv/nvdrv.h" 17#include "core/hle/service/nvdrv/nvdrv.h"
@@ -33,21 +34,21 @@ NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> i
33 case 'A': 34 case 'A':
34 switch (command.cmd) { 35 switch (command.cmd) {
35 case 0x1: 36 case 0x1:
36 return BindChannel(input, output); 37 return Wrap1(&nvhost_as_gpu::BindChannel, input, output);
37 case 0x2: 38 case 0x2:
38 return AllocateSpace(input, output); 39 return Wrap1(&nvhost_as_gpu::AllocateSpace, input, output);
39 case 0x3: 40 case 0x3:
40 return FreeSpace(input, output); 41 return Wrap1(&nvhost_as_gpu::FreeSpace, input, output);
41 case 0x5: 42 case 0x5:
42 return UnmapBuffer(input, output); 43 return Wrap1(&nvhost_as_gpu::UnmapBuffer, input, output);
43 case 0x6: 44 case 0x6:
44 return MapBufferEx(input, output); 45 return Wrap1(&nvhost_as_gpu::MapBufferEx, input, output);
45 case 0x8: 46 case 0x8:
46 return GetVARegions(input, output); 47 return Wrap1(&nvhost_as_gpu::GetVARegions1, input, output);
47 case 0x9: 48 case 0x9:
48 return AllocAsEx(input, output); 49 return Wrap1(&nvhost_as_gpu::AllocAsEx, input, output);
49 case 0x14: 50 case 0x14:
50 return Remap(input, output); 51 return Wrap1(&nvhost_as_gpu::Remap, input, output);
51 default: 52 default:
52 break; 53 break;
53 } 54 }
@@ -72,7 +73,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i
72 case 'A': 73 case 'A':
73 switch (command.cmd) { 74 switch (command.cmd) {
74 case 0x8: 75 case 0x8:
75 return GetVARegions(input, output, inline_output); 76 return Wrap3(&nvhost_as_gpu::GetVARegions3, input, output, inline_output);
76 default: 77 default:
77 break; 78 break;
78 } 79 }
@@ -87,10 +88,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i
87void nvhost_as_gpu::OnOpen(DeviceFD fd) {} 88void nvhost_as_gpu::OnOpen(DeviceFD fd) {}
88void nvhost_as_gpu::OnClose(DeviceFD fd) {} 89void nvhost_as_gpu::OnClose(DeviceFD fd) {}
89 90
90NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::span<u8> output) { 91NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
91 IoctlAllocAsEx params{};
92 std::memcpy(&params, input.data(), input.size());
93
94 LOG_DEBUG(Service_NVDRV, "called, big_page_size=0x{:X}", params.big_page_size); 92 LOG_DEBUG(Service_NVDRV, "called, big_page_size=0x{:X}", params.big_page_size);
95 93
96 std::scoped_lock lock(mutex); 94 std::scoped_lock lock(mutex);
@@ -141,10 +139,7 @@ NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::span<u8> outpu
141 return NvResult::Success; 139 return NvResult::Success;
142} 140}
143 141
144NvResult nvhost_as_gpu::AllocateSpace(std::span<const u8> input, std::span<u8> output) { 142NvResult nvhost_as_gpu::AllocateSpace(IoctlAllocSpace& params) {
145 IoctlAllocSpace params{};
146 std::memcpy(&params, input.data(), input.size());
147
148 LOG_DEBUG(Service_NVDRV, "called, pages={:X}, page_size={:X}, flags={:X}", params.pages, 143 LOG_DEBUG(Service_NVDRV, "called, pages={:X}, page_size={:X}, flags={:X}", params.pages,
149 params.page_size, params.flags); 144 params.page_size, params.flags);
150 145
@@ -194,7 +189,6 @@ NvResult nvhost_as_gpu::AllocateSpace(std::span<const u8> input, std::span<u8> o
194 .big_pages = params.page_size != VM::YUZU_PAGESIZE, 189 .big_pages = params.page_size != VM::YUZU_PAGESIZE,
195 }; 190 };
196 191
197 std::memcpy(output.data(), &params, output.size());
198 return NvResult::Success; 192 return NvResult::Success;
199} 193}
200 194
@@ -222,10 +216,7 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) {
222 mapping_map.erase(offset); 216 mapping_map.erase(offset);
223} 217}
224 218
225NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::span<u8> output) { 219NvResult nvhost_as_gpu::FreeSpace(IoctlFreeSpace& params) {
226 IoctlFreeSpace params{};
227 std::memcpy(&params, input.data(), input.size());
228
229 LOG_DEBUG(Service_NVDRV, "called, offset={:X}, pages={:X}, page_size={:X}", params.offset, 220 LOG_DEBUG(Service_NVDRV, "called, offset={:X}, pages={:X}, page_size={:X}", params.offset,
230 params.pages, params.page_size); 221 params.pages, params.page_size);
231 222
@@ -264,18 +255,11 @@ NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::span<u8> outpu
264 return NvResult::BadValue; 255 return NvResult::BadValue;
265 } 256 }
266 257
267 std::memcpy(output.data(), &params, output.size());
268 return NvResult::Success; 258 return NvResult::Success;
269} 259}
270 260
271NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::span<u8> output) { 261NvResult nvhost_as_gpu::Remap(std::span<IoctlRemapEntry> entries) {
272 const auto num_entries = input.size() / sizeof(IoctlRemapEntry); 262 LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", entries.size());
273
274 LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries);
275
276 std::scoped_lock lock(mutex);
277 entries.resize_destructive(num_entries);
278 std::memcpy(entries.data(), input.data(), input.size());
279 263
280 if (!vm.initialised) { 264 if (!vm.initialised) {
281 return NvResult::BadValue; 265 return NvResult::BadValue;
@@ -317,14 +301,10 @@ NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::span<u8> output) {
317 } 301 }
318 } 302 }
319 303
320 std::memcpy(output.data(), entries.data(), output.size());
321 return NvResult::Success; 304 return NvResult::Success;
322} 305}
323 306
324NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::span<u8> output) { 307NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) {
325 IoctlMapBufferEx params{};
326 std::memcpy(&params, input.data(), input.size());
327
328 LOG_DEBUG(Service_NVDRV, 308 LOG_DEBUG(Service_NVDRV,
329 "called, flags={:X}, nvmap_handle={:X}, buffer_offset={}, mapping_size={}" 309 "called, flags={:X}, nvmap_handle={:X}, buffer_offset={}, mapping_size={}"
330 ", offset={}", 310 ", offset={}",
@@ -421,14 +401,10 @@ NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::span<u8> out
421 mapping_map[params.offset] = mapping; 401 mapping_map[params.offset] = mapping;
422 } 402 }
423 403
424 std::memcpy(output.data(), &params, output.size());
425 return NvResult::Success; 404 return NvResult::Success;
426} 405}
427 406
428NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::span<u8> output) { 407NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) {
429 IoctlUnmapBuffer params{};
430 std::memcpy(&params, input.data(), input.size());
431
432 LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset); 408 LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset);
433 409
434 std::scoped_lock lock(mutex); 410 std::scoped_lock lock(mutex);
@@ -464,9 +440,7 @@ NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::span<u8> out
464 return NvResult::Success; 440 return NvResult::Success;
465} 441}
466 442
467NvResult nvhost_as_gpu::BindChannel(std::span<const u8> input, std::span<u8> output) { 443NvResult nvhost_as_gpu::BindChannel(IoctlBindChannel& params) {
468 IoctlBindChannel params{};
469 std::memcpy(&params, input.data(), input.size());
470 LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); 444 LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
471 445
472 auto gpu_channel_device = module.GetDevice<nvhost_gpu>(params.fd); 446 auto gpu_channel_device = module.GetDevice<nvhost_gpu>(params.fd);
@@ -493,10 +467,7 @@ void nvhost_as_gpu::GetVARegionsImpl(IoctlGetVaRegions& params) {
493 }; 467 };
494} 468}
495 469
496NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> output) { 470NvResult nvhost_as_gpu::GetVARegions1(IoctlGetVaRegions& params) {
497 IoctlGetVaRegions params{};
498 std::memcpy(&params, input.data(), input.size());
499
500 LOG_DEBUG(Service_NVDRV, "called, buf_addr={:X}, buf_size={:X}", params.buf_addr, 471 LOG_DEBUG(Service_NVDRV, "called, buf_addr={:X}, buf_size={:X}", params.buf_addr,
501 params.buf_size); 472 params.buf_size);
502 473
@@ -508,15 +479,10 @@ NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> ou
508 479
509 GetVARegionsImpl(params); 480 GetVARegionsImpl(params);
510 481
511 std::memcpy(output.data(), &params, output.size());
512 return NvResult::Success; 482 return NvResult::Success;
513} 483}
514 484
515NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> output, 485NvResult nvhost_as_gpu::GetVARegions3(IoctlGetVaRegions& params, std::span<u8> inline_output) {
516 std::span<u8> inline_output) {
517 IoctlGetVaRegions params{};
518 std::memcpy(&params, input.data(), input.size());
519
520 LOG_DEBUG(Service_NVDRV, "called, buf_addr={:X}, buf_size={:X}", params.buf_addr, 486 LOG_DEBUG(Service_NVDRV, "called, buf_addr={:X}, buf_size={:X}", params.buf_addr,
521 params.buf_size); 487 params.buf_size);
522 488
@@ -528,9 +494,7 @@ NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> ou
528 494
529 GetVARegionsImpl(params); 495 GetVARegionsImpl(params);
530 496
531 std::memcpy(output.data(), &params, output.size()); 497 std::memcpy(inline_output.data(), params.regions.data(), 2 * sizeof(VaRegion));
532 std::memcpy(inline_output.data(), &params.regions[0], sizeof(VaRegion));
533 std::memcpy(inline_output.data() + sizeof(VaRegion), &params.regions[1], sizeof(VaRegion));
534 498
535 return NvResult::Success; 499 return NvResult::Success;
536} 500}
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 2af3e1260..bc041f215 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -139,18 +139,17 @@ private:
139 static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(VaRegion) * 2, 139 static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(VaRegion) * 2,
140 "IoctlGetVaRegions is incorrect size"); 140 "IoctlGetVaRegions is incorrect size");
141 141
142 NvResult AllocAsEx(std::span<const u8> input, std::span<u8> output); 142 NvResult AllocAsEx(IoctlAllocAsEx& params);
143 NvResult AllocateSpace(std::span<const u8> input, std::span<u8> output); 143 NvResult AllocateSpace(IoctlAllocSpace& params);
144 NvResult Remap(std::span<const u8> input, std::span<u8> output); 144 NvResult Remap(std::span<IoctlRemapEntry> params);
145 NvResult MapBufferEx(std::span<const u8> input, std::span<u8> output); 145 NvResult MapBufferEx(IoctlMapBufferEx& params);
146 NvResult UnmapBuffer(std::span<const u8> input, std::span<u8> output); 146 NvResult UnmapBuffer(IoctlUnmapBuffer& params);
147 NvResult FreeSpace(std::span<const u8> input, std::span<u8> output); 147 NvResult FreeSpace(IoctlFreeSpace& params);
148 NvResult BindChannel(std::span<const u8> input, std::span<u8> output); 148 NvResult BindChannel(IoctlBindChannel& params);
149 149
150 void GetVARegionsImpl(IoctlGetVaRegions& params); 150 void GetVARegionsImpl(IoctlGetVaRegions& params);
151 NvResult GetVARegions(std::span<const u8> input, std::span<u8> output); 151 NvResult GetVARegions1(IoctlGetVaRegions& params);
152 NvResult GetVARegions(std::span<const u8> input, std::span<u8> output, 152 NvResult GetVARegions3(IoctlGetVaRegions& params, std::span<u8> inline_output);
153 std::span<u8> inline_output);
154 153
155 void FreeMappingLocked(u64 offset); 154 void FreeMappingLocked(u64 offset);
156 155
@@ -213,7 +212,6 @@ private:
213 bool initialised{}; 212 bool initialised{};
214 } vm; 213 } vm;
215 std::shared_ptr<Tegra::MemoryManager> gmmu; 214 std::shared_ptr<Tegra::MemoryManager> gmmu;
216 Common::ScratchBuffer<IoctlRemapEntry> entries;
217 215
218 // s32 channel{}; 216 // s32 channel{};
219 // u32 big_page_size{VM::DEFAULT_BIG_PAGE_SIZE}; 217 // u32 big_page_size{VM::DEFAULT_BIG_PAGE_SIZE};
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 46a25fcab..804157ce3 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -134,7 +134,7 @@ NvResult nvhost_gpu::SetClientData(std::span<const u8> input, std::span<u8> outp
134 LOG_DEBUG(Service_NVDRV, "called"); 134 LOG_DEBUG(Service_NVDRV, "called");
135 135
136 IoctlClientData params{}; 136 IoctlClientData params{};
137 std::memcpy(&params, input.data(), input.size()); 137 std::memcpy(&params, input.data(), std::min(sizeof(IoctlClientData), input.size()));
138 user_data = params.data; 138 user_data = params.data;
139 return NvResult::Success; 139 return NvResult::Success;
140} 140}
@@ -143,9 +143,9 @@ NvResult nvhost_gpu::GetClientData(std::span<const u8> input, std::span<u8> outp
143 LOG_DEBUG(Service_NVDRV, "called"); 143 LOG_DEBUG(Service_NVDRV, "called");
144 144
145 IoctlClientData params{}; 145 IoctlClientData params{};
146 std::memcpy(&params, input.data(), input.size()); 146 std::memcpy(&params, input.data(), std::min(sizeof(IoctlClientData), input.size()));
147 params.data = user_data; 147 params.data = user_data;
148 std::memcpy(output.data(), &params, output.size()); 148 std::memcpy(output.data(), &params, std::min(sizeof(IoctlClientData), output.size()));
149 return NvResult::Success; 149 return NvResult::Success;
150} 150}
151 151