diff --git a/app/src/main/cpp/skyline/common/span.h b/app/src/main/cpp/skyline/common/span.h index 47e06b05..f838c727 100644 --- a/app/src/main/cpp/skyline/common/span.h +++ b/app/src/main/cpp/skyline/common/span.h @@ -33,9 +33,9 @@ namespace skyline { template constexpr span(const std::basic_string_view &string) : std::span(const_cast(string.data()), string.size()) {} - template + template 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(span::data()); if (span::size_bytes() >= sizeof(Out)) diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/deserialisation/deserialisation.h b/app/src/main/cpp/skyline/services/nvdrv/devices/deserialisation/deserialisation.h index b2eb5937..a235f698 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/deserialisation/deserialisation.h +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/deserialisation/deserialisation.h @@ -9,26 +9,37 @@ namespace skyline::service::nvdrv::deserialisation { template requires (Desc::In && IsIn::value) - constexpr ArgType DecodeArgument(span buffer, size_t &offset) { - auto out{buffer.subspan(offset).template as()}; + constexpr ArgType DecodeArgument(span buffer, size_t &offset, std::array &saveSlots) { + auto out{buffer.subspan(offset).template as()}; offset += sizeof(ArgType); return out; } template requires (Desc::Out && Desc::In && IsInOut::value) - constexpr ArgType DecodeArgument(span buffer, size_t &offset) { - auto &out{buffer.subspan(offset).template as>()}; + constexpr ArgType DecodeArgument(span buffer, size_t &offset, std::array &saveSlots) { + auto &out{buffer.subspan(offset).template as, true>()}; offset += sizeof(RemoveInOut); return out; } template requires (Desc::Out && IsOut::value) - constexpr ArgType DecodeArgument(span buffer, size_t &offset) { - auto out{Out(buffer.subspan(offset).template as>())}; + constexpr ArgType DecodeArgument(span buffer, size_t &offset, std::array &saveSlots) { + auto out{Out(buffer.subspan(offset).template as, true>())}; offset += sizeof(RemoveOut); return out; } + template requires (IsSlotSizeSpan::value) + constexpr auto DecodeArgument(span buffer, size_t &offset, std::array &saveSlots) { + size_t bytes{saveSlots[ArgType::SaveSlot] * sizeof(RemoveSlotSizeSpan)}; + auto out{buffer.subspan(offset, bytes).template cast, 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{std::forward(ts)...}; } + template - constexpr auto DecodeArgumentsImpl(span buffer, size_t &offset) { + constexpr auto DecodeArgumentsImpl(span buffer, size_t &offset, std::array &saveSlots) { + if constexpr (IsAutoSizeSpan::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)}; - return make_ref_tuple(buffer.subspan(offset, extent * sizeof(RemoveAutoSizeSpan)).template cast>()); + return make_ref_tuple(buffer.subspan(offset).template cast, std::dynamic_extent, true>()); } else if constexpr (IsPad::value) { offset += ArgType::Bytes; - return DecodeArgumentsImpl(buffer, offset); + return DecodeArgumentsImpl(buffer, offset, saveSlots); + } else if constexpr (IsSave::value) { + saveSlots[ArgType::SaveSlot] = buffer.subspan(offset).template as, true>(); + offset += sizeof(RemoveSave); + return DecodeArgumentsImpl(buffer, offset, saveSlots); } else { if constexpr(sizeof...(ArgTypes) == 0) { - return make_ref_tuple(DecodeArgument(buffer, offset)); + return make_ref_tuple(DecodeArgument(buffer, offset, saveSlots)); } else { - return std::tuple_cat(make_ref_tuple(DecodeArgument(buffer, offset)), - DecodeArgumentsImpl(buffer, offset)); + return std::tuple_cat(make_ref_tuple(DecodeArgument(buffer, offset, saveSlots)), + DecodeArgumentsImpl(buffer, offset, saveSlots)); } } } @@ -66,6 +81,7 @@ namespace skyline::service::nvdrv::deserialisation { template constexpr auto DecodeArguments(span buffer) { size_t offset{}; - return DecodeArgumentsImpl(buffer, offset); + std::array saveSlots{}; // No need to zero init as used slots will always be loaded first + return DecodeArgumentsImpl(buffer, offset, saveSlots); } } \ No newline at end of file diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/deserialisation/types.h b/app/src/main/cpp/skyline/services/nvdrv/devices/deserialisation/types.h index ea5761cf..553c6a05 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/deserialisation/types.h +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/deserialisation/types.h @@ -63,7 +63,38 @@ namespace skyline::service::nvdrv::deserialisation { template requires IsOut::value using RemoveOut = typename T::ValueType; + // Padding template types + template requires BufferData + struct Pad { + static constexpr auto Bytes{Count * sizeof(T)}; + }; + template + struct IsPad : std::false_type {}; + + template + struct IsPad> : 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 requires (std::is_integral_v && TSaveSlot < NumSaveSlots) + struct Save { + using SaveType = T; + + static constexpr auto SaveSlot{TSaveSlot}; + }; + + template + struct IsSave : std::false_type {}; + + template + struct IsSave> : std::true_type {}; + + template requires IsSave::value + using RemoveSave = typename T::SaveType; + + // Span template types template requires BufferData using AutoSizeSpan = span; @@ -76,17 +107,21 @@ namespace skyline::service::nvdrv::deserialisation { template requires IsAutoSizeSpan::value using RemoveAutoSizeSpan = typename T::element_type; - // Padding template type - template requires BufferData - struct Pad { - static constexpr auto Bytes{Count * sizeof(T)}; + template requires (BufferData && TSaveSlot < NumSaveSlots) + struct SlotSizeSpan { + static constexpr auto SaveSlot{TSaveSlot}; + + using ValueType = T; }; template - struct IsPad : std::false_type {}; + struct IsSlotSizeSpan : std::false_type {}; - template - struct IsPad> : std::true_type {}; + template + struct IsSlotSizeSpan> : std::true_type {}; + + template requires IsSlotSizeSpan::value + using RemoveSlotSizeSpan = typename T::ValueType; /** * @brief Describes an IOCTL as a type for use in deserialisation