From e0b5339ddf41df3c7ca7b5c33f9507a455d902ec Mon Sep 17 00:00:00 2001 From: spacemeowx2 Date: Tue, 4 Dec 2018 16:08:42 +0800 Subject: [PATCH] Add SmartBuffers --- include/stratosphere/ipc/ipc_buffers.hpp | 35 +++++++++ .../stratosphere/ipc/ipc_serialization.hpp | 75 +++++++++++++++++-- 2 files changed, 102 insertions(+), 8 deletions(-) diff --git a/include/stratosphere/ipc/ipc_buffers.hpp b/include/stratosphere/ipc/ipc_buffers.hpp index 6bf2f71c..ed4962ac 100644 --- a/include/stratosphere/ipc/ipc_buffers.hpp +++ b/include/stratosphere/ipc/ipc_buffers.hpp @@ -115,3 +115,38 @@ struct OutPointerWithClientSize : public OutPointerWithClientSizeBase { OutPointerWithClientSize(void *p, size_t n) : pointer((T *)p), num_elements(n/sizeof(T)) { } }; + +struct InOutSmartBase : public IpcBufferBase {}; + +struct OutSmartBase : public InOutSmartBase {}; + +template +struct OutSmartBuffer : public OutSmartBase { + T *buffer; + size_t num_elements; + static const size_t element_size = sizeof(T); + + /* Convenience. */ + T& operator[](size_t i) const { + return buffer[i]; + } + + OutSmartBuffer(void *b, size_t n) : buffer((T *)b), num_elements(n/sizeof(T)) { } +}; + + +struct InSmartBase : public InOutSmartBase {}; + +template +struct InSmartBuffer : public InSmartBase { + T *buffer; + size_t num_elements; + static const size_t element_size = sizeof(T); + + /* Convenience. */ + T& operator[](size_t i) const { + return buffer[i]; + } + + InSmartBuffer(void *b, size_t n) : buffer((T *)b), num_elements(n/sizeof(T)) { } +}; \ No newline at end of file diff --git a/include/stratosphere/ipc/ipc_serialization.hpp b/include/stratosphere/ipc/ipc_serialization.hpp index dea01e8a..ffcd67fc 100644 --- a/include/stratosphere/ipc/ipc_serialization.hpp +++ b/include/stratosphere/ipc/ipc_serialization.hpp @@ -88,6 +88,8 @@ enum class ArgType { InPointer, OutPointerClientSize, OutPointerServerSize, + InSmartBuffer, + OutSmartBuffer, }; template @@ -102,6 +104,10 @@ constexpr ArgType GetArgType() { return ArgType::InBuffer; } else if constexpr (std::is_base_of_v) { return ArgType::OutBuffer; + } else if constexpr (std::is_base_of_v) { + return ArgType::InSmartBuffer; + } else if constexpr (std::is_base_of_v) { + return ArgType::OutSmartBuffer; } else if constexpr (std::is_base_of_v) { return ArgType::InPointer; } else if constexpr (std::is_base_of_v) { @@ -128,7 +134,7 @@ struct ArgTypeFilter { template struct IsArgTypeBuffer { - static constexpr bool value = ArgT == ArgType::InBuffer || ArgT == ArgType::OutBuffer || ArgT == ArgType::InPointer || ArgT == ArgType::OutPointerClientSize || ArgT == ArgType::OutPointerServerSize; + static constexpr bool value = ArgT == ArgType::InBuffer || ArgT == ArgType::OutBuffer || ArgT == ArgType::InPointer || ArgT == ArgType::OutPointerClientSize || ArgT == ArgType::OutPointerServerSize || ArgT == ArgType::InSmartBuffer || ArgT == ArgType::OutSmartBuffer; }; struct ArgTypeBufferFilter { @@ -264,6 +270,8 @@ struct CommandMetaInfo, _ReturnType> { using InPointers = FilteredTypes::type, _Args...>; using ClientSizeOutPointers = FilteredTypes::type, _Args...>; using ServerSizeOutPointers = FilteredTypes::type, _Args...>; + using InSmarts = FilteredTypes::type, _Args...>; + using OutSmarts = FilteredTypes::type, _Args...>; using Buffers = FilteredTypes; static constexpr size_t NumInDatas = std::tuple_size_v; @@ -274,10 +282,12 @@ struct CommandMetaInfo, _ReturnType> { static constexpr size_t NumOutSessions = std::tuple_size_v; static constexpr size_t NumPidDescs = std::tuple_size_v; - static constexpr size_t NumInBuffers = std::tuple_size_v; - static constexpr size_t NumOutBuffers = std::tuple_size_v; - static constexpr size_t NumInPointers = std::tuple_size_v; - static constexpr size_t NumClientSizeOutPointers = std::tuple_size_v; + static constexpr size_t NumInSmarts = std::tuple_size_v; + static constexpr size_t NumOutSmarts = std::tuple_size_v; + static constexpr size_t NumInBuffers = std::tuple_size_v + NumInSmarts; + static constexpr size_t NumOutBuffers = std::tuple_size_v + NumOutSmarts; + static constexpr size_t NumInPointers = std::tuple_size_v + NumInSmarts; + static constexpr size_t NumClientSizeOutPointers = std::tuple_size_v + NumOutSmarts; static constexpr size_t NumServerSizeOutPointers = std::tuple_size_v; static constexpr size_t NumBuffers = std::tuple_size_v; @@ -317,10 +327,31 @@ struct Validator { } else if constexpr (std::is_same_v) { return ctx->request.WasHandleCopied[h_index++]; } + } else if constexpr (argT == ArgType::InSmartBuffer) { + if (ctx->request.BufferSizes[a_index] > 0) { + return ctx->request.Statics[x_index] == nullptr && ctx->request.StaticSizes[x_index++] == 0 + && ctx->request.Buffers[a_index] != nullptr && ctx->request.BufferDirections[a_index++] == BufferDirection_Send; + } else if (ctx->request.StaticSizes[x_index] > 0) { + return ctx->request.Buffers[a_index] == nullptr && ctx->request.BufferSizes[a_index++] == 0 + && ctx->request.Statics[x_index++] != nullptr; + } + return false; + } else if constexpr (argT == ArgType::OutSmartBuffer) { + if (ctx->request.BufferSizes[b_index] > 0) { + x_index++; + return ctx->request.Buffers[b_index] != nullptr + && ctx->request.BufferDirections[b_index++] == BufferDirection_Recv; + } else if (ctx->request.StaticSizes[x_index++] > 0) { + b_index++; + total_c_size += *((u16 *)((uintptr_t)(ctx->request.Raw) + 0x10 + cur_c_size_offset)); + cur_c_size_offset += sizeof(u16); + return true; + } + return false; } else { if constexpr (argT == ArgType::OutPointerServerSize) { total_c_size += T::num_elements * sizeof(T); - } else if constexpr (argT == ArgType::OutPointerServerSize) { + } else if constexpr (argT == ArgType::OutPointerClientSize) { total_c_size += *((u16 *)((uintptr_t)(ctx->request.Raw) + 0x10 + cur_c_size_offset)); cur_c_size_offset += sizeof(u16); } @@ -406,6 +437,34 @@ struct Decoder { const T& value = T(ctx->request.Statics[x_index], ctx->request.StaticSizes[x_index]); ++x_index; return value; + } else if constexpr (argT == ArgType::InSmartBuffer) { + if (ctx->request.BufferSizes[a_index] > 0) { + const T& value = T(ctx->request.Buffers[a_index], ctx->request.BufferSizes[a_index]); + ++a_index; + ++x_index; + return value; + } else { + const T& value = T(ctx->request.Statics[x_index], ctx->request.StaticSizes[x_index]); + ++a_index; + ++x_index; + return value; + } + } else if constexpr (argT == ArgType::OutSmartBuffer) { + if (ctx->request.BufferSizes[b_index] > 0) { + const T& value = T(ctx->request.Buffers[b_index], ctx->request.BufferSizes[b_index]); + ++b_index; + ++c_index; + return value; + } else { + u16 sz = *(const u16 *)((uintptr_t)ctx->request.Raw + 0x10 + c_sz_offset); + u8* buf = ctx->pb + pb_offset; + c_sz_offset += sizeof(u16); + pb_offset += sz; + ipcAddSendStatic(&ctx->reply, buf, sz, c_index); + ++b_index; + ++c_index; + return T(buf, sz); + } } else if constexpr (argT == ArgType::InHandle) { return T(ctx->request.Handles[in_h_index++]); } else if constexpr (argT == ArgType::OutHandle) { @@ -427,12 +486,12 @@ struct Decoder { } else if constexpr (argT == ArgType::OutPointerClientSize || argT == ArgType::OutPointerServerSize) { u16 sz; if constexpr(argT == ArgType::OutPointerServerSize) { - sz = T::element_size; + sz = T::element_size * T::num_elements; } else { sz = *(const u16 *)((uintptr_t)ctx->request.Raw + 0x10 + c_sz_offset); + c_sz_offset += sizeof(u16); } u8* buf = ctx->pb + pb_offset; - c_sz_offset += sizeof(u16); pb_offset += sz; ipcAddSendStatic(&ctx->reply, buf, sz, c_index++); return T(buf, sz);