mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 09:51:48 +01: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>
|
||||
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() {
|
||||
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());
|
||||
|
||||
if (span::size_bytes() >= sizeof(Out))
|
||||
|
@ -9,26 +9,37 @@
|
||||
|
||||
namespace skyline::service::nvdrv::deserialisation {
|
||||
template<typename Desc, typename ArgType> requires (Desc::In && IsIn<ArgType>::value)
|
||||
constexpr ArgType DecodeArgument(span<u8, Desc::Size> buffer, size_t &offset) {
|
||||
auto out{buffer.subspan(offset).template as<ArgType>()};
|
||||
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, true>()};
|
||||
offset += sizeof(ArgType);
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename Desc, typename ArgType> requires (Desc::Out && Desc::In && IsInOut<ArgType>::value)
|
||||
constexpr ArgType DecodeArgument(span<u8, Desc::Size> buffer, size_t &offset) {
|
||||
auto &out{buffer.subspan(offset).template as<RemoveInOut<ArgType>>()};
|
||||
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>, true>()};
|
||||
offset += sizeof(RemoveInOut<ArgType>);
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename Desc, typename ArgType> requires (Desc::Out && IsOut<ArgType>::value)
|
||||
constexpr ArgType DecodeArgument(span<u8, Desc::Size> buffer, size_t &offset) {
|
||||
auto out{Out(buffer.subspan(offset).template as<RemoveOut<ArgType>>())};
|
||||
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>, true>())};
|
||||
offset += sizeof(RemoveOut<ArgType>);
|
||||
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
|
||||
*/
|
||||
@ -37,23 +48,27 @@ namespace skyline::service::nvdrv::deserialisation {
|
||||
return std::tuple<Ts...>{std::forward<Ts>(ts)...};
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
// AutoSizeSpan needs to be the last argument
|
||||
static_assert(sizeof...(ArgTypes) == 0);
|
||||
size_t bytes{buffer.size() - offset};
|
||||
size_t extent{bytes / sizeof(RemoveAutoSizeSpan<ArgType>)};
|
||||
return make_ref_tuple(buffer.subspan(offset, extent * sizeof(RemoveAutoSizeSpan<ArgType>)).template cast<RemoveAutoSizeSpan<ArgType>>());
|
||||
return make_ref_tuple(buffer.subspan(offset).template cast<RemoveAutoSizeSpan<ArgType>, std::dynamic_extent, true>());
|
||||
} else if constexpr (IsPad<ArgType>::value) {
|
||||
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 {
|
||||
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 {
|
||||
return std::tuple_cat(make_ref_tuple(DecodeArgument<Desc, ArgType>(buffer, offset)),
|
||||
DecodeArgumentsImpl<Desc, ArgTypes...>(buffer, offset));
|
||||
return std::tuple_cat(make_ref_tuple(DecodeArgument<Desc, ArgType>(buffer, offset, saveSlots)),
|
||||
DecodeArgumentsImpl<Desc, ArgTypes...>(buffer, offset, saveSlots));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -66,6 +81,7 @@ namespace skyline::service::nvdrv::deserialisation {
|
||||
template<typename Desc, typename... ArgTypes>
|
||||
constexpr auto DecodeArguments(span<u8, Desc::Size> buffer) {
|
||||
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
|
||||
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>
|
||||
using AutoSizeSpan = span<T>;
|
||||
|
||||
@ -76,17 +107,21 @@ namespace skyline::service::nvdrv::deserialisation {
|
||||
template<typename T> requires IsAutoSizeSpan<T>::value
|
||||
using RemoveAutoSizeSpan = typename T::element_type;
|
||||
|
||||
// Padding template type
|
||||
template<typename T, size_t Count = 1> requires BufferData<T>
|
||||
struct Pad {
|
||||
static constexpr auto Bytes{Count * sizeof(T)};
|
||||
template<typename T, size_t TSaveSlot> requires (BufferData<T> && TSaveSlot < NumSaveSlots)
|
||||
struct SlotSizeSpan {
|
||||
static constexpr auto SaveSlot{TSaveSlot};
|
||||
|
||||
using ValueType = T;
|
||||
};
|
||||
|
||||
template<typename>
|
||||
struct IsPad : std::false_type {};
|
||||
struct IsSlotSizeSpan : std::false_type {};
|
||||
|
||||
template<typename T, size_t TCount>
|
||||
struct IsPad<Pad<T, TCount>> : std::true_type {};
|
||||
template<typename T, size_t SaveSlot>
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user