From 723df0f3685f01ce5a0330d567932136a9de7a8f Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 25 Oct 2023 00:34:40 -0400 Subject: nvdrv: rework to remove memcpy --- .../service/nvdrv/devices/ioctl_serialization.h | 180 +++++++++++++-------- 1 file changed, 116 insertions(+), 64 deletions(-) (limited to 'src/core/hle/service/nvdrv/devices/ioctl_serialization.h') 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 - static T GetClassImpl(R (T::*)(A)); - - template - static A GetArgImpl(R (T::*)(A)); +struct IoctlOneArgTraits { + template + static A GetFirstArgImpl(R (T::*)(A, B...)); }; -struct Ioctl23Traits { - template - static T GetClassImpl(R (T::*)(A, B)); +struct IoctlTwoArgTraits { + template + static A GetFirstArgImpl(R (T::*)(A, B, C...)); - template - static A GetArgImpl(R (T::*)(A, B)); + template + static B GetSecondArgImpl(R (T::*)(A, B, C...)); }; -template -struct ContainerType { - using ValueType = T; -}; +struct Null {}; -template -struct ContainerType { - using ValueType = T::value_type; -}; +// clang-format off -template -NvResult Wrap(std::span input, std::span output, Self* self, F&& callable, - Rest&&... rest) { - using Arg = ContainerType::ValueType; - constexpr bool ArgumentIsContainer = Common::IsContiguousContainer; - - // 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 +NvResult WrapGeneric(F&& callable, std::span input, std::span inline_input, std::span output, std::span inline_output) { + constexpr bool HasFixedArg = !std::is_same_v; + constexpr bool HasVarArg = !std::is_same_v; + constexpr bool HasInlInVarArg = !std::is_same_v; + constexpr bool HasInlOutVarArg = !std::is_same_v; + + // 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 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 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 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 inl_out_var_args(num_inl_out_var_args); + // Perform the call. - NvResult result; - if constexpr (ArgumentIsContainer) { - result = (self->*callable)(params, std::forward(rest)...); - } else { - result = (self->*callable)(params.front(), std::forward(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 -NvResult nvdevice::Wrap1(F&& callable, std::span input, std::span output) { - using Self = decltype(Ioctl1Traits::GetClassImpl(callable)); - using InnerArg = std::remove_reference_t; +template +NvResult WrapFixed(Self* self, F&& callable, std::span input, std::span output, Rest&&... rest) { + using FixedArg = typename std::remove_reference_t; + + const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult { + return (self->*callable)(fixed, std::forward(rest)...); + }; - return Wrap(input, output, static_cast(this), callable); + return WrapGeneric(std::move(Callable), input, {}, output, {}); } -template -NvResult nvdevice::Wrap2(F&& callable, std::span input, std::span inline_input, - std::span output) { - using Self = decltype(Ioctl23Traits::GetClassImpl(callable)); - using InnerArg = std::remove_reference_t; +template +NvResult WrapFixedInlOut(Self* self, F&& callable, std::span input, std::span output, std::span inline_output, Rest&&... rest) { + using FixedArg = typename std::remove_reference_t; + using InlOutVarArg = typename std::remove_reference_t::value_type; - return Wrap(input, output, static_cast(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)...); + }; + + return WrapGeneric(std::move(Callable), input, {}, output, inline_output); +} + +template +NvResult WrapVariable(Self* self, F&& callable, std::span input, std::span output, Rest&&... rest) { + using VarArg = typename std::remove_reference_t::value_type; + + const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult { + return (self->*callable)(var, std::forward(rest)...); + }; + + return WrapGeneric(std::move(Callable), input, {}, output, {}); } -template -NvResult nvdevice::Wrap3(F&& callable, std::span input, std::span output, - std::span inline_output) { - using Self = decltype(Ioctl23Traits::GetClassImpl(callable)); - using InnerArg = std::remove_reference_t; +template +NvResult WrapFixedVariable(Self* self, F&& callable, std::span input, std::span output, Rest&&... rest) { + using FixedArg = typename std::remove_reference_t; + using VarArg = typename std::remove_reference_t::value_type; + + const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult { + return (self->*callable)(fixed, var, std::forward(rest)...); + }; - return Wrap(input, output, static_cast(this), callable, inline_output); + return WrapGeneric(std::move(Callable), input, {}, output, {}); } +template +NvResult WrapFixedInlIn(Self* self, F&& callable, std::span input, std::span inline_input, std::span output, Rest&&... rest) { + using FixedArg = typename std::remove_reference_t; + using InlInVarArg = typename std::remove_reference_t::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)...); + }; + + return WrapGeneric(std::move(Callable), input, inline_input, output, {}); +} + +// clang-format on + } // namespace Service::Nvidia::Devices -- cgit v1.2.3