mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-29 15:15:30 +03:00
Introduce variable sized span support to nvdrv deserialisation
The element containing the size first needs to be saved to a save slot with Save<T, slotId>, it can then be read back later as the size of a span with SlotSizeSpan<T, slotId>. This is needed to support the Host1XChannel Submit IOCTL.
This commit is contained in:
parent
6eeaa343f8
commit
386a3447a8
@ -33,9 +33,9 @@ namespace skyline {
|
|||||||
template<typename Traits>
|
template<typename Traits>
|
||||||
constexpr span(const std::basic_string_view<T, Traits> &string) : std::span<T, Extent>(const_cast<T *>(string.data()), string.size()) {}
|
constexpr span(const std::basic_string_view<T, Traits> &string) : std::span<T, Extent>(const_cast<T *>(string.data()), string.size()) {}
|
||||||
|
|
||||||
template<typename Out>
|
template<typename Out, bool SkipSizeCheck = false>
|
||||||
constexpr Out &as() {
|
constexpr Out &as() {
|
||||||
if constexpr (Extent != std::dynamic_extent && sizeof(T) * Extent >= sizeof(Out))
|
if constexpr (SkipSizeCheck || (Extent != std::dynamic_extent && sizeof(T) * Extent >= sizeof(Out)))
|
||||||
return *reinterpret_cast<Out *>(span::data());
|
return *reinterpret_cast<Out *>(span::data());
|
||||||
|
|
||||||
if (span::size_bytes() >= sizeof(Out))
|
if (span::size_bytes() >= sizeof(Out))
|
||||||
|
@ -9,26 +9,37 @@
|
|||||||
|
|
||||||
namespace skyline::service::nvdrv::deserialisation {
|
namespace skyline::service::nvdrv::deserialisation {
|
||||||
template<typename Desc, typename ArgType> requires (Desc::In && IsIn<ArgType>::value)
|
template<typename Desc, typename ArgType> requires (Desc::In && IsIn<ArgType>::value)
|
||||||
constexpr ArgType DecodeArgument(span<u8, Desc::Size> buffer, size_t &offset) {
|
constexpr ArgType DecodeArgument(span<u8, Desc::Size> buffer, size_t &offset, std::array<size_t, NumSaveSlots> &saveSlots) {
|
||||||
auto out{buffer.subspan(offset).template as<ArgType>()};
|
auto out{buffer.subspan(offset).template as<ArgType, true>()};
|
||||||
offset += sizeof(ArgType);
|
offset += sizeof(ArgType);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Desc, typename ArgType> requires (Desc::Out && Desc::In && IsInOut<ArgType>::value)
|
template<typename Desc, typename ArgType> requires (Desc::Out && Desc::In && IsInOut<ArgType>::value)
|
||||||
constexpr ArgType DecodeArgument(span<u8, Desc::Size> buffer, size_t &offset) {
|
constexpr ArgType DecodeArgument(span<u8, Desc::Size> buffer, size_t &offset, std::array<size_t, NumSaveSlots> &saveSlots) {
|
||||||
auto &out{buffer.subspan(offset).template as<RemoveInOut<ArgType>>()};
|
auto &out{buffer.subspan(offset).template as<RemoveInOut<ArgType>, true>()};
|
||||||
offset += sizeof(RemoveInOut<ArgType>);
|
offset += sizeof(RemoveInOut<ArgType>);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Desc, typename ArgType> requires (Desc::Out && IsOut<ArgType>::value)
|
template<typename Desc, typename ArgType> requires (Desc::Out && IsOut<ArgType>::value)
|
||||||
constexpr ArgType DecodeArgument(span<u8, Desc::Size> buffer, size_t &offset) {
|
constexpr ArgType DecodeArgument(span<u8, Desc::Size> buffer, size_t &offset, std::array<size_t, NumSaveSlots> &saveSlots) {
|
||||||
auto out{Out(buffer.subspan(offset).template as<RemoveOut<ArgType>>())};
|
auto out{Out(buffer.subspan(offset).template as<RemoveOut<ArgType>, true>())};
|
||||||
offset += sizeof(RemoveOut<ArgType>);
|
offset += sizeof(RemoveOut<ArgType>);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Desc, typename ArgType> requires (IsSlotSizeSpan<ArgType>::value)
|
||||||
|
constexpr auto DecodeArgument(span<u8, Desc::Size> buffer, size_t &offset, std::array<size_t, NumSaveSlots> &saveSlots) {
|
||||||
|
size_t bytes{saveSlots[ArgType::SaveSlot] * sizeof(RemoveSlotSizeSpan<ArgType>)};
|
||||||
|
auto out{buffer.subspan(offset, bytes).template cast<RemoveSlotSizeSpan<ArgType>, std::dynamic_extent, true>()};
|
||||||
|
offset += bytes;
|
||||||
|
|
||||||
|
|
||||||
|
// Return a simple `span` as that will be the function argument type as opposed to `SlotSizeSpan`
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates a reference preserving tuple of the given types
|
* @brief Creates a reference preserving tuple of the given types
|
||||||
*/
|
*/
|
||||||
@ -37,23 +48,27 @@ namespace skyline::service::nvdrv::deserialisation {
|
|||||||
return std::tuple<Ts...>{std::forward<Ts>(ts)...};
|
return std::tuple<Ts...>{std::forward<Ts>(ts)...};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename Desc, typename ArgType, typename... ArgTypes>
|
template<typename Desc, typename ArgType, typename... ArgTypes>
|
||||||
constexpr auto DecodeArgumentsImpl(span<u8, Desc::Size> buffer, size_t &offset) {
|
constexpr auto DecodeArgumentsImpl(span<u8, Desc::Size> buffer, size_t &offset, std::array<size_t, NumSaveSlots> &saveSlots) {
|
||||||
|
|
||||||
if constexpr (IsAutoSizeSpan<ArgType>::value) {
|
if constexpr (IsAutoSizeSpan<ArgType>::value) {
|
||||||
// AutoSizeSpan needs to be the last argument
|
// AutoSizeSpan needs to be the last argument
|
||||||
static_assert(sizeof...(ArgTypes) == 0);
|
static_assert(sizeof...(ArgTypes) == 0);
|
||||||
size_t bytes{buffer.size() - offset};
|
return make_ref_tuple(buffer.subspan(offset).template cast<RemoveAutoSizeSpan<ArgType>, std::dynamic_extent, true>());
|
||||||
size_t extent{bytes / sizeof(RemoveAutoSizeSpan<ArgType>)};
|
|
||||||
return make_ref_tuple(buffer.subspan(offset, extent * sizeof(RemoveAutoSizeSpan<ArgType>)).template cast<RemoveAutoSizeSpan<ArgType>>());
|
|
||||||
} else if constexpr (IsPad<ArgType>::value) {
|
} else if constexpr (IsPad<ArgType>::value) {
|
||||||
offset += ArgType::Bytes;
|
offset += ArgType::Bytes;
|
||||||
return DecodeArgumentsImpl<Desc, ArgTypes...>(buffer, offset);
|
return DecodeArgumentsImpl<Desc, ArgTypes...>(buffer, offset, saveSlots);
|
||||||
|
} else if constexpr (IsSave<ArgType>::value) {
|
||||||
|
saveSlots[ArgType::SaveSlot] = buffer.subspan(offset).template as<RemoveSave<ArgType>, true>();
|
||||||
|
offset += sizeof(RemoveSave<ArgType>);
|
||||||
|
return DecodeArgumentsImpl<Desc, ArgTypes...>(buffer, offset, saveSlots);
|
||||||
} else {
|
} else {
|
||||||
if constexpr(sizeof...(ArgTypes) == 0) {
|
if constexpr(sizeof...(ArgTypes) == 0) {
|
||||||
return make_ref_tuple(DecodeArgument<Desc, ArgType>(buffer, offset));
|
return make_ref_tuple(DecodeArgument<Desc, ArgType>(buffer, offset, saveSlots));
|
||||||
} else {
|
} else {
|
||||||
return std::tuple_cat(make_ref_tuple(DecodeArgument<Desc, ArgType>(buffer, offset)),
|
return std::tuple_cat(make_ref_tuple(DecodeArgument<Desc, ArgType>(buffer, offset, saveSlots)),
|
||||||
DecodeArgumentsImpl<Desc, ArgTypes...>(buffer, offset));
|
DecodeArgumentsImpl<Desc, ArgTypes...>(buffer, offset, saveSlots));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,6 +81,7 @@ namespace skyline::service::nvdrv::deserialisation {
|
|||||||
template<typename Desc, typename... ArgTypes>
|
template<typename Desc, typename... ArgTypes>
|
||||||
constexpr auto DecodeArguments(span<u8, Desc::Size> buffer) {
|
constexpr auto DecodeArguments(span<u8, Desc::Size> buffer) {
|
||||||
size_t offset{};
|
size_t offset{};
|
||||||
return DecodeArgumentsImpl<Desc, ArgTypes...>(buffer, offset);
|
std::array<size_t, NumSaveSlots> saveSlots{}; // No need to zero init as used slots will always be loaded first
|
||||||
|
return DecodeArgumentsImpl<Desc, ArgTypes...>(buffer, offset, saveSlots);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -63,7 +63,38 @@ namespace skyline::service::nvdrv::deserialisation {
|
|||||||
template<typename T> requires IsOut<T>::value
|
template<typename T> requires IsOut<T>::value
|
||||||
using RemoveOut = typename T::ValueType;
|
using RemoveOut = typename T::ValueType;
|
||||||
|
|
||||||
|
// Padding template types
|
||||||
|
template<typename T, size_t Count = 1> requires BufferData<T>
|
||||||
|
struct Pad {
|
||||||
|
static constexpr auto Bytes{Count * sizeof(T)};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename>
|
||||||
|
struct IsPad : std::false_type {};
|
||||||
|
|
||||||
|
template<typename T, size_t TCount>
|
||||||
|
struct IsPad<Pad<T, TCount>> : std::true_type {};
|
||||||
|
|
||||||
|
// Save to slot template types
|
||||||
|
constexpr size_t NumSaveSlots{10}; //!< Number of slots to save temporary values in during argument decoding
|
||||||
|
|
||||||
|
template<typename T, size_t TSaveSlot> requires (std::is_integral_v<T> && TSaveSlot < NumSaveSlots)
|
||||||
|
struct Save {
|
||||||
|
using SaveType = T;
|
||||||
|
|
||||||
|
static constexpr auto SaveSlot{TSaveSlot};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename>
|
||||||
|
struct IsSave : std::false_type {};
|
||||||
|
|
||||||
|
template<typename T, size_t SaveSlot>
|
||||||
|
struct IsSave<Save<T, SaveSlot>> : std::true_type {};
|
||||||
|
|
||||||
|
template<typename T> requires IsSave<T>::value
|
||||||
|
using RemoveSave = typename T::SaveType;
|
||||||
|
|
||||||
|
// Span template types
|
||||||
template<typename T> requires BufferData<T>
|
template<typename T> requires BufferData<T>
|
||||||
using AutoSizeSpan = span<T>;
|
using AutoSizeSpan = span<T>;
|
||||||
|
|
||||||
@ -76,17 +107,21 @@ namespace skyline::service::nvdrv::deserialisation {
|
|||||||
template<typename T> requires IsAutoSizeSpan<T>::value
|
template<typename T> requires IsAutoSizeSpan<T>::value
|
||||||
using RemoveAutoSizeSpan = typename T::element_type;
|
using RemoveAutoSizeSpan = typename T::element_type;
|
||||||
|
|
||||||
// Padding template type
|
template<typename T, size_t TSaveSlot> requires (BufferData<T> && TSaveSlot < NumSaveSlots)
|
||||||
template<typename T, size_t Count = 1> requires BufferData<T>
|
struct SlotSizeSpan {
|
||||||
struct Pad {
|
static constexpr auto SaveSlot{TSaveSlot};
|
||||||
static constexpr auto Bytes{Count * sizeof(T)};
|
|
||||||
|
using ValueType = T;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename>
|
template<typename>
|
||||||
struct IsPad : std::false_type {};
|
struct IsSlotSizeSpan : std::false_type {};
|
||||||
|
|
||||||
template<typename T, size_t TCount>
|
template<typename T, size_t SaveSlot>
|
||||||
struct IsPad<Pad<T, TCount>> : std::true_type {};
|
struct IsSlotSizeSpan<SlotSizeSpan<T, SaveSlot>> : std::true_type {};
|
||||||
|
|
||||||
|
template<typename T> requires IsSlotSizeSpan<T>::value
|
||||||
|
using RemoveSlotSizeSpan = typename T::ValueType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Describes an IOCTL as a type for use in deserialisation
|
* @brief Describes an IOCTL as a type for use in deserialisation
|
||||||
|
Loading…
Reference in New Issue
Block a user