summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Liam2023-10-25 00:34:40 -0400
committerGravatar Liam2023-10-25 13:05:56 -0400
commit723df0f3685f01ce5a0330d567932136a9de7a8f (patch)
tree5b26229e14b70dba5d59d9265b750e5edff874b5
parentnvdrv: fix up remaining copy calls (diff)
downloadyuzu-723df0f3685f01ce5a0330d567932136a9de7a8f.tar.gz
yuzu-723df0f3685f01ce5a0330d567932136a9de7a8f.tar.xz
yuzu-723df0f3685f01ce5a0330d567932136a9de7a8f.zip
nvdrv: rework to remove memcpy
-rw-r--r--src/core/hle/service/nvdrv/devices/ioctl_serialization.h180
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp26
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp16
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h11
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp41
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp52
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp14
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp71
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp12
16 files changed, 243 insertions, 225 deletions
diff --git a/src/core/hle/service/nvdrv/devices/ioctl_serialization.h b/src/core/hle/service/nvdrv/devices/ioctl_serialization.h
index c560974f1..b12bcd138 100644
--- a/src/core/hle/service/nvdrv/devices/ioctl_serialization.h
+++ b/src/core/hle/service/nvdrv/devices/ioctl_serialization.h
@@ -11,97 +11,149 @@
11 11
12namespace Service::Nvidia::Devices { 12namespace Service::Nvidia::Devices {
13 13
14struct Ioctl1Traits { 14struct IoctlOneArgTraits {
15 template <typename T, typename R, typename A> 15 template <typename T, typename R, typename A, typename... B>
16 static T GetClassImpl(R (T::*)(A)); 16 static A GetFirstArgImpl(R (T::*)(A, B...));
17
18 template <typename T, typename R, typename A>
19 static A GetArgImpl(R (T::*)(A));
20}; 17};
21 18
22struct Ioctl23Traits { 19struct IoctlTwoArgTraits {
23 template <typename T, typename R, typename A, typename B> 20 template <typename T, typename R, typename A, typename B, typename... C>
24 static T GetClassImpl(R (T::*)(A, B)); 21 static A GetFirstArgImpl(R (T::*)(A, B, C...));
25 22
26 template <typename T, typename R, typename A, typename B> 23 template <typename T, typename R, typename A, typename B, typename... C>
27 static A GetArgImpl(R (T::*)(A, B)); 24 static B GetSecondArgImpl(R (T::*)(A, B, C...));
28}; 25};
29 26
30template <typename T> 27struct Null {};
31struct ContainerType {
32 using ValueType = T;
33};
34 28
35template <Common::IsContiguousContainer T> 29// clang-format off
36struct ContainerType<T> {
37 using ValueType = T::value_type;
38};
39 30
40template <typename InnerArg, typename F, typename Self, typename... Rest> 31template <typename FixedArg, typename VarArg, typename InlInVarArg, typename InlOutVarArg, typename F>
41NvResult Wrap(std::span<const u8> input, std::span<u8> output, Self* self, F&& callable, 32NvResult WrapGeneric(F&& callable, std::span<const u8> input, std::span<const u8> inline_input, std::span<u8> output, std::span<u8> inline_output) {
42 Rest&&... rest) { 33 constexpr bool HasFixedArg = !std::is_same_v<FixedArg, Null>;
43 using Arg = ContainerType<InnerArg>::ValueType; 34 constexpr bool HasVarArg = !std::is_same_v<VarArg, Null>;
44 constexpr bool ArgumentIsContainer = Common::IsContiguousContainer<InnerArg>; 35 constexpr bool HasInlInVarArg = !std::is_same_v<InlInVarArg, Null>;
45 36 constexpr bool HasInlOutVarArg = !std::is_same_v<InlOutVarArg, Null>;
46 // Verify that the input and output sizes are valid. 37
47 const size_t in_params = input.size() / sizeof(Arg); 38 // Declare the fixed-size input value.
48 const size_t out_params = output.size() / sizeof(Arg); 39 FixedArg fixed{};
49 if (in_params * sizeof(Arg) != input.size()) { 40 size_t var_offset = 0;
50 return NvResult::InvalidSize; 41
51 } 42 if constexpr (HasFixedArg) {
52 if (out_params * sizeof(Arg) != output.size()) { 43 // Read the fixed-size input value.
53 return NvResult::InvalidSize; 44 var_offset = std::min(sizeof(FixedArg), input.size());
45 if (var_offset > 0) {
46 std::memcpy(&fixed, input.data(), var_offset);
47 }
54 } 48 }
55 if (in_params == 0 && out_params == 0 && !ArgumentIsContainer) { 49
56 return NvResult::InvalidSize; 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 } 57 }
58 58
59 // Copy inputs, if needed. 59 const size_t num_inl_in_var_args = HasInlInVarArg ? (inline_input.size() / sizeof(InlInVarArg)) : 0;
60 std::vector<Arg> params(std::max(in_params, out_params)); 60 std::vector<InlInVarArg> inl_in_var_args(num_inl_in_var_args);
61 if (in_params > 0) { 61 if constexpr (HasInlInVarArg) {
62 std::memcpy(params.data(), input.data(), input.size()); 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 }
63 } 65 }
64 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
65 // Perform the call. 71 // Perform the call.
66 NvResult result; 72 NvResult result = callable(fixed, var_args, inl_in_var_args, inl_out_var_args);
67 if constexpr (ArgumentIsContainer) { 73
68 result = (self->*callable)(params, std::forward<Rest>(rest)...); 74 // Copy outputs.
69 } else { 75 if constexpr (HasFixedArg) {
70 result = (self->*callable)(params.front(), std::forward<Rest>(rest)...); 76 if (output.size() > 0) {
77 std::memcpy(output.data(), &fixed, std::min(output.size(), sizeof(FixedArg)));
78 }
71 } 79 }
72 80
73 // Copy outputs, if needed. 81 if constexpr (HasVarArg) {
74 if (out_params > 0) { 82 if (num_var_args > 0 && output.size() > var_offset) {
75 std::memcpy(output.data(), params.data(), output.size()); 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 }
76 } 86 }
77 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.
78 return result; 96 return result;
79} 97}
80 98
81template <typename F> 99template <typename Self, typename F, typename... Rest>
82NvResult nvdevice::Wrap1(F&& callable, std::span<const u8> input, std::span<u8> output) { 100NvResult WrapFixed(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, Rest&&... rest) {
83 using Self = decltype(Ioctl1Traits::GetClassImpl(callable)); 101 using FixedArg = typename std::remove_reference_t<decltype(IoctlOneArgTraits::GetFirstArgImpl(callable))>;
84 using InnerArg = std::remove_reference_t<decltype(Ioctl1Traits::GetArgImpl(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 };
85 106
86 return Wrap<InnerArg>(input, output, static_cast<Self*>(this), callable); 107 return WrapGeneric<FixedArg, Null, Null, Null>(std::move(Callable), input, {}, output, {});
87} 108}
88 109
89template <typename F> 110template <typename Self, typename F, typename... Rest>
90NvResult nvdevice::Wrap2(F&& callable, std::span<const u8> input, std::span<const u8> inline_input, 111NvResult WrapFixedInlOut(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, std::span<u8> inline_output, Rest&&... rest) {
91 std::span<u8> output) { 112 using FixedArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetFirstArgImpl(callable))>;
92 using Self = decltype(Ioctl23Traits::GetClassImpl(callable)); 113 using InlOutVarArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetSecondArgImpl(callable))>::value_type;
93 using InnerArg = std::remove_reference_t<decltype(Ioctl23Traits::GetArgImpl(callable))>;
94 114
95 return Wrap<InnerArg>(input, output, static_cast<Self*>(this), callable, inline_input); 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, {});
96} 131}
97 132
98template <typename F> 133template <typename Self, typename F, typename... Rest>
99NvResult nvdevice::Wrap3(F&& callable, std::span<const u8> input, std::span<u8> output, 134NvResult WrapFixedVariable(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, Rest&&... rest) {
100 std::span<u8> inline_output) { 135 using FixedArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetFirstArgImpl(callable))>;
101 using Self = decltype(Ioctl23Traits::GetClassImpl(callable)); 136 using VarArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetSecondArgImpl(callable))>::value_type;
102 using InnerArg = std::remove_reference_t<decltype(Ioctl23Traits::GetArgImpl(callable))>; 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 };
103 141
104 return Wrap<InnerArg>(input, output, static_cast<Self*>(this), callable, inline_output); 142 return WrapGeneric<FixedArg, VarArg, Null, Null>(std::move(Callable), input, {}, output, {});
105} 143}
106 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
107} // namespace Service::Nvidia::Devices 159} // 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 af766f320..a04538d5d 100644
--- a/src/core/hle/service/nvdrv/devices/nvdevice.h
+++ b/src/core/hle/service/nvdrv/devices/nvdevice.h
@@ -75,18 +75,6 @@ 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:
90 Core::System& system; 78 Core::System& system;
91}; 79};
92 80
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 484001071..6b3639008 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -34,21 +34,21 @@ NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> i
34 case 'A': 34 case 'A':
35 switch (command.cmd) { 35 switch (command.cmd) {
36 case 0x1: 36 case 0x1:
37 return Wrap1(&nvhost_as_gpu::BindChannel, input, output); 37 return WrapFixed(this, &nvhost_as_gpu::BindChannel, input, output);
38 case 0x2: 38 case 0x2:
39 return Wrap1(&nvhost_as_gpu::AllocateSpace, input, output); 39 return WrapFixed(this, &nvhost_as_gpu::AllocateSpace, input, output);
40 case 0x3: 40 case 0x3:
41 return Wrap1(&nvhost_as_gpu::FreeSpace, input, output); 41 return WrapFixed(this, &nvhost_as_gpu::FreeSpace, input, output);
42 case 0x5: 42 case 0x5:
43 return Wrap1(&nvhost_as_gpu::UnmapBuffer, input, output); 43 return WrapFixed(this, &nvhost_as_gpu::UnmapBuffer, input, output);
44 case 0x6: 44 case 0x6:
45 return Wrap1(&nvhost_as_gpu::MapBufferEx, input, output); 45 return WrapFixed(this, &nvhost_as_gpu::MapBufferEx, input, output);
46 case 0x8: 46 case 0x8:
47 return Wrap1(&nvhost_as_gpu::GetVARegions1, input, output); 47 return WrapFixed(this, &nvhost_as_gpu::GetVARegions1, input, output);
48 case 0x9: 48 case 0x9:
49 return Wrap1(&nvhost_as_gpu::AllocAsEx, input, output); 49 return WrapFixed(this, &nvhost_as_gpu::AllocAsEx, input, output);
50 case 0x14: 50 case 0x14:
51 return Wrap1(&nvhost_as_gpu::Remap, input, output); 51 return WrapVariable(this, &nvhost_as_gpu::Remap, input, output);
52 default: 52 default:
53 break; 53 break;
54 } 54 }
@@ -73,7 +73,8 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i
73 case 'A': 73 case 'A':
74 switch (command.cmd) { 74 switch (command.cmd) {
75 case 0x8: 75 case 0x8:
76 return Wrap3(&nvhost_as_gpu::GetVARegions3, input, output, inline_output); 76 return WrapFixedInlOut(this, &nvhost_as_gpu::GetVARegions3, input, output,
77 inline_output);
77 default: 78 default:
78 break; 79 break;
79 } 80 }
@@ -482,7 +483,7 @@ NvResult nvhost_as_gpu::GetVARegions1(IoctlGetVaRegions& params) {
482 return NvResult::Success; 483 return NvResult::Success;
483} 484}
484 485
485NvResult nvhost_as_gpu::GetVARegions3(IoctlGetVaRegions& params, std::span<u8> inline_output) { 486NvResult nvhost_as_gpu::GetVARegions3(IoctlGetVaRegions& params, std::span<VaRegion> regions) {
486 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,
487 params.buf_size); 488 params.buf_size);
488 489
@@ -494,7 +495,10 @@ NvResult nvhost_as_gpu::GetVARegions3(IoctlGetVaRegions& params, std::span<u8> i
494 495
495 GetVARegionsImpl(params); 496 GetVARegionsImpl(params);
496 497
497 std::memcpy(inline_output.data(), params.regions.data(), 2 * sizeof(VaRegion)); 498 const size_t num_regions = std::min(params.regions.size(), regions.size());
499 for (size_t i = 0; i < num_regions; i++) {
500 regions[i] = params.regions[i];
501 }
498 502
499 return NvResult::Success; 503 return NvResult::Success;
500} 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 bc041f215..932997e75 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -149,7 +149,7 @@ private:
149 149
150 void GetVARegionsImpl(IoctlGetVaRegions& params); 150 void GetVARegionsImpl(IoctlGetVaRegions& params);
151 NvResult GetVARegions1(IoctlGetVaRegions& params); 151 NvResult GetVARegions1(IoctlGetVaRegions& params);
152 NvResult GetVARegions3(IoctlGetVaRegions& params, std::span<u8> inline_output); 152 NvResult GetVARegions3(IoctlGetVaRegions& params, std::span<VaRegion> regions);
153 153
154 void FreeMappingLocked(u64 offset); 154 void FreeMappingLocked(u64 offset);
155 155
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index 8cefff6d1..b8dd34e24 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -41,19 +41,19 @@ NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inp
41 case 0x0: 41 case 0x0:
42 switch (command.cmd) { 42 switch (command.cmd) {
43 case 0x1b: 43 case 0x1b:
44 return Wrap1(&nvhost_ctrl::NvOsGetConfigU32, input, output); 44 return WrapFixed(this, &nvhost_ctrl::NvOsGetConfigU32, input, output);
45 case 0x1c: 45 case 0x1c:
46 return Wrap1(&nvhost_ctrl::IocCtrlClearEventWait, input, output); 46 return WrapFixed(this, &nvhost_ctrl::IocCtrlClearEventWait, input, output);
47 case 0x1d: 47 case 0x1d:
48 return Wrap1(&nvhost_ctrl::IocCtrlEventWaitWithAllocation, input, output); 48 return WrapFixed(this, &nvhost_ctrl::IocCtrlEventWait, input, output, true);
49 case 0x1e: 49 case 0x1e:
50 return Wrap1(&nvhost_ctrl::IocCtrlEventWaitNotAllocation, input, output); 50 return WrapFixed(this, &nvhost_ctrl::IocCtrlEventWait, input, output, false);
51 case 0x1f: 51 case 0x1f:
52 return Wrap1(&nvhost_ctrl::IocCtrlEventRegister, input, output); 52 return WrapFixed(this, &nvhost_ctrl::IocCtrlEventRegister, input, output);
53 case 0x20: 53 case 0x20:
54 return Wrap1(&nvhost_ctrl::IocCtrlEventUnregister, input, output); 54 return WrapFixed(this, &nvhost_ctrl::IocCtrlEventUnregister, input, output);
55 case 0x21: 55 case 0x21:
56 return Wrap1(&nvhost_ctrl::IocCtrlEventUnregisterBatch, input, output); 56 return WrapFixed(this, &nvhost_ctrl::IocCtrlEventUnregisterBatch, input, output);
57 } 57 }
58 break; 58 break;
59 default: 59 default:
@@ -86,7 +86,7 @@ NvResult nvhost_ctrl::NvOsGetConfigU32(IocGetConfigParams& params) {
86 return NvResult::ConfigVarNotFound; // Returns error on production mode 86 return NvResult::ConfigVarNotFound; // Returns error on production mode
87} 87}
88 88
89NvResult nvhost_ctrl::IocCtrlEventWaitImpl(IocCtrlEventWaitParams& params, bool is_allocation) { 89NvResult nvhost_ctrl::IocCtrlEventWait(IocCtrlEventWaitParams& params, bool is_allocation) {
90 LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_allocation={}", 90 LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_allocation={}",
91 params.fence.id, params.fence.value, params.timeout, is_allocation); 91 params.fence.id, params.fence.value, params.timeout, is_allocation);
92 92
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index 6913c61ac..992124b60 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -190,20 +190,11 @@ private:
190 NvResult IocCtrlEventRegister(IocCtrlEventRegisterParams& params); 190 NvResult IocCtrlEventRegister(IocCtrlEventRegisterParams& params);
191 NvResult IocCtrlEventUnregister(IocCtrlEventUnregisterParams& params); 191 NvResult IocCtrlEventUnregister(IocCtrlEventUnregisterParams& params);
192 NvResult IocCtrlEventUnregisterBatch(IocCtrlEventUnregisterBatchParams& params); 192 NvResult IocCtrlEventUnregisterBatch(IocCtrlEventUnregisterBatchParams& params);
193 NvResult IocCtrlEventWait(IocCtrlEventWaitParams& params, bool is_allocation);
193 NvResult IocCtrlClearEventWait(IocCtrlEventClearParams& params); 194 NvResult IocCtrlClearEventWait(IocCtrlEventClearParams& params);
194 195
195 NvResult FreeEvent(u32 slot); 196 NvResult FreeEvent(u32 slot);
196 197
197 // TODO: these are not the correct names
198 NvResult IocCtrlEventWaitNotAllocation(IocCtrlEventWaitParams& params) {
199 return this->IocCtrlEventWaitImpl(params, false);
200 }
201 NvResult IocCtrlEventWaitWithAllocation(IocCtrlEventWaitParams& params) {
202 return this->IocCtrlEventWaitImpl(params, true);
203 }
204
205 NvResult IocCtrlEventWaitImpl(IocCtrlEventWaitParams& params, bool is_allocation);
206
207 EventInterface& events_interface; 198 EventInterface& events_interface;
208 NvCore::Container& core; 199 NvCore::Container& core;
209 NvCore::SyncpointManager& syncpoint_manager; 200 NvCore::SyncpointManager& syncpoint_manager;
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 92e677b3d..61a2df121 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -28,23 +28,23 @@ NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8>
28 case 'G': 28 case 'G':
29 switch (command.cmd) { 29 switch (command.cmd) {
30 case 0x1: 30 case 0x1:
31 return Wrap1(&nvhost_ctrl_gpu::ZCullGetCtxSize, input, output); 31 return WrapFixed(this, &nvhost_ctrl_gpu::ZCullGetCtxSize, input, output);
32 case 0x2: 32 case 0x2:
33 return Wrap1(&nvhost_ctrl_gpu::ZCullGetInfo, input, output); 33 return WrapFixed(this, &nvhost_ctrl_gpu::ZCullGetInfo, input, output);
34 case 0x3: 34 case 0x3:
35 return Wrap1(&nvhost_ctrl_gpu::ZBCSetTable, input, output); 35 return WrapFixed(this, &nvhost_ctrl_gpu::ZBCSetTable, input, output);
36 case 0x4: 36 case 0x4:
37 return Wrap1(&nvhost_ctrl_gpu::ZBCQueryTable, input, output); 37 return WrapFixed(this, &nvhost_ctrl_gpu::ZBCQueryTable, input, output);
38 case 0x5: 38 case 0x5:
39 return Wrap1(&nvhost_ctrl_gpu::GetCharacteristics1, input, output); 39 return WrapFixed(this, &nvhost_ctrl_gpu::GetCharacteristics1, input, output);
40 case 0x6: 40 case 0x6:
41 return Wrap1(&nvhost_ctrl_gpu::GetTPCMasks1, input, output); 41 return WrapFixed(this, &nvhost_ctrl_gpu::GetTPCMasks1, input, output);
42 case 0x7: 42 case 0x7:
43 return Wrap1(&nvhost_ctrl_gpu::FlushL2, input, output); 43 return WrapFixed(this, &nvhost_ctrl_gpu::FlushL2, input, output);
44 case 0x14: 44 case 0x14:
45 return Wrap1(&nvhost_ctrl_gpu::GetActiveSlotMask, input, output); 45 return WrapFixed(this, &nvhost_ctrl_gpu::GetActiveSlotMask, input, output);
46 case 0x1c: 46 case 0x1c:
47 return Wrap1(&nvhost_ctrl_gpu::GetGpuTime, input, output); 47 return WrapFixed(this, &nvhost_ctrl_gpu::GetGpuTime, input, output);
48 default: 48 default:
49 break; 49 break;
50 } 50 }
@@ -66,9 +66,11 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8>
66 case 'G': 66 case 'G':
67 switch (command.cmd) { 67 switch (command.cmd) {
68 case 0x5: 68 case 0x5:
69 return Wrap3(&nvhost_ctrl_gpu::GetCharacteristics3, input, output, inline_output); 69 return WrapFixedInlOut(this, &nvhost_ctrl_gpu::GetCharacteristics3, input, output,
70 inline_output);
70 case 0x6: 71 case 0x6:
71 return Wrap3(&nvhost_ctrl_gpu::GetTPCMasks3, input, output, inline_output); 72 return WrapFixedInlOut(this, &nvhost_ctrl_gpu::GetTPCMasks3, input, output,
73 inline_output);
72 default: 74 default:
73 break; 75 break;
74 } 76 }
@@ -125,8 +127,8 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics1(IoctlCharacteristics& params) {
125 return NvResult::Success; 127 return NvResult::Success;
126} 128}
127 129
128NvResult nvhost_ctrl_gpu::GetCharacteristics3(IoctlCharacteristics& params, 130NvResult nvhost_ctrl_gpu::GetCharacteristics3(
129 std::span<u8> inline_output) { 131 IoctlCharacteristics& params, std::span<IoctlGpuCharacteristics> gpu_characteristics) {
130 LOG_DEBUG(Service_NVDRV, "called"); 132 LOG_DEBUG(Service_NVDRV, "called");
131 133
132 params.gc.arch = 0x120; 134 params.gc.arch = 0x120;
@@ -166,8 +168,9 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics3(IoctlCharacteristics& params,
166 params.gc.gr_compbit_store_base_hw = 0x0; 168 params.gc.gr_compbit_store_base_hw = 0x0;
167 params.gpu_characteristics_buf_size = 0xA0; 169 params.gpu_characteristics_buf_size = 0xA0;
168 params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) 170 params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED)
169 std::memcpy(inline_output.data(), &params.gc, 171 if (!gpu_characteristics.empty()) {
170 std::min(sizeof(params.gc), inline_output.size())); 172 gpu_characteristics.front() = params.gc;
173 }
171 return NvResult::Success; 174 return NvResult::Success;
172} 175}
173 176
@@ -179,14 +182,14 @@ NvResult nvhost_ctrl_gpu::GetTPCMasks1(IoctlGpuGetTpcMasksArgs& params) {
179 return NvResult::Success; 182 return NvResult::Success;
180} 183}
181 184
182NvResult nvhost_ctrl_gpu::GetTPCMasks3(IoctlGpuGetTpcMasksArgs& params, 185NvResult nvhost_ctrl_gpu::GetTPCMasks3(IoctlGpuGetTpcMasksArgs& params, std::span<u32> tpc_mask) {
183 std::span<u8> inline_output) {
184 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);
185 if (params.mask_buffer_size != 0) { 187 if (params.mask_buffer_size != 0) {
186 params.tcp_mask = 3; 188 params.tcp_mask = 3;
187 } 189 }
188 std::memcpy(inline_output.data(), &params.tcp_mask, 190 if (!tpc_mask.empty()) {
189 std::min(sizeof(params.tcp_mask), inline_output.size())); 191 tpc_mask.front() = params.tcp_mask;
192 }
190 return NvResult::Success; 193 return NvResult::Success;
191} 194}
192 195
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 e1977a6b5..d170299bd 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
@@ -152,10 +152,11 @@ private:
152 static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); 152 static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size");
153 153
154 NvResult GetCharacteristics1(IoctlCharacteristics& params); 154 NvResult GetCharacteristics1(IoctlCharacteristics& params);
155 NvResult GetCharacteristics3(IoctlCharacteristics& params, std::span<u8> inline_output); 155 NvResult GetCharacteristics3(IoctlCharacteristics& params,
156 std::span<IoctlGpuCharacteristics> gpu_characteristics);
156 157
157 NvResult GetTPCMasks1(IoctlGpuGetTpcMasksArgs& params); 158 NvResult GetTPCMasks1(IoctlGpuGetTpcMasksArgs& params);
158 NvResult GetTPCMasks3(IoctlGpuGetTpcMasksArgs& params, std::span<u8> inline_output); 159 NvResult GetTPCMasks3(IoctlGpuGetTpcMasksArgs& params, std::span<u32> tpc_mask);
159 160
160 NvResult GetActiveSlotMask(IoctlActiveSlotMask& params); 161 NvResult GetActiveSlotMask(IoctlActiveSlotMask& params);
161 NvResult ZCullGetCtxSize(IoctlZcullGetCtxSize& params); 162 NvResult ZCullGetCtxSize(IoctlZcullGetCtxSize& params);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 2d67acc6a..b0395c2f0 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -53,7 +53,7 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
53 case 0x0: 53 case 0x0:
54 switch (command.cmd) { 54 switch (command.cmd) {
55 case 0x3: 55 case 0x3:
56 return Wrap1(&nvhost_gpu::GetWaitbase, input, output); 56 return WrapFixed(this, &nvhost_gpu::GetWaitbase, input, output);
57 default: 57 default:
58 break; 58 break;
59 } 59 }
@@ -61,25 +61,25 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
61 case 'H': 61 case 'H':
62 switch (command.cmd) { 62 switch (command.cmd) {
63 case 0x1: 63 case 0x1:
64 return Wrap1(&nvhost_gpu::SetNVMAPfd, input, output); 64 return WrapFixed(this, &nvhost_gpu::SetNVMAPfd, input, output);
65 case 0x3: 65 case 0x3:
66 return Wrap1(&nvhost_gpu::ChannelSetTimeout, input, output); 66 return WrapFixed(this, &nvhost_gpu::ChannelSetTimeout, input, output);
67 case 0x8: 67 case 0x8:
68 return SubmitGPFIFOBase1(input, false); 68 return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, false);
69 case 0x9: 69 case 0x9:
70 return Wrap1(&nvhost_gpu::AllocateObjectContext, input, output); 70 return WrapFixed(this, &nvhost_gpu::AllocateObjectContext, input, output);
71 case 0xb: 71 case 0xb:
72 return Wrap1(&nvhost_gpu::ZCullBind, input, output); 72 return WrapFixed(this, &nvhost_gpu::ZCullBind, input, output);
73 case 0xc: 73 case 0xc:
74 return Wrap1(&nvhost_gpu::SetErrorNotifier, input, output); 74 return WrapFixed(this, &nvhost_gpu::SetErrorNotifier, input, output);
75 case 0xd: 75 case 0xd:
76 return Wrap1(&nvhost_gpu::SetChannelPriority, input, output); 76 return WrapFixed(this, &nvhost_gpu::SetChannelPriority, input, output);
77 case 0x1a: 77 case 0x1a:
78 return Wrap1(&nvhost_gpu::AllocGPFIFOEx2, input, output); 78 return WrapFixed(this, &nvhost_gpu::AllocGPFIFOEx2, input, output);
79 case 0x1b: 79 case 0x1b:
80 return SubmitGPFIFOBase1(input, true); 80 return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, true);
81 case 0x1d: 81 case 0x1d:
82 return Wrap1(&nvhost_gpu::ChannelSetTimeslice, input, output); 82 return WrapFixed(this, &nvhost_gpu::ChannelSetTimeslice, input, output);
83 default: 83 default:
84 break; 84 break;
85 } 85 }
@@ -87,9 +87,9 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
87 case 'G': 87 case 'G':
88 switch (command.cmd) { 88 switch (command.cmd) {
89 case 0x14: 89 case 0x14:
90 return Wrap1(&nvhost_gpu::SetClientData, input, output); 90 return WrapFixed(this, &nvhost_gpu::SetClientData, input, output);
91 case 0x15: 91 case 0x15:
92 return Wrap1(&nvhost_gpu::GetClientData, input, output); 92 return WrapFixed(this, &nvhost_gpu::GetClientData, input, output);
93 default: 93 default:
94 break; 94 break;
95 } 95 }
@@ -105,7 +105,8 @@ NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> inpu
105 case 'H': 105 case 'H':
106 switch (command.cmd) { 106 switch (command.cmd) {
107 case 0x1b: 107 case 0x1b:
108 return SubmitGPFIFOBase2(input, inline_input); 108 return WrapFixedInlIn(this, &nvhost_gpu::SubmitGPFIFOBase2, input, inline_input,
109 output);
109 } 110 }
110 break; 111 break;
111 } 112 }
@@ -271,36 +272,35 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL
271 return NvResult::Success; 272 return NvResult::Success;
272} 273}
273 274
274NvResult nvhost_gpu::SubmitGPFIFOBase1(std::span<const u8> input, bool kickoff) { 275NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
275 if (input.size() < sizeof(IoctlSubmitGpfifo)) { 276 std::span<Tegra::CommandListHeader> commands, bool kickoff) {
277 if (params.num_entries > commands.size()) {
276 UNIMPLEMENTED(); 278 UNIMPLEMENTED();
277 return NvResult::InvalidSize; 279 return NvResult::InvalidSize;
278 } 280 }
279 IoctlSubmitGpfifo params{};
280 std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
281 Tegra::CommandList entries(params.num_entries);
282 281
282 Tegra::CommandList entries(params.num_entries);
283 if (kickoff) { 283 if (kickoff) {
284 system.ApplicationMemory().ReadBlock(params.address, entries.command_lists.data(), 284 system.ApplicationMemory().ReadBlock(params.address, entries.command_lists.data(),
285 params.num_entries * sizeof(Tegra::CommandListHeader)); 285 params.num_entries * sizeof(Tegra::CommandListHeader));
286 } else { 286 } else {
287 std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)], 287 std::memcpy(entries.command_lists.data(), commands.data(),
288 params.num_entries * sizeof(Tegra::CommandListHeader)); 288 params.num_entries * sizeof(Tegra::CommandListHeader));
289 } 289 }
290 290
291 return SubmitGPFIFOImpl(params, std::move(entries)); 291 return SubmitGPFIFOImpl(params, std::move(entries));
292} 292}
293 293
294NvResult nvhost_gpu::SubmitGPFIFOBase2(std::span<const u8> input, 294NvResult nvhost_gpu::SubmitGPFIFOBase2(IoctlSubmitGpfifo& params,
295 std::span<const u8> input_inline) { 295 std::span<const Tegra::CommandListHeader> commands) {
296 if (input.size() < sizeof(IoctlSubmitGpfifo)) { 296 if (params.num_entries > commands.size()) {
297 UNIMPLEMENTED(); 297 UNIMPLEMENTED();
298 return NvResult::InvalidSize; 298 return NvResult::InvalidSize;
299 } 299 }
300 IoctlSubmitGpfifo params{}; 300
301 std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
302 Tegra::CommandList entries(params.num_entries); 301 Tegra::CommandList entries(params.num_entries);
303 std::memcpy(entries.command_lists.data(), input_inline.data(), input_inline.size()); 302 std::memcpy(entries.command_lists.data(), commands.data(),
303 params.num_entries * sizeof(Tegra::CommandListHeader));
304 return SubmitGPFIFOImpl(params, std::move(entries)); 304 return SubmitGPFIFOImpl(params, std::move(entries));
305} 305}
306 306
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index 703079a54..88fd228ff 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -196,8 +196,10 @@ private:
196 NvResult AllocateObjectContext(IoctlAllocObjCtx& params); 196 NvResult AllocateObjectContext(IoctlAllocObjCtx& params);
197 197
198 NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandList&& entries); 198 NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandList&& entries);
199 NvResult SubmitGPFIFOBase1(std::span<const u8> input, bool kickoff = false); 199 NvResult SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
200 NvResult SubmitGPFIFOBase2(std::span<const u8> input, std::span<const u8> input_inline); 200 std::span<Tegra::CommandListHeader> commands, bool kickoff = false);
201 NvResult SubmitGPFIFOBase2(IoctlSubmitGpfifo& params,
202 std::span<const Tegra::CommandListHeader> commands);
201 203
202 NvResult GetWaitbase(IoctlGetWaitbase& params); 204 NvResult GetWaitbase(IoctlGetWaitbase& params);
203 NvResult ChannelSetTimeout(IoctlChannelSetTimeout& params); 205 NvResult ChannelSetTimeout(IoctlChannelSetTimeout& params);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index 74790a7d8..f43914e1b 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -26,18 +26,18 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
26 if (!host1x_file.fd_to_id.contains(fd)) { 26 if (!host1x_file.fd_to_id.contains(fd)) {
27 host1x_file.fd_to_id[fd] = host1x_file.nvdec_next_id++; 27 host1x_file.fd_to_id[fd] = host1x_file.nvdec_next_id++;
28 } 28 }
29 return Submit(fd, input, output); 29 return WrapFixedVariable(this, &nvhost_nvdec::Submit, input, output, fd);
30 } 30 }
31 case 0x2: 31 case 0x2:
32 return Wrap1(&nvhost_nvdec::GetSyncpoint, input, output); 32 return WrapFixed(this, &nvhost_nvdec::GetSyncpoint, input, output);
33 case 0x3: 33 case 0x3:
34 return Wrap1(&nvhost_nvdec::GetWaitbase, input, output); 34 return WrapFixed(this, &nvhost_nvdec::GetWaitbase, input, output);
35 case 0x7: 35 case 0x7:
36 return Wrap1(&nvhost_nvdec::SetSubmitTimeout, input, output); 36 return WrapFixed(this, &nvhost_nvdec::SetSubmitTimeout, input, output);
37 case 0x9: 37 case 0x9:
38 return MapBuffer(input, output); 38 return WrapFixedVariable(this, &nvhost_nvdec::MapBuffer, input, output);
39 case 0xa: 39 case 0xa:
40 return UnmapBuffer(input, output); 40 return WrapFixedVariable(this, &nvhost_nvdec::UnmapBuffer, input, output);
41 default: 41 default:
42 break; 42 break;
43 } 43 }
@@ -45,7 +45,7 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
45 case 'H': 45 case 'H':
46 switch (command.cmd) { 46 switch (command.cmd) {
47 case 0x1: 47 case 0x1:
48 return Wrap1(&nvhost_nvdec::SetNVMAPfd, input, output); 48 return WrapFixed(this, &nvhost_nvdec::SetNVMAPfd, input, output);
49 default: 49 default:
50 break; 50 break;
51 } 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 3fdf383f0..74c701b95 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -76,13 +76,7 @@ NvResult nvhost_nvdec_common::SetNVMAPfd(IoctlSetNvmapFD& params) {
76 return NvResult::Success; 76 return NvResult::Success;
77} 77}
78 78
79NvResult 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) {
80 if (input.size() < sizeof(IoctlSubmit) || output.size() < sizeof(IoctlSubmit)) {
81 UNIMPLEMENTED();
82 return NvResult::InvalidSize;
83 }
84 IoctlSubmit params{};
85 std::memcpy(&params, input.data(), std::min(input.size(), sizeof(IoctlSubmit)));
86 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);
87 81
88 // Instantiate param buffers 82 // Instantiate param buffers
@@ -93,12 +87,12 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, std
93 std::vector<u32> fence_thresholds(params.fence_count); 87 std::vector<u32> fence_thresholds(params.fence_count);
94 88
95 // Slice input into their respective buffers 89 // Slice input into their respective buffers
96 std::size_t offset = sizeof(IoctlSubmit); 90 std::size_t offset = 0;
97 offset += SliceVectors(input, command_buffers, params.cmd_buffer_count, offset); 91 offset += SliceVectors(data, command_buffers, params.cmd_buffer_count, offset);
98 offset += SliceVectors(input, relocs, params.relocation_count, offset); 92 offset += SliceVectors(data, relocs, params.relocation_count, offset);
99 offset += SliceVectors(input, reloc_shifts, params.relocation_count, offset); 93 offset += SliceVectors(data, reloc_shifts, params.relocation_count, offset);
100 offset += SliceVectors(input, syncpt_increments, params.syncpoint_count, offset); 94 offset += SliceVectors(data, syncpt_increments, params.syncpoint_count, offset);
101 offset += SliceVectors(input, fence_thresholds, params.fence_count, offset); 95 offset += SliceVectors(data, fence_thresholds, params.fence_count, offset);
102 96
103 auto& gpu = system.GPU(); 97 auto& gpu = system.GPU();
104 if (gpu.UseNvdec()) { 98 if (gpu.UseNvdec()) {
@@ -116,14 +110,13 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, std
116 cmdlist.size() * sizeof(u32)); 110 cmdlist.size() * sizeof(u32));
117 gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist); 111 gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist);
118 } 112 }
119 std::memcpy(output.data(), &params, sizeof(IoctlSubmit));
120 // Some games expect command_buffers to be written back 113 // Some games expect command_buffers to be written back
121 offset = sizeof(IoctlSubmit); 114 offset = 0;
122 offset += WriteVectors(output, command_buffers, offset); 115 offset += WriteVectors(data, command_buffers, offset);
123 offset += WriteVectors(output, relocs, offset); 116 offset += WriteVectors(data, relocs, offset);
124 offset += WriteVectors(output, reloc_shifts, offset); 117 offset += WriteVectors(data, reloc_shifts, offset);
125 offset += WriteVectors(output, syncpt_increments, offset); 118 offset += WriteVectors(data, syncpt_increments, offset);
126 offset += WriteVectors(output, fence_thresholds, offset); 119 offset += WriteVectors(data, fence_thresholds, offset);
127 120
128 return NvResult::Success; 121 return NvResult::Success;
129} 122}
@@ -140,40 +133,24 @@ NvResult nvhost_nvdec_common::GetWaitbase(IoctlGetWaitbase& params) {
140 return NvResult::Success; 133 return NvResult::Success;
141} 134}
142 135
143NvResult nvhost_nvdec_common::MapBuffer(std::span<const u8> input, std::span<u8> output) { 136NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries) {
144 IoctlMapBuffer params{}; 137 const size_t num_entries = std::min(params.num_entries, static_cast<u32>(entries.size()));
145 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer)); 138 for (size_t i = 0; i < num_entries; i++) {
146 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); 139 entries[i].map_address = nvmap.PinHandle(entries[i].map_handle);
147
148 SliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
149
150 for (auto& cmd_buffer : cmd_buffer_handles) {
151 cmd_buffer.map_address = nvmap.PinHandle(cmd_buffer.map_handle);
152 } 140 }
153 141
154 if (output.size() <
155 sizeof(IoctlMapBuffer) + cmd_buffer_handles.size() * sizeof(MapBufferEntry)) {
156 return NvResult::InvalidSize;
157 }
158
159 std::memcpy(output.data(), &params, sizeof(IoctlMapBuffer));
160 std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(),
161 cmd_buffer_handles.size() * sizeof(MapBufferEntry));
162
163 return NvResult::Success; 142 return NvResult::Success;
164} 143}
165 144
166NvResult nvhost_nvdec_common::UnmapBuffer(std::span<const u8> input, std::span<u8> output) { 145NvResult nvhost_nvdec_common::UnmapBuffer(IoctlMapBuffer& params,
167 IoctlMapBuffer params{}; 146 std::span<MapBufferEntry> entries) {
168 std::memcpy(&params, input.data(), std::min(input.size(), sizeof(IoctlMapBuffer))); 147 const size_t num_entries = std::min(params.num_entries, static_cast<u32>(entries.size()));
169 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); 148 for (size_t i = 0; i < num_entries; i++) {
170 149 nvmap.UnpinHandle(entries[i].map_handle);
171 SliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer)); 150 entries[i] = {};
172 for (auto& cmd_buffer : cmd_buffer_handles) {
173 nvmap.UnpinHandle(cmd_buffer.map_handle);
174 } 151 }
175 152
176 std::memset(output.data(), 0, output.size()); 153 params = {};
177 return NvResult::Success; 154 return NvResult::Success;
178} 155}
179 156
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 cc988b897..7ce748e18 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
@@ -108,11 +108,11 @@ protected:
108 108
109 /// Ioctl command implementations 109 /// Ioctl command implementations
110 NvResult SetNVMAPfd(IoctlSetNvmapFD&); 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(IoctlGetSyncpoint& params); 112 NvResult GetSyncpoint(IoctlGetSyncpoint& params);
113 NvResult GetWaitbase(IoctlGetWaitbase& params); 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(u32 timeout); 116 NvResult SetSubmitTimeout(u32 timeout);
117 117
118 Kernel::KEvent* QueryEvent(u32 event_id) override; 118 Kernel::KEvent* QueryEvent(u32 event_id) override;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
index 23a57c4d5..9e6b86458 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
@@ -19,7 +19,7 @@ NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
19 case 'H': 19 case 'H':
20 switch (command.cmd) { 20 switch (command.cmd) {
21 case 0x1: 21 case 0x1:
22 return Wrap1(&nvhost_nvjpg::SetNVMAPfd, input, output); 22 return WrapFixed(this, &nvhost_nvjpg::SetNVMAPfd, input, output);
23 default: 23 default:
24 break; 24 break;
25 } 25 }
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index 20af75872..87f8d7c22 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -26,16 +26,16 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
26 if (!host1x_file.fd_to_id.contains(fd)) { 26 if (!host1x_file.fd_to_id.contains(fd)) {
27 host1x_file.fd_to_id[fd] = host1x_file.vic_next_id++; 27 host1x_file.fd_to_id[fd] = host1x_file.vic_next_id++;
28 } 28 }
29 return Submit(fd, input, output); 29 return WrapFixedVariable(this, &nvhost_vic::Submit, input, output, fd);
30 } 30 }
31 case 0x2: 31 case 0x2:
32 return Wrap1(&nvhost_vic::GetSyncpoint, input, output); 32 return WrapFixed(this, &nvhost_vic::GetSyncpoint, input, output);
33 case 0x3: 33 case 0x3:
34 return Wrap1(&nvhost_vic::GetWaitbase, input, output); 34 return WrapFixed(this, &nvhost_vic::GetWaitbase, input, output);
35 case 0x9: 35 case 0x9:
36 return MapBuffer(input, output); 36 return WrapFixedVariable(this, &nvhost_vic::MapBuffer, input, output);
37 case 0xa: 37 case 0xa:
38 return UnmapBuffer(input, output); 38 return WrapFixedVariable(this, &nvhost_vic::UnmapBuffer, input, output);
39 default: 39 default:
40 break; 40 break;
41 } 41 }
@@ -43,7 +43,7 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
43 case 'H': 43 case 'H':
44 switch (command.cmd) { 44 switch (command.cmd) {
45 case 0x1: 45 case 0x1:
46 return Wrap1(&nvhost_vic::SetNVMAPfd, input, output); 46 return WrapFixed(this, &nvhost_vic::SetNVMAPfd, input, output);
47 default: 47 default:
48 break; 48 break;
49 } 49 }
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index 94286e295..71b2e62ec 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -32,17 +32,17 @@ NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
32 case 0x1: 32 case 0x1:
33 switch (command.cmd) { 33 switch (command.cmd) {
34 case 0x1: 34 case 0x1:
35 return Wrap1(&nvmap::IocCreate, input, output); 35 return WrapFixed(this, &nvmap::IocCreate, input, output);
36 case 0x3: 36 case 0x3:
37 return Wrap1(&nvmap::IocFromId, input, output); 37 return WrapFixed(this, &nvmap::IocFromId, input, output);
38 case 0x4: 38 case 0x4:
39 return Wrap1(&nvmap::IocAlloc, input, output); 39 return WrapFixed(this, &nvmap::IocAlloc, input, output);
40 case 0x5: 40 case 0x5:
41 return Wrap1(&nvmap::IocFree, input, output); 41 return WrapFixed(this, &nvmap::IocFree, input, output);
42 case 0x9: 42 case 0x9:
43 return Wrap1(&nvmap::IocParam, input, output); 43 return WrapFixed(this, &nvmap::IocParam, input, output);
44 case 0xe: 44 case 0xe:
45 return Wrap1(&nvmap::IocGetId, input, output); 45 return WrapFixed(this, &nvmap::IocGetId, input, output);
46 default: 46 default:
47 break; 47 break;
48 } 48 }