summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/nvdrv/devices/ioctl_serialization.h159
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp82
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h20
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp42
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp115
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h29
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp117
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h35
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp15
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp87
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h14
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp7
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp13
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp47
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h12
-rw-r--r--src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp27
18 files changed, 407 insertions, 428 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..b12bcd138
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/ioctl_serialization.h
@@ -0,0 +1,159 @@
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 IoctlOneArgTraits {
15 template <typename T, typename R, typename A, typename... B>
16 static A GetFirstArgImpl(R (T::*)(A, B...));
17};
18
19struct IoctlTwoArgTraits {
20 template <typename T, typename R, typename A, typename B, typename... C>
21 static A GetFirstArgImpl(R (T::*)(A, B, C...));
22
23 template <typename T, typename R, typename A, typename B, typename... C>
24 static B GetSecondArgImpl(R (T::*)(A, B, C...));
25};
26
27struct Null {};
28
29// clang-format off
30
31template <typename FixedArg, typename VarArg, typename InlInVarArg, typename InlOutVarArg, typename F>
32NvResult WrapGeneric(F&& callable, std::span<const u8> input, std::span<const u8> inline_input, std::span<u8> output, std::span<u8> inline_output) {
33 constexpr bool HasFixedArg = !std::is_same_v<FixedArg, Null>;
34 constexpr bool HasVarArg = !std::is_same_v<VarArg, Null>;
35 constexpr bool HasInlInVarArg = !std::is_same_v<InlInVarArg, Null>;
36 constexpr bool HasInlOutVarArg = !std::is_same_v<InlOutVarArg, Null>;
37
38 // Declare the fixed-size input value.
39 FixedArg fixed{};
40 size_t var_offset = 0;
41
42 if constexpr (HasFixedArg) {
43 // Read the fixed-size input value.
44 var_offset = std::min(sizeof(FixedArg), input.size());
45 if (var_offset > 0) {
46 std::memcpy(&fixed, input.data(), var_offset);
47 }
48 }
49
50 // Read the variable-sized inputs.
51 const size_t num_var_args = HasVarArg ? ((input.size() - var_offset) / sizeof(VarArg)) : 0;
52 std::vector<VarArg> var_args(num_var_args);
53 if constexpr (HasVarArg) {
54 if (num_var_args > 0) {
55 std::memcpy(var_args.data(), input.data() + var_offset, num_var_args * sizeof(VarArg));
56 }
57 }
58
59 const size_t num_inl_in_var_args = HasInlInVarArg ? (inline_input.size() / sizeof(InlInVarArg)) : 0;
60 std::vector<InlInVarArg> inl_in_var_args(num_inl_in_var_args);
61 if constexpr (HasInlInVarArg) {
62 if (num_inl_in_var_args > 0) {
63 std::memcpy(inl_in_var_args.data(), inline_input.data(), num_inl_in_var_args * sizeof(InlInVarArg));
64 }
65 }
66
67 // Construct inline output data.
68 const size_t num_inl_out_var_args = HasInlOutVarArg ? (inline_output.size() / sizeof(InlOutVarArg)) : 0;
69 std::vector<InlOutVarArg> inl_out_var_args(num_inl_out_var_args);
70
71 // Perform the call.
72 NvResult result = callable(fixed, var_args, inl_in_var_args, inl_out_var_args);
73
74 // Copy outputs.
75 if constexpr (HasFixedArg) {
76 if (output.size() > 0) {
77 std::memcpy(output.data(), &fixed, std::min(output.size(), sizeof(FixedArg)));
78 }
79 }
80
81 if constexpr (HasVarArg) {
82 if (num_var_args > 0 && output.size() > var_offset) {
83 const size_t max_var_size = output.size() - var_offset;
84 std::memcpy(output.data() + var_offset, var_args.data(), std::min(max_var_size, num_var_args * sizeof(VarArg)));
85 }
86 }
87
88 // Copy inline outputs.
89 if constexpr (HasInlOutVarArg) {
90 if (num_inl_out_var_args > 0) {
91 std::memcpy(inline_output.data(), inl_out_var_args.data(), num_inl_out_var_args * sizeof(InlOutVarArg));
92 }
93 }
94
95 // We're done.
96 return result;
97}
98
99template <typename Self, typename F, typename... Rest>
100NvResult WrapFixed(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, Rest&&... rest) {
101 using FixedArg = typename std::remove_reference_t<decltype(IoctlOneArgTraits::GetFirstArgImpl(callable))>;
102
103 const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
104 return (self->*callable)(fixed, std::forward<Rest>(rest)...);
105 };
106
107 return WrapGeneric<FixedArg, Null, Null, Null>(std::move(Callable), input, {}, output, {});
108}
109
110template <typename Self, typename F, typename... Rest>
111NvResult WrapFixedInlOut(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, std::span<u8> inline_output, Rest&&... rest) {
112 using FixedArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetFirstArgImpl(callable))>;
113 using InlOutVarArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetSecondArgImpl(callable))>::value_type;
114
115 const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
116 return (self->*callable)(fixed, inl_out, std::forward<Rest>(rest)...);
117 };
118
119 return WrapGeneric<FixedArg, Null, Null, InlOutVarArg>(std::move(Callable), input, {}, output, inline_output);
120}
121
122template <typename Self, typename F, typename... Rest>
123NvResult WrapVariable(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, Rest&&... rest) {
124 using VarArg = typename std::remove_reference_t<decltype(IoctlOneArgTraits::GetFirstArgImpl(callable))>::value_type;
125
126 const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
127 return (self->*callable)(var, std::forward<Rest>(rest)...);
128 };
129
130 return WrapGeneric<Null, VarArg, Null, Null>(std::move(Callable), input, {}, output, {});
131}
132
133template <typename Self, typename F, typename... Rest>
134NvResult WrapFixedVariable(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, Rest&&... rest) {
135 using FixedArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetFirstArgImpl(callable))>;
136 using VarArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetSecondArgImpl(callable))>::value_type;
137
138 const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
139 return (self->*callable)(fixed, var, std::forward<Rest>(rest)...);
140 };
141
142 return WrapGeneric<FixedArg, VarArg, Null, Null>(std::move(Callable), input, {}, output, {});
143}
144
145template <typename Self, typename F, typename... Rest>
146NvResult WrapFixedInlIn(Self* self, F&& callable, std::span<const u8> input, std::span<const u8> inline_input, std::span<u8> output, Rest&&... rest) {
147 using FixedArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetFirstArgImpl(callable))>;
148 using InlInVarArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetSecondArgImpl(callable))>::value_type;
149
150 const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
151 return (self->*callable)(fixed, inl_in, std::forward<Rest>(rest)...);
152 };
153
154 return WrapGeneric<FixedArg, Null, InlInVarArg, Null>(std::move(Callable), input, inline_input, output, {});
155}
156
157// clang-format on
158
159} // namespace Service::Nvidia::Devices
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..6b3639008 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 WrapFixed(this, &nvhost_as_gpu::BindChannel, input, output);
37 case 0x2: 38 case 0x2:
38 return AllocateSpace(input, output); 39 return WrapFixed(this, &nvhost_as_gpu::AllocateSpace, input, output);
39 case 0x3: 40 case 0x3:
40 return FreeSpace(input, output); 41 return WrapFixed(this, &nvhost_as_gpu::FreeSpace, input, output);
41 case 0x5: 42 case 0x5:
42 return UnmapBuffer(input, output); 43 return WrapFixed(this, &nvhost_as_gpu::UnmapBuffer, input, output);
43 case 0x6: 44 case 0x6:
44 return MapBufferEx(input, output); 45 return WrapFixed(this, &nvhost_as_gpu::MapBufferEx, input, output);
45 case 0x8: 46 case 0x8:
46 return GetVARegions(input, output); 47 return WrapFixed(this, &nvhost_as_gpu::GetVARegions1, input, output);
47 case 0x9: 48 case 0x9:
48 return AllocAsEx(input, output); 49 return WrapFixed(this, &nvhost_as_gpu::AllocAsEx, input, output);
49 case 0x14: 50 case 0x14:
50 return Remap(input, output); 51 return WrapVariable(this, &nvhost_as_gpu::Remap, input, output);
51 default: 52 default:
52 break; 53 break;
53 } 54 }
@@ -72,7 +73,8 @@ 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 WrapFixedInlOut(this, &nvhost_as_gpu::GetVARegions3, input, output,
77 inline_output);
76 default: 78 default:
77 break; 79 break;
78 } 80 }
@@ -87,10 +89,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i
87void nvhost_as_gpu::OnOpen(DeviceFD fd) {} 89void nvhost_as_gpu::OnOpen(DeviceFD fd) {}
88void nvhost_as_gpu::OnClose(DeviceFD fd) {} 90void nvhost_as_gpu::OnClose(DeviceFD fd) {}
89 91
90NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::span<u8> output) { 92NvResult 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); 93 LOG_DEBUG(Service_NVDRV, "called, big_page_size=0x{:X}", params.big_page_size);
95 94
96 std::scoped_lock lock(mutex); 95 std::scoped_lock lock(mutex);
@@ -141,10 +140,7 @@ NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::span<u8> outpu
141 return NvResult::Success; 140 return NvResult::Success;
142} 141}
143 142
144NvResult nvhost_as_gpu::AllocateSpace(std::span<const u8> input, std::span<u8> output) { 143NvResult 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, 144 LOG_DEBUG(Service_NVDRV, "called, pages={:X}, page_size={:X}, flags={:X}", params.pages,
149 params.page_size, params.flags); 145 params.page_size, params.flags);
150 146
@@ -194,7 +190,6 @@ NvResult nvhost_as_gpu::AllocateSpace(std::span<const u8> input, std::span<u8> o
194 .big_pages = params.page_size != VM::YUZU_PAGESIZE, 190 .big_pages = params.page_size != VM::YUZU_PAGESIZE,
195 }; 191 };
196 192
197 std::memcpy(output.data(), &params, output.size());
198 return NvResult::Success; 193 return NvResult::Success;
199} 194}
200 195
@@ -222,10 +217,7 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) {
222 mapping_map.erase(offset); 217 mapping_map.erase(offset);
223} 218}
224 219
225NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::span<u8> output) { 220NvResult 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, 221 LOG_DEBUG(Service_NVDRV, "called, offset={:X}, pages={:X}, page_size={:X}", params.offset,
230 params.pages, params.page_size); 222 params.pages, params.page_size);
231 223
@@ -264,18 +256,11 @@ NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::span<u8> outpu
264 return NvResult::BadValue; 256 return NvResult::BadValue;
265 } 257 }
266 258
267 std::memcpy(output.data(), &params, output.size());
268 return NvResult::Success; 259 return NvResult::Success;
269} 260}
270 261
271NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::span<u8> output) { 262NvResult nvhost_as_gpu::Remap(std::span<IoctlRemapEntry> entries) {
272 const auto num_entries = input.size() / sizeof(IoctlRemapEntry); 263 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 264
280 if (!vm.initialised) { 265 if (!vm.initialised) {
281 return NvResult::BadValue; 266 return NvResult::BadValue;
@@ -317,14 +302,10 @@ NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::span<u8> output) {
317 } 302 }
318 } 303 }
319 304
320 std::memcpy(output.data(), entries.data(), output.size());
321 return NvResult::Success; 305 return NvResult::Success;
322} 306}
323 307
324NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::span<u8> output) { 308NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) {
325 IoctlMapBufferEx params{};
326 std::memcpy(&params, input.data(), input.size());
327
328 LOG_DEBUG(Service_NVDRV, 309 LOG_DEBUG(Service_NVDRV,
329 "called, flags={:X}, nvmap_handle={:X}, buffer_offset={}, mapping_size={}" 310 "called, flags={:X}, nvmap_handle={:X}, buffer_offset={}, mapping_size={}"
330 ", offset={}", 311 ", offset={}",
@@ -421,14 +402,10 @@ NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::span<u8> out
421 mapping_map[params.offset] = mapping; 402 mapping_map[params.offset] = mapping;
422 } 403 }
423 404
424 std::memcpy(output.data(), &params, output.size());
425 return NvResult::Success; 405 return NvResult::Success;
426} 406}
427 407
428NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::span<u8> output) { 408NvResult 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); 409 LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset);
433 410
434 std::scoped_lock lock(mutex); 411 std::scoped_lock lock(mutex);
@@ -464,9 +441,7 @@ NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::span<u8> out
464 return NvResult::Success; 441 return NvResult::Success;
465} 442}
466 443
467NvResult nvhost_as_gpu::BindChannel(std::span<const u8> input, std::span<u8> output) { 444NvResult 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); 445 LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
471 446
472 auto gpu_channel_device = module.GetDevice<nvhost_gpu>(params.fd); 447 auto gpu_channel_device = module.GetDevice<nvhost_gpu>(params.fd);
@@ -493,10 +468,7 @@ void nvhost_as_gpu::GetVARegionsImpl(IoctlGetVaRegions& params) {
493 }; 468 };
494} 469}
495 470
496NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> output) { 471NvResult 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, 472 LOG_DEBUG(Service_NVDRV, "called, buf_addr={:X}, buf_size={:X}", params.buf_addr,
501 params.buf_size); 473 params.buf_size);
502 474
@@ -508,15 +480,10 @@ NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> ou
508 480
509 GetVARegionsImpl(params); 481 GetVARegionsImpl(params);
510 482
511 std::memcpy(output.data(), &params, output.size());
512 return NvResult::Success; 483 return NvResult::Success;
513} 484}
514 485
515NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> output, 486NvResult nvhost_as_gpu::GetVARegions3(IoctlGetVaRegions& params, std::span<VaRegion> regions) {
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, 487 LOG_DEBUG(Service_NVDRV, "called, buf_addr={:X}, buf_size={:X}", params.buf_addr,
521 params.buf_size); 488 params.buf_size);
522 489
@@ -528,9 +495,10 @@ NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> ou
528 495
529 GetVARegionsImpl(params); 496 GetVARegionsImpl(params);
530 497
531 std::memcpy(output.data(), &params, output.size()); 498 const size_t num_regions = std::min(params.regions.size(), regions.size());
532 std::memcpy(inline_output.data(), &params.regions[0], sizeof(VaRegion)); 499 for (size_t i = 0; i < num_regions; i++) {
533 std::memcpy(inline_output.data() + sizeof(VaRegion), &params.regions[1], sizeof(VaRegion)); 500 regions[i] = params.regions[i];
501 }
534 502
535 return NvResult::Success; 503 return NvResult::Success;
536} 504}
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..932997e75 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<VaRegion> regions);
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_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index 4d55554b4..b8dd34e24 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -14,6 +14,7 @@
14#include "core/hle/kernel/k_event.h" 14#include "core/hle/kernel/k_event.h"
15#include "core/hle/service/nvdrv/core/container.h" 15#include "core/hle/service/nvdrv/core/container.h"
16#include "core/hle/service/nvdrv/core/syncpoint_manager.h" 16#include "core/hle/service/nvdrv/core/syncpoint_manager.h"
17#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
17#include "core/hle/service/nvdrv/devices/nvhost_ctrl.h" 18#include "core/hle/service/nvdrv/devices/nvhost_ctrl.h"
18#include "video_core/gpu.h" 19#include "video_core/gpu.h"
19#include "video_core/host1x/host1x.h" 20#include "video_core/host1x/host1x.h"
@@ -40,19 +41,19 @@ NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inp
40 case 0x0: 41 case 0x0:
41 switch (command.cmd) { 42 switch (command.cmd) {
42 case 0x1b: 43 case 0x1b:
43 return NvOsGetConfigU32(input, output); 44 return WrapFixed(this, &nvhost_ctrl::NvOsGetConfigU32, input, output);
44 case 0x1c: 45 case 0x1c:
45 return IocCtrlClearEventWait(input, output); 46 return WrapFixed(this, &nvhost_ctrl::IocCtrlClearEventWait, input, output);
46 case 0x1d: 47 case 0x1d:
47 return IocCtrlEventWait(input, output, true); 48 return WrapFixed(this, &nvhost_ctrl::IocCtrlEventWait, input, output, true);
48 case 0x1e: 49 case 0x1e:
49 return IocCtrlEventWait(input, output, false); 50 return WrapFixed(this, &nvhost_ctrl::IocCtrlEventWait, input, output, false);
50 case 0x1f: 51 case 0x1f:
51 return IocCtrlEventRegister(input, output); 52 return WrapFixed(this, &nvhost_ctrl::IocCtrlEventRegister, input, output);
52 case 0x20: 53 case 0x20:
53 return IocCtrlEventUnregister(input, output); 54 return WrapFixed(this, &nvhost_ctrl::IocCtrlEventUnregister, input, output);
54 case 0x21: 55 case 0x21:
55 return IocCtrlEventUnregisterBatch(input, output); 56 return WrapFixed(this, &nvhost_ctrl::IocCtrlEventUnregisterBatch, input, output);
56 } 57 }
57 break; 58 break;
58 default: 59 default:
@@ -79,25 +80,19 @@ void nvhost_ctrl::OnOpen(DeviceFD fd) {}
79 80
80void nvhost_ctrl::OnClose(DeviceFD fd) {} 81void nvhost_ctrl::OnClose(DeviceFD fd) {}
81 82
82NvResult nvhost_ctrl::NvOsGetConfigU32(std::span<const u8> input, std::span<u8> output) { 83NvResult nvhost_ctrl::NvOsGetConfigU32(IocGetConfigParams& params) {
83 IocGetConfigParams params{};
84 std::memcpy(&params, input.data(), sizeof(params));
85 LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(), 84 LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(),
86 params.param_str.data()); 85 params.param_str.data());
87 return NvResult::ConfigVarNotFound; // Returns error on production mode 86 return NvResult::ConfigVarNotFound; // Returns error on production mode
88} 87}
89 88
90NvResult nvhost_ctrl::IocCtrlEventWait(std::span<const u8> input, std::span<u8> output, 89NvResult nvhost_ctrl::IocCtrlEventWait(IocCtrlEventWaitParams& params, bool is_allocation) {
91 bool is_allocation) {
92 IocCtrlEventWaitParams params{};
93 std::memcpy(&params, input.data(), sizeof(params));
94 LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_allocation={}", 90 LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_allocation={}",
95 params.fence.id, params.fence.value, params.timeout, is_allocation); 91 params.fence.id, params.fence.value, params.timeout, is_allocation);
96 92
97 bool must_unmark_fail = !is_allocation; 93 bool must_unmark_fail = !is_allocation;
98 const u32 event_id = params.value.raw; 94 const u32 event_id = params.value.raw;
99 SCOPE_EXIT({ 95 SCOPE_EXIT({
100 std::memcpy(output.data(), &params, sizeof(params));
101 if (must_unmark_fail) { 96 if (must_unmark_fail) {
102 events[event_id].fails = 0; 97 events[event_id].fails = 0;
103 } 98 }
@@ -231,9 +226,7 @@ NvResult nvhost_ctrl::FreeEvent(u32 slot) {
231 return NvResult::Success; 226 return NvResult::Success;
232} 227}
233 228
234NvResult nvhost_ctrl::IocCtrlEventRegister(std::span<const u8> input, std::span<u8> output) { 229NvResult nvhost_ctrl::IocCtrlEventRegister(IocCtrlEventRegisterParams& params) {
235 IocCtrlEventRegisterParams params{};
236 std::memcpy(&params, input.data(), sizeof(params));
237 const u32 event_id = params.user_event_id; 230 const u32 event_id = params.user_event_id;
238 LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id); 231 LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id);
239 if (event_id >= MaxNvEvents) { 232 if (event_id >= MaxNvEvents) {
@@ -252,9 +245,7 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(std::span<const u8> input, std::span<
252 return NvResult::Success; 245 return NvResult::Success;
253} 246}
254 247
255NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span<const u8> input, std::span<u8> output) { 248NvResult nvhost_ctrl::IocCtrlEventUnregister(IocCtrlEventUnregisterParams& params) {
256 IocCtrlEventUnregisterParams params{};
257 std::memcpy(&params, input.data(), sizeof(params));
258 const u32 event_id = params.user_event_id & 0x00FF; 249 const u32 event_id = params.user_event_id & 0x00FF;
259 LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id); 250 LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id);
260 251
@@ -262,9 +253,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span<const u8> input, std::spa
262 return FreeEvent(event_id); 253 return FreeEvent(event_id);
263} 254}
264 255
265NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span<const u8> input, std::span<u8> output) { 256NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(IocCtrlEventUnregisterBatchParams& params) {
266 IocCtrlEventUnregisterBatchParams params{};
267 std::memcpy(&params, input.data(), sizeof(params));
268 u64 event_mask = params.user_events; 257 u64 event_mask = params.user_events;
269 LOG_DEBUG(Service_NVDRV, " called, event_mask: {:X}", event_mask); 258 LOG_DEBUG(Service_NVDRV, " called, event_mask: {:X}", event_mask);
270 259
@@ -280,10 +269,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span<const u8> input, std
280 return NvResult::Success; 269 return NvResult::Success;
281} 270}
282 271
283NvResult nvhost_ctrl::IocCtrlClearEventWait(std::span<const u8> input, std::span<u8> output) { 272NvResult nvhost_ctrl::IocCtrlClearEventWait(IocCtrlEventClearParams& params) {
284 IocCtrlEventClearParams params{};
285 std::memcpy(&params, input.data(), sizeof(params));
286
287 u32 event_id = params.event_id.slot; 273 u32 event_id = params.event_id.slot;
288 LOG_DEBUG(Service_NVDRV, "called, event_id: {:X}", event_id); 274 LOG_DEBUG(Service_NVDRV, "called, event_id: {:X}", event_id);
289 275
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index 2efed4862..992124b60 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -186,12 +186,12 @@ private:
186 static_assert(sizeof(IocCtrlEventUnregisterBatchParams) == 8, 186 static_assert(sizeof(IocCtrlEventUnregisterBatchParams) == 8,
187 "IocCtrlEventKill is incorrect size"); 187 "IocCtrlEventKill is incorrect size");
188 188
189 NvResult NvOsGetConfigU32(std::span<const u8> input, std::span<u8> output); 189 NvResult NvOsGetConfigU32(IocGetConfigParams& params);
190 NvResult IocCtrlEventWait(std::span<const u8> input, std::span<u8> output, bool is_allocation); 190 NvResult IocCtrlEventRegister(IocCtrlEventRegisterParams& params);
191 NvResult IocCtrlEventRegister(std::span<const u8> input, std::span<u8> output); 191 NvResult IocCtrlEventUnregister(IocCtrlEventUnregisterParams& params);
192 NvResult IocCtrlEventUnregister(std::span<const u8> input, std::span<u8> output); 192 NvResult IocCtrlEventUnregisterBatch(IocCtrlEventUnregisterBatchParams& params);
193 NvResult IocCtrlEventUnregisterBatch(std::span<const u8> input, std::span<u8> output); 193 NvResult IocCtrlEventWait(IocCtrlEventWaitParams& params, bool is_allocation);
194 NvResult IocCtrlClearEventWait(std::span<const u8> input, std::span<u8> output); 194 NvResult IocCtrlClearEventWait(IocCtrlEventClearParams& params);
195 195
196 NvResult FreeEvent(u32 slot); 196 NvResult FreeEvent(u32 slot);
197 197
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 6081d92e9..61a2df121 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -6,6 +6,7 @@
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/core_timing.h" 8#include "core/core_timing.h"
9#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
9#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" 10#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
10#include "core/hle/service/nvdrv/nvdrv.h" 11#include "core/hle/service/nvdrv/nvdrv.h"
11 12
@@ -27,23 +28,23 @@ NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8>
27 case 'G': 28 case 'G':
28 switch (command.cmd) { 29 switch (command.cmd) {
29 case 0x1: 30 case 0x1:
30 return ZCullGetCtxSize(input, output); 31 return WrapFixed(this, &nvhost_ctrl_gpu::ZCullGetCtxSize, input, output);
31 case 0x2: 32 case 0x2:
32 return ZCullGetInfo(input, output); 33 return WrapFixed(this, &nvhost_ctrl_gpu::ZCullGetInfo, input, output);
33 case 0x3: 34 case 0x3:
34 return ZBCSetTable(input, output); 35 return WrapFixed(this, &nvhost_ctrl_gpu::ZBCSetTable, input, output);
35 case 0x4: 36 case 0x4:
36 return ZBCQueryTable(input, output); 37 return WrapFixed(this, &nvhost_ctrl_gpu::ZBCQueryTable, input, output);
37 case 0x5: 38 case 0x5:
38 return GetCharacteristics(input, output); 39 return WrapFixed(this, &nvhost_ctrl_gpu::GetCharacteristics1, input, output);
39 case 0x6: 40 case 0x6:
40 return GetTPCMasks(input, output); 41 return WrapFixed(this, &nvhost_ctrl_gpu::GetTPCMasks1, input, output);
41 case 0x7: 42 case 0x7:
42 return FlushL2(input, output); 43 return WrapFixed(this, &nvhost_ctrl_gpu::FlushL2, input, output);
43 case 0x14: 44 case 0x14:
44 return GetActiveSlotMask(input, output); 45 return WrapFixed(this, &nvhost_ctrl_gpu::GetActiveSlotMask, input, output);
45 case 0x1c: 46 case 0x1c:
46 return GetGpuTime(input, output); 47 return WrapFixed(this, &nvhost_ctrl_gpu::GetGpuTime, input, output);
47 default: 48 default:
48 break; 49 break;
49 } 50 }
@@ -65,9 +66,11 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8>
65 case 'G': 66 case 'G':
66 switch (command.cmd) { 67 switch (command.cmd) {
67 case 0x5: 68 case 0x5:
68 return GetCharacteristics(input, output, inline_output); 69 return WrapFixedInlOut(this, &nvhost_ctrl_gpu::GetCharacteristics3, input, output,
70 inline_output);
69 case 0x6: 71 case 0x6:
70 return GetTPCMasks(input, output, inline_output); 72 return WrapFixedInlOut(this, &nvhost_ctrl_gpu::GetTPCMasks3, input, output,
73 inline_output);
71 default: 74 default:
72 break; 75 break;
73 } 76 }
@@ -82,10 +85,8 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8>
82void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {} 85void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {}
83void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {} 86void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {}
84 87
85NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::span<u8> output) { 88NvResult nvhost_ctrl_gpu::GetCharacteristics1(IoctlCharacteristics& params) {
86 LOG_DEBUG(Service_NVDRV, "called"); 89 LOG_DEBUG(Service_NVDRV, "called");
87 IoctlCharacteristics params{};
88 std::memcpy(&params, input.data(), input.size());
89 params.gc.arch = 0x120; 90 params.gc.arch = 0x120;
90 params.gc.impl = 0xb; 91 params.gc.impl = 0xb;
91 params.gc.rev = 0xa1; 92 params.gc.rev = 0xa1;
@@ -123,15 +124,13 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::spa
123 params.gc.gr_compbit_store_base_hw = 0x0; 124 params.gc.gr_compbit_store_base_hw = 0x0;
124 params.gpu_characteristics_buf_size = 0xA0; 125 params.gpu_characteristics_buf_size = 0xA0;
125 params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) 126 params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED)
126 std::memcpy(output.data(), &params, output.size());
127 return NvResult::Success; 127 return NvResult::Success;
128} 128}
129 129
130NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::span<u8> output, 130NvResult nvhost_ctrl_gpu::GetCharacteristics3(
131 std::span<u8> inline_output) { 131 IoctlCharacteristics& params, std::span<IoctlGpuCharacteristics> gpu_characteristics) {
132 LOG_DEBUG(Service_NVDRV, "called"); 132 LOG_DEBUG(Service_NVDRV, "called");
133 IoctlCharacteristics params{}; 133
134 std::memcpy(&params, input.data(), input.size());
135 params.gc.arch = 0x120; 134 params.gc.arch = 0x120;
136 params.gc.impl = 0xb; 135 params.gc.impl = 0xb;
137 params.gc.rev = 0xa1; 136 params.gc.rev = 0xa1;
@@ -169,70 +168,47 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::spa
169 params.gc.gr_compbit_store_base_hw = 0x0; 168 params.gc.gr_compbit_store_base_hw = 0x0;
170 params.gpu_characteristics_buf_size = 0xA0; 169 params.gpu_characteristics_buf_size = 0xA0;
171 params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) 170 params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED)
172 171 if (!gpu_characteristics.empty()) {
173 std::memcpy(output.data(), &params, output.size()); 172 gpu_characteristics.front() = params.gc;
174 std::memcpy(inline_output.data(), &params.gc, inline_output.size()); 173 }
175 return NvResult::Success; 174 return NvResult::Success;
176} 175}
177 176
178NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::span<u8> output) { 177NvResult nvhost_ctrl_gpu::GetTPCMasks1(IoctlGpuGetTpcMasksArgs& params) {
179 IoctlGpuGetTpcMasksArgs params{};
180 std::memcpy(&params, input.data(), input.size());
181 LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); 178 LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
182 if (params.mask_buffer_size != 0) { 179 if (params.mask_buffer_size != 0) {
183 params.tcp_mask = 3; 180 params.tcp_mask = 3;
184 } 181 }
185 std::memcpy(output.data(), &params, output.size());
186 return NvResult::Success; 182 return NvResult::Success;
187} 183}
188 184
189NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::span<u8> output, 185NvResult nvhost_ctrl_gpu::GetTPCMasks3(IoctlGpuGetTpcMasksArgs& params, std::span<u32> tpc_mask) {
190 std::span<u8> inline_output) {
191 IoctlGpuGetTpcMasksArgs params{};
192 std::memcpy(&params, input.data(), input.size());
193 LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); 186 LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
194 if (params.mask_buffer_size != 0) { 187 if (params.mask_buffer_size != 0) {
195 params.tcp_mask = 3; 188 params.tcp_mask = 3;
196 } 189 }
197 std::memcpy(output.data(), &params, output.size()); 190 if (!tpc_mask.empty()) {
198 std::memcpy(inline_output.data(), &params.tcp_mask, inline_output.size()); 191 tpc_mask.front() = params.tcp_mask;
192 }
199 return NvResult::Success; 193 return NvResult::Success;
200} 194}
201 195
202NvResult nvhost_ctrl_gpu::GetActiveSlotMask(std::span<const u8> input, std::span<u8> output) { 196NvResult nvhost_ctrl_gpu::GetActiveSlotMask(IoctlActiveSlotMask& params) {
203 LOG_DEBUG(Service_NVDRV, "called"); 197 LOG_DEBUG(Service_NVDRV, "called");
204 198
205 IoctlActiveSlotMask params{};
206 if (input.size() > 0) {
207 std::memcpy(&params, input.data(), input.size());
208 }
209 params.slot = 0x07; 199 params.slot = 0x07;
210 params.mask = 0x01; 200 params.mask = 0x01;
211 std::memcpy(output.data(), &params, output.size());
212 return NvResult::Success; 201 return NvResult::Success;
213} 202}
214 203
215NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(std::span<const u8> input, std::span<u8> output) { 204NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(IoctlZcullGetCtxSize& params) {
216 LOG_DEBUG(Service_NVDRV, "called"); 205 LOG_DEBUG(Service_NVDRV, "called");
217
218 IoctlZcullGetCtxSize params{};
219 if (input.size() > 0) {
220 std::memcpy(&params, input.data(), input.size());
221 }
222 params.size = 0x1; 206 params.size = 0x1;
223 std::memcpy(output.data(), &params, output.size());
224 return NvResult::Success; 207 return NvResult::Success;
225} 208}
226 209
227NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span<const u8> input, std::span<u8> output) { 210NvResult nvhost_ctrl_gpu::ZCullGetInfo(IoctlNvgpuGpuZcullGetInfoArgs& params) {
228 LOG_DEBUG(Service_NVDRV, "called"); 211 LOG_DEBUG(Service_NVDRV, "called");
229
230 IoctlNvgpuGpuZcullGetInfoArgs params{};
231
232 if (input.size() > 0) {
233 std::memcpy(&params, input.data(), input.size());
234 }
235
236 params.width_align_pixels = 0x20; 212 params.width_align_pixels = 0x20;
237 params.height_align_pixels = 0x20; 213 params.height_align_pixels = 0x20;
238 params.pixel_squares_by_aliquots = 0x400; 214 params.pixel_squares_by_aliquots = 0x400;
@@ -243,53 +219,28 @@ NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span<const u8> input, std::span<u8>
243 params.subregion_width_align_pixels = 0x20; 219 params.subregion_width_align_pixels = 0x20;
244 params.subregion_height_align_pixels = 0x40; 220 params.subregion_height_align_pixels = 0x40;
245 params.subregion_count = 0x10; 221 params.subregion_count = 0x10;
246 std::memcpy(output.data(), &params, output.size());
247 return NvResult::Success; 222 return NvResult::Success;
248} 223}
249 224
250NvResult nvhost_ctrl_gpu::ZBCSetTable(std::span<const u8> input, std::span<u8> output) { 225NvResult nvhost_ctrl_gpu::ZBCSetTable(IoctlZbcSetTable& params) {
251 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 226 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
252
253 IoctlZbcSetTable params{};
254 std::memcpy(&params, input.data(), input.size());
255 // TODO(ogniK): What does this even actually do? 227 // TODO(ogniK): What does this even actually do?
256
257 // Prevent null pointer being passed as arg 1
258 if (output.empty()) {
259 LOG_WARNING(Service_NVDRV, "Avoiding passing null pointer to memcpy");
260 } else {
261 std::memcpy(output.data(), &params, output.size());
262 }
263 return NvResult::Success; 228 return NvResult::Success;
264} 229}
265 230
266NvResult nvhost_ctrl_gpu::ZBCQueryTable(std::span<const u8> input, std::span<u8> output) { 231NvResult nvhost_ctrl_gpu::ZBCQueryTable(IoctlZbcQueryTable& params) {
267 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 232 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
268
269 IoctlZbcQueryTable params{};
270 std::memcpy(&params, input.data(), input.size());
271 // TODO : To implement properly
272 std::memcpy(output.data(), &params, output.size());
273 return NvResult::Success; 233 return NvResult::Success;
274} 234}
275 235
276NvResult nvhost_ctrl_gpu::FlushL2(std::span<const u8> input, std::span<u8> output) { 236NvResult nvhost_ctrl_gpu::FlushL2(IoctlFlushL2& params) {
277 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 237 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
278
279 IoctlFlushL2 params{};
280 std::memcpy(&params, input.data(), input.size());
281 // TODO : To implement properly
282 std::memcpy(output.data(), &params, output.size());
283 return NvResult::Success; 238 return NvResult::Success;
284} 239}
285 240
286NvResult nvhost_ctrl_gpu::GetGpuTime(std::span<const u8> input, std::span<u8> output) { 241NvResult nvhost_ctrl_gpu::GetGpuTime(IoctlGetGpuTime& params) {
287 LOG_DEBUG(Service_NVDRV, "called"); 242 LOG_DEBUG(Service_NVDRV, "called");
288
289 IoctlGetGpuTime params{};
290 std::memcpy(&params, input.data(), input.size());
291 params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count()); 243 params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count());
292 std::memcpy(output.data(), &params, output.size());
293 return NvResult::Success; 244 return NvResult::Success;
294} 245}
295 246
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 97995551c..d170299bd 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
@@ -151,21 +151,20 @@ private:
151 }; 151 };
152 static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); 152 static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size");
153 153
154 NvResult GetCharacteristics(std::span<const u8> input, std::span<u8> output); 154 NvResult GetCharacteristics1(IoctlCharacteristics& params);
155 NvResult GetCharacteristics(std::span<const u8> input, std::span<u8> output, 155 NvResult GetCharacteristics3(IoctlCharacteristics& params,
156 std::span<u8> inline_output); 156 std::span<IoctlGpuCharacteristics> gpu_characteristics);
157 157
158 NvResult GetTPCMasks(std::span<const u8> input, std::span<u8> output); 158 NvResult GetTPCMasks1(IoctlGpuGetTpcMasksArgs& params);
159 NvResult GetTPCMasks(std::span<const u8> input, std::span<u8> output, 159 NvResult GetTPCMasks3(IoctlGpuGetTpcMasksArgs& params, std::span<u32> tpc_mask);
160 std::span<u8> inline_output); 160
161 161 NvResult GetActiveSlotMask(IoctlActiveSlotMask& params);
162 NvResult GetActiveSlotMask(std::span<const u8> input, std::span<u8> output); 162 NvResult ZCullGetCtxSize(IoctlZcullGetCtxSize& params);
163 NvResult ZCullGetCtxSize(std::span<const u8> input, std::span<u8> output); 163 NvResult ZCullGetInfo(IoctlNvgpuGpuZcullGetInfoArgs& params);
164 NvResult ZCullGetInfo(std::span<const u8> input, std::span<u8> output); 164 NvResult ZBCSetTable(IoctlZbcSetTable& params);
165 NvResult ZBCSetTable(std::span<const u8> input, std::span<u8> output); 165 NvResult ZBCQueryTable(IoctlZbcQueryTable& params);
166 NvResult ZBCQueryTable(std::span<const u8> input, std::span<u8> output); 166 NvResult FlushL2(IoctlFlushL2& params);
167 NvResult FlushL2(std::span<const u8> input, std::span<u8> output); 167 NvResult GetGpuTime(IoctlGetGpuTime& params);
168 NvResult GetGpuTime(std::span<const u8> input, std::span<u8> output);
169 168
170 EventInterface& events_interface; 169 EventInterface& events_interface;
171 170
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 46a25fcab..b0395c2f0 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -8,6 +8,7 @@
8#include "core/hle/service/nvdrv/core/container.h" 8#include "core/hle/service/nvdrv/core/container.h"
9#include "core/hle/service/nvdrv/core/nvmap.h" 9#include "core/hle/service/nvdrv/core/nvmap.h"
10#include "core/hle/service/nvdrv/core/syncpoint_manager.h" 10#include "core/hle/service/nvdrv/core/syncpoint_manager.h"
11#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
11#include "core/hle/service/nvdrv/devices/nvhost_gpu.h" 12#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
12#include "core/hle/service/nvdrv/nvdrv.h" 13#include "core/hle/service/nvdrv/nvdrv.h"
13#include "core/memory.h" 14#include "core/memory.h"
@@ -52,7 +53,7 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
52 case 0x0: 53 case 0x0:
53 switch (command.cmd) { 54 switch (command.cmd) {
54 case 0x3: 55 case 0x3:
55 return GetWaitbase(input, output); 56 return WrapFixed(this, &nvhost_gpu::GetWaitbase, input, output);
56 default: 57 default:
57 break; 58 break;
58 } 59 }
@@ -60,25 +61,25 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
60 case 'H': 61 case 'H':
61 switch (command.cmd) { 62 switch (command.cmd) {
62 case 0x1: 63 case 0x1:
63 return SetNVMAPfd(input, output); 64 return WrapFixed(this, &nvhost_gpu::SetNVMAPfd, input, output);
64 case 0x3: 65 case 0x3:
65 return ChannelSetTimeout(input, output); 66 return WrapFixed(this, &nvhost_gpu::ChannelSetTimeout, input, output);
66 case 0x8: 67 case 0x8:
67 return SubmitGPFIFOBase(input, output, false); 68 return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, false);
68 case 0x9: 69 case 0x9:
69 return AllocateObjectContext(input, output); 70 return WrapFixed(this, &nvhost_gpu::AllocateObjectContext, input, output);
70 case 0xb: 71 case 0xb:
71 return ZCullBind(input, output); 72 return WrapFixed(this, &nvhost_gpu::ZCullBind, input, output);
72 case 0xc: 73 case 0xc:
73 return SetErrorNotifier(input, output); 74 return WrapFixed(this, &nvhost_gpu::SetErrorNotifier, input, output);
74 case 0xd: 75 case 0xd:
75 return SetChannelPriority(input, output); 76 return WrapFixed(this, &nvhost_gpu::SetChannelPriority, input, output);
76 case 0x1a: 77 case 0x1a:
77 return AllocGPFIFOEx2(input, output); 78 return WrapFixed(this, &nvhost_gpu::AllocGPFIFOEx2, input, output);
78 case 0x1b: 79 case 0x1b:
79 return SubmitGPFIFOBase(input, output, true); 80 return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, true);
80 case 0x1d: 81 case 0x1d:
81 return ChannelSetTimeslice(input, output); 82 return WrapFixed(this, &nvhost_gpu::ChannelSetTimeslice, input, output);
82 default: 83 default:
83 break; 84 break;
84 } 85 }
@@ -86,9 +87,9 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
86 case 'G': 87 case 'G':
87 switch (command.cmd) { 88 switch (command.cmd) {
88 case 0x14: 89 case 0x14:
89 return SetClientData(input, output); 90 return WrapFixed(this, &nvhost_gpu::SetClientData, input, output);
90 case 0x15: 91 case 0x15:
91 return GetClientData(input, output); 92 return WrapFixed(this, &nvhost_gpu::GetClientData, input, output);
92 default: 93 default:
93 break; 94 break;
94 } 95 }
@@ -104,7 +105,8 @@ NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> inpu
104 case 'H': 105 case 'H':
105 switch (command.cmd) { 106 switch (command.cmd) {
106 case 0x1b: 107 case 0x1b:
107 return SubmitGPFIFOBase(input, inline_input, output); 108 return WrapFixedInlIn(this, &nvhost_gpu::SubmitGPFIFOBase2, input, inline_input,
109 output);
108 } 110 }
109 break; 111 break;
110 } 112 }
@@ -121,63 +123,45 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu
121void nvhost_gpu::OnOpen(DeviceFD fd) {} 123void nvhost_gpu::OnOpen(DeviceFD fd) {}
122void nvhost_gpu::OnClose(DeviceFD fd) {} 124void nvhost_gpu::OnClose(DeviceFD fd) {}
123 125
124NvResult nvhost_gpu::SetNVMAPfd(std::span<const u8> input, std::span<u8> output) { 126NvResult nvhost_gpu::SetNVMAPfd(IoctlSetNvmapFD& params) {
125 IoctlSetNvmapFD params{};
126 std::memcpy(&params, input.data(), input.size());
127 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 127 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
128 128
129 nvmap_fd = params.nvmap_fd; 129 nvmap_fd = params.nvmap_fd;
130 return NvResult::Success; 130 return NvResult::Success;
131} 131}
132 132
133NvResult nvhost_gpu::SetClientData(std::span<const u8> input, std::span<u8> output) { 133NvResult nvhost_gpu::SetClientData(IoctlClientData& params) {
134 LOG_DEBUG(Service_NVDRV, "called"); 134 LOG_DEBUG(Service_NVDRV, "called");
135
136 IoctlClientData params{};
137 std::memcpy(&params, input.data(), input.size());
138 user_data = params.data; 135 user_data = params.data;
139 return NvResult::Success; 136 return NvResult::Success;
140} 137}
141 138
142NvResult nvhost_gpu::GetClientData(std::span<const u8> input, std::span<u8> output) { 139NvResult nvhost_gpu::GetClientData(IoctlClientData& params) {
143 LOG_DEBUG(Service_NVDRV, "called"); 140 LOG_DEBUG(Service_NVDRV, "called");
144
145 IoctlClientData params{};
146 std::memcpy(&params, input.data(), input.size());
147 params.data = user_data; 141 params.data = user_data;
148 std::memcpy(output.data(), &params, output.size());
149 return NvResult::Success; 142 return NvResult::Success;
150} 143}
151 144
152NvResult nvhost_gpu::ZCullBind(std::span<const u8> input, std::span<u8> output) { 145NvResult nvhost_gpu::ZCullBind(IoctlZCullBind& params) {
153 std::memcpy(&zcull_params, input.data(), input.size()); 146 zcull_params = params;
154 LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, 147 LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,
155 zcull_params.mode); 148 zcull_params.mode);
156
157 std::memcpy(output.data(), &zcull_params, output.size());
158 return NvResult::Success; 149 return NvResult::Success;
159} 150}
160 151
161NvResult nvhost_gpu::SetErrorNotifier(std::span<const u8> input, std::span<u8> output) { 152NvResult nvhost_gpu::SetErrorNotifier(IoctlSetErrorNotifier& params) {
162 IoctlSetErrorNotifier params{};
163 std::memcpy(&params, input.data(), input.size());
164 LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, 153 LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,
165 params.size, params.mem); 154 params.size, params.mem);
166
167 std::memcpy(output.data(), &params, output.size());
168 return NvResult::Success; 155 return NvResult::Success;
169} 156}
170 157
171NvResult nvhost_gpu::SetChannelPriority(std::span<const u8> input, std::span<u8> output) { 158NvResult nvhost_gpu::SetChannelPriority(IoctlChannelSetPriority& params) {
172 std::memcpy(&channel_priority, input.data(), input.size()); 159 channel_priority = params.priority;
173 LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); 160 LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
174
175 return NvResult::Success; 161 return NvResult::Success;
176} 162}
177 163
178NvResult nvhost_gpu::AllocGPFIFOEx2(std::span<const u8> input, std::span<u8> output) { 164NvResult nvhost_gpu::AllocGPFIFOEx2(IoctlAllocGpfifoEx2& params) {
179 IoctlAllocGpfifoEx2 params{};
180 std::memcpy(&params, input.data(), input.size());
181 LOG_WARNING(Service_NVDRV, 165 LOG_WARNING(Service_NVDRV,
182 "(STUBBED) called, num_entries={:X}, flags={:X}, unk0={:X}, " 166 "(STUBBED) called, num_entries={:X}, flags={:X}, unk0={:X}, "
183 "unk1={:X}, unk2={:X}, unk3={:X}", 167 "unk1={:X}, unk2={:X}, unk3={:X}",
@@ -193,18 +177,14 @@ NvResult nvhost_gpu::AllocGPFIFOEx2(std::span<const u8> input, std::span<u8> out
193 177
194 params.fence_out = syncpoint_manager.GetSyncpointFence(channel_syncpoint); 178 params.fence_out = syncpoint_manager.GetSyncpointFence(channel_syncpoint);
195 179
196 std::memcpy(output.data(), &params, output.size());
197 return NvResult::Success; 180 return NvResult::Success;
198} 181}
199 182
200NvResult nvhost_gpu::AllocateObjectContext(std::span<const u8> input, std::span<u8> output) { 183NvResult nvhost_gpu::AllocateObjectContext(IoctlAllocObjCtx& params) {
201 IoctlAllocObjCtx params{};
202 std::memcpy(&params, input.data(), input.size());
203 LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, 184 LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num,
204 params.flags); 185 params.flags);
205 186
206 params.obj_id = 0x0; 187 params.obj_id = 0x0;
207 std::memcpy(output.data(), &params, output.size());
208 return NvResult::Success; 188 return NvResult::Success;
209} 189}
210 190
@@ -248,8 +228,7 @@ static boost::container::small_vector<Tegra::CommandHeader, 512> BuildIncrementW
248 return result; 228 return result;
249} 229}
250 230
251NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span<u8> output, 231NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandList&& entries) {
252 Tegra::CommandList&& entries) {
253 LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, 232 LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,
254 params.num_entries, params.flags.raw); 233 params.num_entries, params.flags.raw);
255 234
@@ -290,65 +269,55 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span<u8> o
290 269
291 flags.raw = 0; 270 flags.raw = 0;
292 271
293 std::memcpy(output.data(), &params, sizeof(IoctlSubmitGpfifo));
294 return NvResult::Success; 272 return NvResult::Success;
295} 273}
296 274
297NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<u8> output, 275NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
298 bool kickoff) { 276 std::span<Tegra::CommandListHeader> commands, bool kickoff) {
299 if (input.size() < sizeof(IoctlSubmitGpfifo)) { 277 if (params.num_entries > commands.size()) {
300 UNIMPLEMENTED(); 278 UNIMPLEMENTED();
301 return NvResult::InvalidSize; 279 return NvResult::InvalidSize;
302 } 280 }
303 IoctlSubmitGpfifo params{};
304 std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
305 Tegra::CommandList entries(params.num_entries);
306 281
282 Tegra::CommandList entries(params.num_entries);
307 if (kickoff) { 283 if (kickoff) {
308 system.ApplicationMemory().ReadBlock(params.address, entries.command_lists.data(), 284 system.ApplicationMemory().ReadBlock(params.address, entries.command_lists.data(),
309 params.num_entries * sizeof(Tegra::CommandListHeader)); 285 params.num_entries * sizeof(Tegra::CommandListHeader));
310 } else { 286 } else {
311 std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)], 287 std::memcpy(entries.command_lists.data(), commands.data(),
312 params.num_entries * sizeof(Tegra::CommandListHeader)); 288 params.num_entries * sizeof(Tegra::CommandListHeader));
313 } 289 }
314 290
315 return SubmitGPFIFOImpl(params, output, std::move(entries)); 291 return SubmitGPFIFOImpl(params, std::move(entries));
316} 292}
317 293
318NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline, 294NvResult nvhost_gpu::SubmitGPFIFOBase2(IoctlSubmitGpfifo& params,
319 std::span<u8> output) { 295 std::span<const Tegra::CommandListHeader> commands) {
320 if (input.size() < sizeof(IoctlSubmitGpfifo)) { 296 if (params.num_entries > commands.size()) {
321 UNIMPLEMENTED(); 297 UNIMPLEMENTED();
322 return NvResult::InvalidSize; 298 return NvResult::InvalidSize;
323 } 299 }
324 IoctlSubmitGpfifo params{}; 300
325 std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
326 Tegra::CommandList entries(params.num_entries); 301 Tegra::CommandList entries(params.num_entries);
327 std::memcpy(entries.command_lists.data(), input_inline.data(), input_inline.size()); 302 std::memcpy(entries.command_lists.data(), commands.data(),
328 return SubmitGPFIFOImpl(params, output, std::move(entries)); 303 params.num_entries * sizeof(Tegra::CommandListHeader));
304 return SubmitGPFIFOImpl(params, std::move(entries));
329} 305}
330 306
331NvResult nvhost_gpu::GetWaitbase(std::span<const u8> input, std::span<u8> output) { 307NvResult nvhost_gpu::GetWaitbase(IoctlGetWaitbase& params) {
332 IoctlGetWaitbase params{};
333 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
334 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); 308 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
335 309
336 params.value = 0; // Seems to be hard coded at 0 310 params.value = 0; // Seems to be hard coded at 0
337 std::memcpy(output.data(), &params, output.size());
338 return NvResult::Success; 311 return NvResult::Success;
339} 312}
340 313
341NvResult nvhost_gpu::ChannelSetTimeout(std::span<const u8> input, std::span<u8> output) { 314NvResult nvhost_gpu::ChannelSetTimeout(IoctlChannelSetTimeout& params) {
342 IoctlChannelSetTimeout params{};
343 std::memcpy(&params, input.data(), sizeof(IoctlChannelSetTimeout));
344 LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); 315 LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout);
345 316
346 return NvResult::Success; 317 return NvResult::Success;
347} 318}
348 319
349NvResult nvhost_gpu::ChannelSetTimeslice(std::span<const u8> input, std::span<u8> output) { 320NvResult nvhost_gpu::ChannelSetTimeslice(IoctlSetTimeslice& params) {
350 IoctlSetTimeslice params{};
351 std::memcpy(&params, input.data(), sizeof(IoctlSetTimeslice));
352 LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); 321 LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice);
353 322
354 channel_timeslice = params.timeslice; 323 channel_timeslice = params.timeslice;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index 529c20526..88fd228ff 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -186,23 +186,24 @@ private:
186 u32_le channel_priority{}; 186 u32_le channel_priority{};
187 u32_le channel_timeslice{}; 187 u32_le channel_timeslice{};
188 188
189 NvResult SetNVMAPfd(std::span<const u8> input, std::span<u8> output); 189 NvResult SetNVMAPfd(IoctlSetNvmapFD& params);
190 NvResult SetClientData(std::span<const u8> input, std::span<u8> output); 190 NvResult SetClientData(IoctlClientData& params);
191 NvResult GetClientData(std::span<const u8> input, std::span<u8> output); 191 NvResult GetClientData(IoctlClientData& params);
192 NvResult ZCullBind(std::span<const u8> input, std::span<u8> output); 192 NvResult ZCullBind(IoctlZCullBind& params);
193 NvResult SetErrorNotifier(std::span<const u8> input, std::span<u8> output); 193 NvResult SetErrorNotifier(IoctlSetErrorNotifier& params);
194 NvResult SetChannelPriority(std::span<const u8> input, std::span<u8> output); 194 NvResult SetChannelPriority(IoctlChannelSetPriority& params);
195 NvResult AllocGPFIFOEx2(std::span<const u8> input, std::span<u8> output); 195 NvResult AllocGPFIFOEx2(IoctlAllocGpfifoEx2& params);
196 NvResult AllocateObjectContext(std::span<const u8> input, std::span<u8> output); 196 NvResult AllocateObjectContext(IoctlAllocObjCtx& params);
197 NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span<u8> output, 197
198 Tegra::CommandList&& entries); 198 NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandList&& entries);
199 NvResult SubmitGPFIFOBase(std::span<const u8> input, std::span<u8> output, 199 NvResult SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
200 bool kickoff = false); 200 std::span<Tegra::CommandListHeader> commands, bool kickoff = false);
201 NvResult SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline, 201 NvResult SubmitGPFIFOBase2(IoctlSubmitGpfifo& params,
202 std::span<u8> output); 202 std::span<const Tegra::CommandListHeader> commands);
203 NvResult GetWaitbase(std::span<const u8> input, std::span<u8> output); 203
204 NvResult ChannelSetTimeout(std::span<const u8> input, std::span<u8> output); 204 NvResult GetWaitbase(IoctlGetWaitbase& params);
205 NvResult ChannelSetTimeslice(std::span<const u8> input, std::span<u8> output); 205 NvResult ChannelSetTimeout(IoctlChannelSetTimeout& params);
206 NvResult ChannelSetTimeslice(IoctlSetTimeslice& params);
206 207
207 EventInterface& events_interface; 208 EventInterface& events_interface;
208 NvCore::Container& core; 209 NvCore::Container& core;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index a174442a6..f43914e1b 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -6,6 +6,7 @@
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hle/service/nvdrv/core/container.h" 8#include "core/hle/service/nvdrv/core/container.h"
9#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
9#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" 10#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
10#include "video_core/renderer_base.h" 11#include "video_core/renderer_base.h"
11 12
@@ -25,18 +26,18 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
25 if (!host1x_file.fd_to_id.contains(fd)) { 26 if (!host1x_file.fd_to_id.contains(fd)) {
26 host1x_file.fd_to_id[fd] = host1x_file.nvdec_next_id++; 27 host1x_file.fd_to_id[fd] = host1x_file.nvdec_next_id++;
27 } 28 }
28 return Submit(fd, input, output); 29 return WrapFixedVariable(this, &nvhost_nvdec::Submit, input, output, fd);
29 } 30 }
30 case 0x2: 31 case 0x2:
31 return GetSyncpoint(input, output); 32 return WrapFixed(this, &nvhost_nvdec::GetSyncpoint, input, output);
32 case 0x3: 33 case 0x3:
33 return GetWaitbase(input, output); 34 return WrapFixed(this, &nvhost_nvdec::GetWaitbase, input, output);
34 case 0x7: 35 case 0x7:
35 return SetSubmitTimeout(input, output); 36 return WrapFixed(this, &nvhost_nvdec::SetSubmitTimeout, input, output);
36 case 0x9: 37 case 0x9:
37 return MapBuffer(input, output); 38 return WrapFixedVariable(this, &nvhost_nvdec::MapBuffer, input, output);
38 case 0xa: 39 case 0xa:
39 return UnmapBuffer(input, output); 40 return WrapFixedVariable(this, &nvhost_nvdec::UnmapBuffer, input, output);
40 default: 41 default:
41 break; 42 break;
42 } 43 }
@@ -44,7 +45,7 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
44 case 'H': 45 case 'H':
45 switch (command.cmd) { 46 switch (command.cmd) {
46 case 0x1: 47 case 0x1:
47 return SetNVMAPfd(input); 48 return WrapFixed(this, &nvhost_nvdec::SetNVMAPfd, input, output);
48 default: 49 default:
49 break; 50 break;
50 } 51 }
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 61649aa4a..74c701b95 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -29,6 +29,9 @@ std::size_t SliceVectors(std::span<const u8> input, std::vector<T>& dst, std::si
29 return 0; 29 return 0;
30 } 30 }
31 const size_t bytes_copied = count * sizeof(T); 31 const size_t bytes_copied = count * sizeof(T);
32 if (input.size() < offset + bytes_copied) {
33 return 0;
34 }
32 std::memcpy(dst.data(), input.data() + offset, bytes_copied); 35 std::memcpy(dst.data(), input.data() + offset, bytes_copied);
33 return bytes_copied; 36 return bytes_copied;
34} 37}
@@ -41,6 +44,9 @@ std::size_t WriteVectors(std::span<u8> dst, const std::vector<T>& src, std::size
41 return 0; 44 return 0;
42 } 45 }
43 const size_t bytes_copied = src.size() * sizeof(T); 46 const size_t bytes_copied = src.size() * sizeof(T);
47 if (dst.size() < offset + bytes_copied) {
48 return 0;
49 }
44 std::memcpy(dst.data() + offset, src.data(), bytes_copied); 50 std::memcpy(dst.data() + offset, src.data(), bytes_copied);
45 return bytes_copied; 51 return bytes_copied;
46} 52}
@@ -63,18 +69,14 @@ nvhost_nvdec_common::~nvhost_nvdec_common() {
63 core.Host1xDeviceFile().syncpts_accumulated.push_back(channel_syncpoint); 69 core.Host1xDeviceFile().syncpts_accumulated.push_back(channel_syncpoint);
64} 70}
65 71
66NvResult nvhost_nvdec_common::SetNVMAPfd(std::span<const u8> input) { 72NvResult nvhost_nvdec_common::SetNVMAPfd(IoctlSetNvmapFD& params) {
67 IoctlSetNvmapFD params{};
68 std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD));
69 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 73 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
70 74
71 nvmap_fd = params.nvmap_fd; 75 nvmap_fd = params.nvmap_fd;
72 return NvResult::Success; 76 return NvResult::Success;
73} 77}
74 78
75NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, std::span<u8> output) { 79NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span<u8> data, DeviceFD fd) {
76 IoctlSubmit params{};
77 std::memcpy(&params, input.data(), sizeof(IoctlSubmit));
78 LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count); 80 LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count);
79 81
80 // Instantiate param buffers 82 // Instantiate param buffers
@@ -85,12 +87,12 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, std
85 std::vector<u32> fence_thresholds(params.fence_count); 87 std::vector<u32> fence_thresholds(params.fence_count);
86 88
87 // Slice input into their respective buffers 89 // Slice input into their respective buffers
88 std::size_t offset = sizeof(IoctlSubmit); 90 std::size_t offset = 0;
89 offset += SliceVectors(input, command_buffers, params.cmd_buffer_count, offset); 91 offset += SliceVectors(data, command_buffers, params.cmd_buffer_count, offset);
90 offset += SliceVectors(input, relocs, params.relocation_count, offset); 92 offset += SliceVectors(data, relocs, params.relocation_count, offset);
91 offset += SliceVectors(input, reloc_shifts, params.relocation_count, offset); 93 offset += SliceVectors(data, reloc_shifts, params.relocation_count, offset);
92 offset += SliceVectors(input, syncpt_increments, params.syncpoint_count, offset); 94 offset += SliceVectors(data, syncpt_increments, params.syncpoint_count, offset);
93 offset += SliceVectors(input, fence_thresholds, params.fence_count, offset); 95 offset += SliceVectors(data, fence_thresholds, params.fence_count, offset);
94 96
95 auto& gpu = system.GPU(); 97 auto& gpu = system.GPU();
96 if (gpu.UseNvdec()) { 98 if (gpu.UseNvdec()) {
@@ -108,72 +110,51 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, std
108 cmdlist.size() * sizeof(u32)); 110 cmdlist.size() * sizeof(u32));
109 gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist); 111 gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist);
110 } 112 }
111 std::memcpy(output.data(), &params, sizeof(IoctlSubmit));
112 // Some games expect command_buffers to be written back 113 // Some games expect command_buffers to be written back
113 offset = sizeof(IoctlSubmit); 114 offset = 0;
114 offset += WriteVectors(output, command_buffers, offset); 115 offset += WriteVectors(data, command_buffers, offset);
115 offset += WriteVectors(output, relocs, offset); 116 offset += WriteVectors(data, relocs, offset);
116 offset += WriteVectors(output, reloc_shifts, offset); 117 offset += WriteVectors(data, reloc_shifts, offset);
117 offset += WriteVectors(output, syncpt_increments, offset); 118 offset += WriteVectors(data, syncpt_increments, offset);
118 offset += WriteVectors(output, fence_thresholds, offset); 119 offset += WriteVectors(data, fence_thresholds, offset);
119 120
120 return NvResult::Success; 121 return NvResult::Success;
121} 122}
122 123
123NvResult nvhost_nvdec_common::GetSyncpoint(std::span<const u8> input, std::span<u8> output) { 124NvResult nvhost_nvdec_common::GetSyncpoint(IoctlGetSyncpoint& params) {
124 IoctlGetSyncpoint params{};
125 std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint));
126 LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param); 125 LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param);
127
128 // const u32 id{NvCore::SyncpointManager::channel_syncpoints[static_cast<u32>(channel_type)]};
129 params.value = channel_syncpoint; 126 params.value = channel_syncpoint;
130 std::memcpy(output.data(), &params, sizeof(IoctlGetSyncpoint));
131
132 return NvResult::Success; 127 return NvResult::Success;
133} 128}
134 129
135NvResult nvhost_nvdec_common::GetWaitbase(std::span<const u8> input, std::span<u8> output) { 130NvResult nvhost_nvdec_common::GetWaitbase(IoctlGetWaitbase& params) {
136 IoctlGetWaitbase params{};
137 LOG_CRITICAL(Service_NVDRV, "called WAITBASE"); 131 LOG_CRITICAL(Service_NVDRV, "called WAITBASE");
138 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
139 params.value = 0; // Seems to be hard coded at 0 132 params.value = 0; // Seems to be hard coded at 0
140 std::memcpy(output.data(), &params, sizeof(IoctlGetWaitbase));
141 return NvResult::Success; 133 return NvResult::Success;
142} 134}
143 135
144NvResult nvhost_nvdec_common::MapBuffer(std::span<const u8> input, std::span<u8> output) { 136NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries) {
145 IoctlMapBuffer params{}; 137 const size_t num_entries = std::min(params.num_entries, static_cast<u32>(entries.size()));
146 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer)); 138 for (size_t i = 0; i < num_entries; i++) {
147 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); 139 entries[i].map_address = nvmap.PinHandle(entries[i].map_handle);
148
149 SliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
150
151 for (auto& cmd_buffer : cmd_buffer_handles) {
152 cmd_buffer.map_address = nvmap.PinHandle(cmd_buffer.map_handle);
153 } 140 }
154 std::memcpy(output.data(), &params, sizeof(IoctlMapBuffer));
155 std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(),
156 cmd_buffer_handles.size() * sizeof(MapBufferEntry));
157 141
158 return NvResult::Success; 142 return NvResult::Success;
159} 143}
160 144
161NvResult nvhost_nvdec_common::UnmapBuffer(std::span<const u8> input, std::span<u8> output) { 145NvResult nvhost_nvdec_common::UnmapBuffer(IoctlMapBuffer& params,
162 IoctlMapBuffer params{}; 146 std::span<MapBufferEntry> entries) {
163 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer)); 147 const size_t num_entries = std::min(params.num_entries, static_cast<u32>(entries.size()));
164 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); 148 for (size_t i = 0; i < num_entries; i++) {
165 149 nvmap.UnpinHandle(entries[i].map_handle);
166 SliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer)); 150 entries[i] = {};
167 for (auto& cmd_buffer : cmd_buffer_handles) {
168 nvmap.UnpinHandle(cmd_buffer.map_handle);
169 } 151 }
170 152
171 std::memset(output.data(), 0, output.size()); 153 params = {};
172 return NvResult::Success; 154 return NvResult::Success;
173} 155}
174 156
175NvResult nvhost_nvdec_common::SetSubmitTimeout(std::span<const u8> input, std::span<u8> output) { 157NvResult nvhost_nvdec_common::SetSubmitTimeout(u32 timeout) {
176 std::memcpy(&submit_timeout, input.data(), input.size());
177 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 158 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
178 return NvResult::Success; 159 return NvResult::Success;
179} 160}
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 9bb573bfe..7ce748e18 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
@@ -107,13 +107,13 @@ protected:
107 static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size"); 107 static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
108 108
109 /// Ioctl command implementations 109 /// Ioctl command implementations
110 NvResult SetNVMAPfd(std::span<const u8> input); 110 NvResult SetNVMAPfd(IoctlSetNvmapFD&);
111 NvResult Submit(DeviceFD fd, std::span<const u8> input, std::span<u8> output); 111 NvResult Submit(IoctlSubmit& params, std::span<u8> input, DeviceFD fd);
112 NvResult GetSyncpoint(std::span<const u8> input, std::span<u8> output); 112 NvResult GetSyncpoint(IoctlGetSyncpoint& params);
113 NvResult GetWaitbase(std::span<const u8> input, std::span<u8> output); 113 NvResult GetWaitbase(IoctlGetWaitbase& params);
114 NvResult MapBuffer(std::span<const u8> input, std::span<u8> output); 114 NvResult MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries);
115 NvResult UnmapBuffer(std::span<const u8> input, std::span<u8> output); 115 NvResult UnmapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries);
116 NvResult SetSubmitTimeout(std::span<const u8> input, std::span<u8> output); 116 NvResult SetSubmitTimeout(u32 timeout);
117 117
118 Kernel::KEvent* QueryEvent(u32 event_id) override; 118 Kernel::KEvent* QueryEvent(u32 event_id) override;
119 119
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
index a05c8cdae..9e6b86458 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
@@ -5,6 +5,7 @@
5 5
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
8#include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h" 9#include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h"
9 10
10namespace Service::Nvidia::Devices { 11namespace Service::Nvidia::Devices {
@@ -18,7 +19,7 @@ NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
18 case 'H': 19 case 'H':
19 switch (command.cmd) { 20 switch (command.cmd) {
20 case 0x1: 21 case 0x1:
21 return SetNVMAPfd(input, output); 22 return WrapFixed(this, &nvhost_nvjpg::SetNVMAPfd, input, output);
22 default: 23 default:
23 break; 24 break;
24 } 25 }
@@ -46,9 +47,7 @@ NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
46void nvhost_nvjpg::OnOpen(DeviceFD fd) {} 47void nvhost_nvjpg::OnOpen(DeviceFD fd) {}
47void nvhost_nvjpg::OnClose(DeviceFD fd) {} 48void nvhost_nvjpg::OnClose(DeviceFD fd) {}
48 49
49NvResult nvhost_nvjpg::SetNVMAPfd(std::span<const u8> input, std::span<u8> output) { 50NvResult nvhost_nvjpg::SetNVMAPfd(IoctlSetNvmapFD& params) {
50 IoctlSetNvmapFD params{};
51 std::memcpy(&params, input.data(), input.size());
52 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 51 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
53 52
54 nvmap_fd = params.nvmap_fd; 53 nvmap_fd = params.nvmap_fd;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
index 5623e0d47..790c97f6a 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
@@ -33,7 +33,7 @@ private:
33 33
34 s32_le nvmap_fd{}; 34 s32_le nvmap_fd{};
35 35
36 NvResult SetNVMAPfd(std::span<const u8> input, std::span<u8> output); 36 NvResult SetNVMAPfd(IoctlSetNvmapFD& params);
37}; 37};
38 38
39} // namespace Service::Nvidia::Devices 39} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index c0b8684c3..87f8d7c22 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -5,6 +5,7 @@
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/core.h" 6#include "core/core.h"
7#include "core/hle/service/nvdrv/core/container.h" 7#include "core/hle/service/nvdrv/core/container.h"
8#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
8#include "core/hle/service/nvdrv/devices/nvhost_vic.h" 9#include "core/hle/service/nvdrv/devices/nvhost_vic.h"
9#include "video_core/renderer_base.h" 10#include "video_core/renderer_base.h"
10 11
@@ -25,16 +26,16 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
25 if (!host1x_file.fd_to_id.contains(fd)) { 26 if (!host1x_file.fd_to_id.contains(fd)) {
26 host1x_file.fd_to_id[fd] = host1x_file.vic_next_id++; 27 host1x_file.fd_to_id[fd] = host1x_file.vic_next_id++;
27 } 28 }
28 return Submit(fd, input, output); 29 return WrapFixedVariable(this, &nvhost_vic::Submit, input, output, fd);
29 } 30 }
30 case 0x2: 31 case 0x2:
31 return GetSyncpoint(input, output); 32 return WrapFixed(this, &nvhost_vic::GetSyncpoint, input, output);
32 case 0x3: 33 case 0x3:
33 return GetWaitbase(input, output); 34 return WrapFixed(this, &nvhost_vic::GetWaitbase, input, output);
34 case 0x9: 35 case 0x9:
35 return MapBuffer(input, output); 36 return WrapFixedVariable(this, &nvhost_vic::MapBuffer, input, output);
36 case 0xa: 37 case 0xa:
37 return UnmapBuffer(input, output); 38 return WrapFixedVariable(this, &nvhost_vic::UnmapBuffer, input, output);
38 default: 39 default:
39 break; 40 break;
40 } 41 }
@@ -42,7 +43,7 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
42 case 'H': 43 case 'H':
43 switch (command.cmd) { 44 switch (command.cmd) {
44 case 0x1: 45 case 0x1:
45 return SetNVMAPfd(input); 46 return WrapFixed(this, &nvhost_vic::SetNVMAPfd, input, output);
46 default: 47 default:
47 break; 48 break;
48 } 49 }
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index 968eaa175..71b2e62ec 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -13,6 +13,7 @@
13#include "core/hle/kernel/k_process.h" 13#include "core/hle/kernel/k_process.h"
14#include "core/hle/service/nvdrv/core/container.h" 14#include "core/hle/service/nvdrv/core/container.h"
15#include "core/hle/service/nvdrv/core/nvmap.h" 15#include "core/hle/service/nvdrv/core/nvmap.h"
16#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
16#include "core/hle/service/nvdrv/devices/nvmap.h" 17#include "core/hle/service/nvdrv/devices/nvmap.h"
17#include "core/memory.h" 18#include "core/memory.h"
18 19
@@ -31,17 +32,17 @@ NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
31 case 0x1: 32 case 0x1:
32 switch (command.cmd) { 33 switch (command.cmd) {
33 case 0x1: 34 case 0x1:
34 return IocCreate(input, output); 35 return WrapFixed(this, &nvmap::IocCreate, input, output);
35 case 0x3: 36 case 0x3:
36 return IocFromId(input, output); 37 return WrapFixed(this, &nvmap::IocFromId, input, output);
37 case 0x4: 38 case 0x4:
38 return IocAlloc(input, output); 39 return WrapFixed(this, &nvmap::IocAlloc, input, output);
39 case 0x5: 40 case 0x5:
40 return IocFree(input, output); 41 return WrapFixed(this, &nvmap::IocFree, input, output);
41 case 0x9: 42 case 0x9:
42 return IocParam(input, output); 43 return WrapFixed(this, &nvmap::IocParam, input, output);
43 case 0xe: 44 case 0xe:
44 return IocGetId(input, output); 45 return WrapFixed(this, &nvmap::IocGetId, input, output);
45 default: 46 default:
46 break; 47 break;
47 } 48 }
@@ -69,9 +70,7 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, st
69void nvmap::OnOpen(DeviceFD fd) {} 70void nvmap::OnOpen(DeviceFD fd) {}
70void nvmap::OnClose(DeviceFD fd) {} 71void nvmap::OnClose(DeviceFD fd) {}
71 72
72NvResult nvmap::IocCreate(std::span<const u8> input, std::span<u8> output) { 73NvResult nvmap::IocCreate(IocCreateParams& params) {
73 IocCreateParams params;
74 std::memcpy(&params, input.data(), sizeof(params));
75 LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size); 74 LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size);
76 75
77 std::shared_ptr<NvCore::NvMap::Handle> handle_description{}; 76 std::shared_ptr<NvCore::NvMap::Handle> handle_description{};
@@ -85,13 +84,10 @@ NvResult nvmap::IocCreate(std::span<const u8> input, std::span<u8> output) {
85 params.handle = handle_description->id; 84 params.handle = handle_description->id;
86 LOG_DEBUG(Service_NVDRV, "handle: {}, size: 0x{:X}", handle_description->id, params.size); 85 LOG_DEBUG(Service_NVDRV, "handle: {}, size: 0x{:X}", handle_description->id, params.size);
87 86
88 std::memcpy(output.data(), &params, sizeof(params));
89 return NvResult::Success; 87 return NvResult::Success;
90} 88}
91 89
92NvResult nvmap::IocAlloc(std::span<const u8> input, std::span<u8> output) { 90NvResult nvmap::IocAlloc(IocAllocParams& params) {
93 IocAllocParams params;
94 std::memcpy(&params, input.data(), sizeof(params));
95 LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address); 91 LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address);
96 92
97 if (!params.handle) { 93 if (!params.handle) {
@@ -133,14 +129,10 @@ NvResult nvmap::IocAlloc(std::span<const u8> input, std::span<u8> output) {
133 handle_description->size, 129 handle_description->size,
134 Kernel::KMemoryPermission::None, true, false) 130 Kernel::KMemoryPermission::None, true, false)
135 .IsSuccess()); 131 .IsSuccess());
136 std::memcpy(output.data(), &params, sizeof(params));
137 return result; 132 return result;
138} 133}
139 134
140NvResult nvmap::IocGetId(std::span<const u8> input, std::span<u8> output) { 135NvResult nvmap::IocGetId(IocGetIdParams& params) {
141 IocGetIdParams params;
142 std::memcpy(&params, input.data(), sizeof(params));
143
144 LOG_DEBUG(Service_NVDRV, "called"); 136 LOG_DEBUG(Service_NVDRV, "called");
145 137
146 // See the comment in FromId for extra info on this function 138 // See the comment in FromId for extra info on this function
@@ -157,14 +149,10 @@ NvResult nvmap::IocGetId(std::span<const u8> input, std::span<u8> output) {
157 } 149 }
158 150
159 params.id = handle_description->id; 151 params.id = handle_description->id;
160 std::memcpy(output.data(), &params, sizeof(params));
161 return NvResult::Success; 152 return NvResult::Success;
162} 153}
163 154
164NvResult nvmap::IocFromId(std::span<const u8> input, std::span<u8> output) { 155NvResult nvmap::IocFromId(IocFromIdParams& params) {
165 IocFromIdParams params;
166 std::memcpy(&params, input.data(), sizeof(params));
167
168 LOG_DEBUG(Service_NVDRV, "called, id:{}", params.id); 156 LOG_DEBUG(Service_NVDRV, "called, id:{}", params.id);
169 157
170 // Handles and IDs are always the same value in nvmap however IDs can be used globally given the 158 // Handles and IDs are always the same value in nvmap however IDs can be used globally given the
@@ -188,16 +176,12 @@ NvResult nvmap::IocFromId(std::span<const u8> input, std::span<u8> output) {
188 return result; 176 return result;
189 } 177 }
190 params.handle = handle_description->id; 178 params.handle = handle_description->id;
191 std::memcpy(output.data(), &params, sizeof(params));
192 return NvResult::Success; 179 return NvResult::Success;
193} 180}
194 181
195NvResult nvmap::IocParam(std::span<const u8> input, std::span<u8> output) { 182NvResult nvmap::IocParam(IocParamParams& params) {
196 enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 }; 183 enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
197 184
198 IocParamParams params;
199 std::memcpy(&params, input.data(), sizeof(params));
200
201 LOG_DEBUG(Service_NVDRV, "called type={}", params.param); 185 LOG_DEBUG(Service_NVDRV, "called type={}", params.param);
202 186
203 if (!params.handle) { 187 if (!params.handle) {
@@ -237,14 +221,10 @@ NvResult nvmap::IocParam(std::span<const u8> input, std::span<u8> output) {
237 return NvResult::BadValue; 221 return NvResult::BadValue;
238 } 222 }
239 223
240 std::memcpy(output.data(), &params, sizeof(params));
241 return NvResult::Success; 224 return NvResult::Success;
242} 225}
243 226
244NvResult nvmap::IocFree(std::span<const u8> input, std::span<u8> output) { 227NvResult nvmap::IocFree(IocFreeParams& params) {
245 IocFreeParams params;
246 std::memcpy(&params, input.data(), sizeof(params));
247
248 LOG_DEBUG(Service_NVDRV, "called"); 228 LOG_DEBUG(Service_NVDRV, "called");
249 229
250 if (!params.handle) { 230 if (!params.handle) {
@@ -267,7 +247,6 @@ NvResult nvmap::IocFree(std::span<const u8> input, std::span<u8> output) {
267 // This is possible when there's internal dups or other duplicates. 247 // This is possible when there's internal dups or other duplicates.
268 } 248 }
269 249
270 std::memcpy(output.data(), &params, sizeof(params));
271 return NvResult::Success; 250 return NvResult::Success;
272} 251}
273 252
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
index 4c0cc71cd..049c11028 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -99,12 +99,12 @@ public:
99 }; 99 };
100 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); 100 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
101 101
102 NvResult IocCreate(std::span<const u8> input, std::span<u8> output); 102 NvResult IocCreate(IocCreateParams& params);
103 NvResult IocAlloc(std::span<const u8> input, std::span<u8> output); 103 NvResult IocAlloc(IocAllocParams& params);
104 NvResult IocGetId(std::span<const u8> input, std::span<u8> output); 104 NvResult IocGetId(IocGetIdParams& params);
105 NvResult IocFromId(std::span<const u8> input, std::span<u8> output); 105 NvResult IocFromId(IocFromIdParams& params);
106 NvResult IocParam(std::span<const u8> input, std::span<u8> output); 106 NvResult IocParam(IocParamParams& params);
107 NvResult IocFree(std::span<const u8> input, std::span<u8> output); 107 NvResult IocFree(IocFreeParams& params);
108 108
109private: 109private:
110 /// Id to use for the next handle that is created. 110 /// Id to use for the next handle that is created.
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 2e29bc848..6dc327b8b 100644
--- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
+++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
@@ -71,24 +71,17 @@ Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
71 R_SUCCEED(); 71 R_SUCCEED();
72} 72}
73 73
74template <typename T>
75std::span<u8> SerializeIoc(T& params) {
76 return std::span(reinterpret_cast<u8*>(std::addressof(params)), sizeof(T));
77}
78
79Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap, u32 size) { 74Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap, u32 size) {
80 // Create a handle. 75 // Create a handle.
81 Nvidia::Devices::nvmap::IocCreateParams create_in_params{ 76 Nvidia::Devices::nvmap::IocCreateParams create_params{
82 .size = size, 77 .size = size,
83 .handle = 0, 78 .handle = 0,
84 }; 79 };
85 Nvidia::Devices::nvmap::IocCreateParams create_out_params{}; 80 R_UNLESS(nvmap.IocCreate(create_params) == Nvidia::NvResult::Success,
86 R_UNLESS(nvmap.IocCreate(SerializeIoc(create_in_params), SerializeIoc(create_out_params)) ==
87 Nvidia::NvResult::Success,
88 VI::ResultOperationFailed); 81 VI::ResultOperationFailed);
89 82
90 // Assign the output handle. 83 // Assign the output handle.
91 *out_nv_map_handle = create_out_params.handle; 84 *out_nv_map_handle = create_params.handle;
92 85
93 // We succeeded. 86 // We succeeded.
94 R_SUCCEED(); 87 R_SUCCEED();
@@ -96,13 +89,10 @@ Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap,
96 89
97Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle) { 90Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle) {
98 // Free the handle. 91 // Free the handle.
99 Nvidia::Devices::nvmap::IocFreeParams free_in_params{ 92 Nvidia::Devices::nvmap::IocFreeParams free_params{
100 .handle = handle, 93 .handle = handle,
101 }; 94 };
102 Nvidia::Devices::nvmap::IocFreeParams free_out_params{}; 95 R_UNLESS(nvmap.IocFree(free_params) == Nvidia::NvResult::Success, VI::ResultOperationFailed);
103 R_UNLESS(nvmap.IocFree(SerializeIoc(free_in_params), SerializeIoc(free_out_params)) ==
104 Nvidia::NvResult::Success,
105 VI::ResultOperationFailed);
106 96
107 // We succeeded. 97 // We succeeded.
108 R_SUCCEED(); 98 R_SUCCEED();
@@ -111,7 +101,7 @@ Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle) {
111Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::ProcessAddress buffer, 101Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::ProcessAddress buffer,
112 u32 size) { 102 u32 size) {
113 // Assign the allocated memory to the handle. 103 // Assign the allocated memory to the handle.
114 Nvidia::Devices::nvmap::IocAllocParams alloc_in_params{ 104 Nvidia::Devices::nvmap::IocAllocParams alloc_params{
115 .handle = handle, 105 .handle = handle,
116 .heap_mask = 0, 106 .heap_mask = 0,
117 .flags = {}, 107 .flags = {},
@@ -119,10 +109,7 @@ Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::Proce
119 .kind = 0, 109 .kind = 0,
120 .address = GetInteger(buffer), 110 .address = GetInteger(buffer),
121 }; 111 };
122 Nvidia::Devices::nvmap::IocAllocParams alloc_out_params{}; 112 R_UNLESS(nvmap.IocAlloc(alloc_params) == Nvidia::NvResult::Success, VI::ResultOperationFailed);
123 R_UNLESS(nvmap.IocAlloc(SerializeIoc(alloc_in_params), SerializeIoc(alloc_out_params)) ==
124 Nvidia::NvResult::Success,
125 VI::ResultOperationFailed);
126 113
127 // We succeeded. 114 // We succeeded.
128 R_SUCCEED(); 115 R_SUCCEED();