summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/nvdrv/devices/ioctl_serialization.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/hle/service/nvdrv/devices/ioctl_serialization.h180
1 files changed, 116 insertions, 64 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 @@
namespace Service::Nvidia::Devices {
-struct Ioctl1Traits {
- template <typename T, typename R, typename A>
- static T GetClassImpl(R (T::*)(A));
-
- template <typename T, typename R, typename A>
- static A GetArgImpl(R (T::*)(A));
+struct IoctlOneArgTraits {
+ template <typename T, typename R, typename A, typename... B>
+ static A GetFirstArgImpl(R (T::*)(A, B...));
};
-struct Ioctl23Traits {
- template <typename T, typename R, typename A, typename B>
- static T GetClassImpl(R (T::*)(A, B));
+struct IoctlTwoArgTraits {
+ template <typename T, typename R, typename A, typename B, typename... C>
+ static A GetFirstArgImpl(R (T::*)(A, B, C...));
- template <typename T, typename R, typename A, typename B>
- static A GetArgImpl(R (T::*)(A, B));
+ template <typename T, typename R, typename A, typename B, typename... C>
+ static B GetSecondArgImpl(R (T::*)(A, B, C...));
};
-template <typename T>
-struct ContainerType {
- using ValueType = T;
-};
+struct Null {};
-template <Common::IsContiguousContainer T>
-struct ContainerType<T> {
- using ValueType = T::value_type;
-};
+// clang-format off
-template <typename InnerArg, typename F, typename Self, typename... Rest>
-NvResult Wrap(std::span<const u8> input, std::span<u8> output, Self* self, F&& callable,
- Rest&&... rest) {
- using Arg = ContainerType<InnerArg>::ValueType;
- constexpr bool ArgumentIsContainer = Common::IsContiguousContainer<InnerArg>;
-
- // Verify that the input and output sizes are valid.
- const size_t in_params = input.size() / sizeof(Arg);
- const size_t out_params = output.size() / sizeof(Arg);
- if (in_params * sizeof(Arg) != input.size()) {
- return NvResult::InvalidSize;
- }
- if (out_params * sizeof(Arg) != output.size()) {
- return NvResult::InvalidSize;
+template <typename FixedArg, typename VarArg, typename InlInVarArg, typename InlOutVarArg, typename F>
+NvResult WrapGeneric(F&& callable, std::span<const u8> input, std::span<const u8> inline_input, std::span<u8> output, std::span<u8> inline_output) {
+ constexpr bool HasFixedArg = !std::is_same_v<FixedArg, Null>;
+ constexpr bool HasVarArg = !std::is_same_v<VarArg, Null>;
+ constexpr bool HasInlInVarArg = !std::is_same_v<InlInVarArg, Null>;
+ constexpr bool HasInlOutVarArg = !std::is_same_v<InlOutVarArg, Null>;
+
+ // Declare the fixed-size input value.
+ FixedArg fixed{};
+ size_t var_offset = 0;
+
+ if constexpr (HasFixedArg) {
+ // Read the fixed-size input value.
+ var_offset = std::min(sizeof(FixedArg), input.size());
+ if (var_offset > 0) {
+ std::memcpy(&fixed, input.data(), var_offset);
+ }
}
- if (in_params == 0 && out_params == 0 && !ArgumentIsContainer) {
- return NvResult::InvalidSize;
+
+ // Read the variable-sized inputs.
+ const size_t num_var_args = HasVarArg ? ((input.size() - var_offset) / sizeof(VarArg)) : 0;
+ std::vector<VarArg> var_args(num_var_args);
+ if constexpr (HasVarArg) {
+ if (num_var_args > 0) {
+ std::memcpy(var_args.data(), input.data() + var_offset, num_var_args * sizeof(VarArg));
+ }
}
- // Copy inputs, if needed.
- std::vector<Arg> params(std::max(in_params, out_params));
- if (in_params > 0) {
- std::memcpy(params.data(), input.data(), input.size());
+ const size_t num_inl_in_var_args = HasInlInVarArg ? (inline_input.size() / sizeof(InlInVarArg)) : 0;
+ std::vector<InlInVarArg> inl_in_var_args(num_inl_in_var_args);
+ if constexpr (HasInlInVarArg) {
+ if (num_inl_in_var_args > 0) {
+ std::memcpy(inl_in_var_args.data(), inline_input.data(), num_inl_in_var_args * sizeof(InlInVarArg));
+ }
}
+ // Construct inline output data.
+ const size_t num_inl_out_var_args = HasInlOutVarArg ? (inline_output.size() / sizeof(InlOutVarArg)) : 0;
+ std::vector<InlOutVarArg> inl_out_var_args(num_inl_out_var_args);
+
// Perform the call.
- NvResult result;
- if constexpr (ArgumentIsContainer) {
- result = (self->*callable)(params, std::forward<Rest>(rest)...);
- } else {
- result = (self->*callable)(params.front(), std::forward<Rest>(rest)...);
+ NvResult result = callable(fixed, var_args, inl_in_var_args, inl_out_var_args);
+
+ // Copy outputs.
+ if constexpr (HasFixedArg) {
+ if (output.size() > 0) {
+ std::memcpy(output.data(), &fixed, std::min(output.size(), sizeof(FixedArg)));
+ }
}
- // Copy outputs, if needed.
- if (out_params > 0) {
- std::memcpy(output.data(), params.data(), output.size());
+ if constexpr (HasVarArg) {
+ if (num_var_args > 0 && output.size() > var_offset) {
+ const size_t max_var_size = output.size() - var_offset;
+ std::memcpy(output.data() + var_offset, var_args.data(), std::min(max_var_size, num_var_args * sizeof(VarArg)));
+ }
}
+ // Copy inline outputs.
+ if constexpr (HasInlOutVarArg) {
+ if (num_inl_out_var_args > 0) {
+ std::memcpy(inline_output.data(), inl_out_var_args.data(), num_inl_out_var_args * sizeof(InlOutVarArg));
+ }
+ }
+
+ // We're done.
return result;
}
-template <typename F>
-NvResult nvdevice::Wrap1(F&& callable, std::span<const u8> input, std::span<u8> output) {
- using Self = decltype(Ioctl1Traits::GetClassImpl(callable));
- using InnerArg = std::remove_reference_t<decltype(Ioctl1Traits::GetArgImpl(callable))>;
+template <typename Self, typename F, typename... Rest>
+NvResult WrapFixed(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, Rest&&... rest) {
+ using FixedArg = typename std::remove_reference_t<decltype(IoctlOneArgTraits::GetFirstArgImpl(callable))>;
+
+ const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
+ return (self->*callable)(fixed, std::forward<Rest>(rest)...);
+ };
- return Wrap<InnerArg>(input, output, static_cast<Self*>(this), callable);
+ return WrapGeneric<FixedArg, Null, Null, Null>(std::move(Callable), input, {}, output, {});
}
-template <typename F>
-NvResult nvdevice::Wrap2(F&& callable, std::span<const u8> input, std::span<const u8> inline_input,
- std::span<u8> output) {
- using Self = decltype(Ioctl23Traits::GetClassImpl(callable));
- using InnerArg = std::remove_reference_t<decltype(Ioctl23Traits::GetArgImpl(callable))>;
+template <typename Self, typename F, typename... Rest>
+NvResult WrapFixedInlOut(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, std::span<u8> inline_output, Rest&&... rest) {
+ using FixedArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetFirstArgImpl(callable))>;
+ using InlOutVarArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetSecondArgImpl(callable))>::value_type;
- return Wrap<InnerArg>(input, output, static_cast<Self*>(this), callable, inline_input);
+ const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
+ return (self->*callable)(fixed, inl_out, std::forward<Rest>(rest)...);
+ };
+
+ return WrapGeneric<FixedArg, Null, Null, InlOutVarArg>(std::move(Callable), input, {}, output, inline_output);
+}
+
+template <typename Self, typename F, typename... Rest>
+NvResult WrapVariable(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, Rest&&... rest) {
+ using VarArg = typename std::remove_reference_t<decltype(IoctlOneArgTraits::GetFirstArgImpl(callable))>::value_type;
+
+ const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
+ return (self->*callable)(var, std::forward<Rest>(rest)...);
+ };
+
+ return WrapGeneric<Null, VarArg, Null, Null>(std::move(Callable), input, {}, output, {});
}
-template <typename F>
-NvResult nvdevice::Wrap3(F&& callable, std::span<const u8> input, std::span<u8> output,
- std::span<u8> inline_output) {
- using Self = decltype(Ioctl23Traits::GetClassImpl(callable));
- using InnerArg = std::remove_reference_t<decltype(Ioctl23Traits::GetArgImpl(callable))>;
+template <typename Self, typename F, typename... Rest>
+NvResult WrapFixedVariable(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, Rest&&... rest) {
+ using FixedArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetFirstArgImpl(callable))>;
+ using VarArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetSecondArgImpl(callable))>::value_type;
+
+ const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
+ return (self->*callable)(fixed, var, std::forward<Rest>(rest)...);
+ };
- return Wrap<InnerArg>(input, output, static_cast<Self*>(this), callable, inline_output);
+ return WrapGeneric<FixedArg, VarArg, Null, Null>(std::move(Callable), input, {}, output, {});
}
+template <typename Self, typename F, typename... Rest>
+NvResult WrapFixedInlIn(Self* self, F&& callable, std::span<const u8> input, std::span<const u8> inline_input, std::span<u8> output, Rest&&... rest) {
+ using FixedArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetFirstArgImpl(callable))>;
+ using InlInVarArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetSecondArgImpl(callable))>::value_type;
+
+ const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
+ return (self->*callable)(fixed, inl_in, std::forward<Rest>(rest)...);
+ };
+
+ return WrapGeneric<FixedArg, Null, InlInVarArg, Null>(std::move(Callable), input, inline_input, output, {});
+}
+
+// clang-format on
+
} // namespace Service::Nvidia::Devices