diff --git a/libraries/libstratosphere/Makefile b/libraries/libstratosphere/Makefile index 37bac54f2..57acad73b 100644 --- a/libraries/libstratosphere/Makefile +++ b/libraries/libstratosphere/Makefile @@ -23,7 +23,7 @@ PRECOMPILED_HEADERS := $(CURRENT_DIRECTORY)/include/stratosphere.hpp DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_STRATOSPHERE -D_GNU_SOURCE SETTINGS := $(ATMOSPHERE_SETTINGS) -O2 CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) -CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -flto +CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) LDFLAGS := -specs=$(DEVKITPRO)/libnx/switch.specs $(SETTINGS) -Wl,-Map,$(notdir $*.map) diff --git a/libraries/libstratosphere/include/stratosphere/tipc.hpp b/libraries/libstratosphere/include/stratosphere/tipc.hpp index c8d6589f0..dc8227750 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc.hpp @@ -13,7 +13,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - #pragma once #include diff --git a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_command_serialization.hpp b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_command_serialization.hpp index 619812b85..09625e7a5 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_command_serialization.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_command_serialization.hpp @@ -15,6 +15,10 @@ */ #pragma once #include +#include +#include +#include +#include namespace ams::tipc { @@ -72,13 +76,13 @@ namespace ams::tipc::impl { constexpr inline ArgumentType GetArgumentType = [] { if constexpr (tipc::IsBuffer) { return ArgumentType::Buffer; - } else if constexpr (std::is_base_of::value) { + } else if constexpr (std::is_base_of::value) { return ArgumentType::InHandle; - } else if constexpr (std::is_base_of::value) { + } else if constexpr (std::is_base_of::value) { return ArgumentType::OutHandle; - } else if constexpr (std::is_base_of::value) { + } else if constexpr (std::is_base_of::value) { return ArgumentType::OutData; - } else if constexpr (std::same_as) { + } else if constexpr (std::same_as) { return ArgumentType::ProcessId; } else if constexpr (std::is_trivial::value && !std::is_pointer::value) { return ArgumentType::InData; @@ -111,21 +115,21 @@ namespace ams::tipc::impl { template using OutHandleFilter = ArgumentTypeFilter; + template + using ProcessIdFilter = ArgumentTypeFilter; + /* Handle kind filters. */ template - using InMoveHandleFilter = TypeEqualityFilter; + using InMoveHandleFilter = TypeEqualityFilter; template - using InCopyHandleFilter = TypeEqualityFilter; + using InCopyHandleFilter = TypeEqualityFilter; template - using OutMoveHandleFilter = TypeEqualityFilter>; + using OutMoveHandleFilter = TypeEqualityFilter>; template - using OutCopyHandleFilter = TypeEqualityFilter>; - - template - struct ProcessIdFilter = ArgumentTypeFilter; + using OutCopyHandleFilter = TypeEqualityFilter>; template struct BufferAttributeArrayGetter; @@ -236,7 +240,8 @@ namespace ams::tipc::impl { template struct CommandMetaInfo { public: - using CommandId = _CommandId; + static constexpr u16 CommandId = _CommandId; + using ArgsType = std::tuple::type...>; using InDatas = TupleFilter::FilteredType; @@ -257,7 +262,7 @@ namespace ams::tipc::impl { static_assert(NumBuffers <= 8, "Methods must take in <= 8 Buffers"); static_assert(NumInHandles <= 8, "Methods must take in <= 8 Handles"); - static_assert(NumOutHandles + NumOutObjects <= 8, "Methods must output <= 8 Handles"); + static_assert(NumOutHandles <= 8, "Methods must output <= 8 Handles"); /* Buffer marshalling. */ static constexpr std::array BufferAttributes = BufferAttributeArrayGetter::value; @@ -292,8 +297,8 @@ namespace ams::tipc::impl { /* tipc-specific accessors. */ static constexpr bool HasInSpecialHeader = HasProcessId || NumInHandles > 0; - static constexpr svc::ipc::MessageBuffer::MessageHeader InMessageHeader(CommandId, HasInSpecialHeader, 0, NumInBuffers, NumOutBuffers, 0, InDataSize / sizeof(u32), 0); - static constexpr svc::ipc::MessageBuffer::SpecialHeader InSpecialHeader(HasProcessId, NumInMoveHandles, NumInCopyHandles); + static constexpr svc::ipc::MessageBuffer::MessageHeader InMessageHeader{CommandId, HasInSpecialHeader, 0, NumInBuffers, NumOutBuffers, 0, InDataSize / sizeof(u32), 0}; + static constexpr svc::ipc::MessageBuffer::SpecialHeader InSpecialHeader{HasProcessId, NumInCopyHandles, NumInMoveHandles, HasInSpecialHeader}; static constexpr auto InMessageProcessIdIndex = svc::ipc::MessageBuffer::GetSpecialDataIndex(InMessageHeader, InSpecialHeader); static constexpr auto InMessageHandleIndex = svc::ipc::MessageBuffer::GetSpecialDataIndex(InMessageHeader, InSpecialHeader) + (HasProcessId ? sizeof(u64) / sizeof(u32) : 0); @@ -302,8 +307,8 @@ namespace ams::tipc::impl { static constexpr bool HasOutSpecialHeader = NumOutHandles > 0; - static constexpr svc::ipc::MessageBuffer::MessageHeader OutMessageHeader(CommandId, HasOutSpecialHeader, 0, 0, 0, 0, (OutDataSize / sizeof(u32)) + 1, 0); - static constexpr svc::ipc::MessageBuffer::SpecialHeader OutSpecialHeader(false, NumOutMoveHandles, NumOutCopyHandles); + static constexpr svc::ipc::MessageBuffer::MessageHeader OutMessageHeader{CommandId, HasOutSpecialHeader, 0, 0, 0, 0, (OutDataSize / sizeof(u32)) + 1, 0}; + static constexpr svc::ipc::MessageBuffer::SpecialHeader OutSpecialHeader{false, NumOutCopyHandles, NumOutMoveHandles, HasOutSpecialHeader}; static constexpr auto OutMessageHandleIndex = svc::ipc::MessageBuffer::GetSpecialDataIndex(OutMessageHeader, OutSpecialHeader); static constexpr auto OutMessageRawDataIndex = svc::ipc::MessageBuffer::GetRawDataIndex(OutMessageHeader, OutSpecialHeader); @@ -322,10 +327,6 @@ namespace ams::tipc::impl { /* Save a copy of the current state to return. */ ArgumentSerializationInfo returned_info = current_info; - /* Clear previous iteration's fixed size. */ - returned_info.fixed_size = 0; - current_info.fixed_size = 0; - constexpr auto arg_type = GetArgumentType; returned_info.arg_type = arg_type; if constexpr (arg_type == ArgumentType::InData) { @@ -336,18 +337,18 @@ namespace ams::tipc::impl { current_info.out_raw_data_index++; } else if constexpr (arg_type == ArgumentType::InHandle) { /* New InHandle, increment the appropriate index. */ - if constexpr (std::is_same::value) { + if constexpr (std::is_same::value) { current_info.in_move_handle_index++; - } else if constexpr (std::is_same::value) { + } else if constexpr (std::is_same::value) { current_info.in_copy_handle_index++; } else { static_assert(!std::is_same::value, "Invalid InHandle kind"); } } else if constexpr (arg_type == ArgumentType::OutHandle) { /* New OutHandle, increment the appropriate index. */ - if constexpr (std::is_same>::value) { + if constexpr (std::is_same>::value) { current_info.out_move_handle_index++; - } else if constexpr (std::is_same>::value) { + } else if constexpr (std::is_same>::value) { current_info.out_copy_handle_index++; } else { static_assert(!std::is_same::value, "Invalid OutHandle kind"); @@ -477,12 +478,12 @@ namespace ams::tipc::impl { static consteval u32 GetSpecialHeaderForCheck(const svc::ipc::MessageBuffer::SpecialHeader &header) { using Value = util::BitPack32::Field<0, BITSIZEOF(util::BitPack32)>; - return header->GetHeader()->Get(); + return header.GetHeader()->Get(); } /* Argument deserialization. */ template::type> - static ALWAYS_INLINE typename std::tuple_element::type DeserializeArgumentImpl(const svc::ipc::MessageBuffer &message_buffer, const OutRawHolderType &out_raw_holder, OutHandleHolderType &out_handles_holder) { + static ALWAYS_INLINE typename std::tuple_element::type DeserializeArgumentImpl(const svc::ipc::MessageBuffer &message_buffer, const OutRawHolderType &out_raw_holder, OutHandleHolderType &out_handles_holder) { constexpr auto Info = CommandMeta::ArgumentSerializationInfos[Index]; if constexpr (Info.arg_type == ArgumentType::InData) { /* New in rawdata. */ @@ -490,17 +491,21 @@ namespace ams::tipc::impl { constexpr size_t RawIndex = Offset / sizeof(u32); static_assert(Offset == RawIndex * sizeof(u32)); /* TODO: Do unaligned data exist? */ - return message_buffer.GetRaw(InMessageRawDataIndex + RawIndex); + if constexpr (!std::same_as) { + return message_buffer.GetRaw(CommandMeta::InMessageRawDataIndex + RawIndex); + } else { + return message_buffer.GetRaw(CommandMeta::InMessageRawDataIndex + RawIndex) & 1; + } } else if constexpr (Info.arg_type == ArgumentType::OutData) { /* New out rawdata. */ constexpr size_t Offset = CommandMeta::OutDataOffsets[Info.out_raw_data_index]; return T(out_raw_holder.template GetAddress()); } else if constexpr (Info.arg_type == ArgumentType::InHandle) { /* New InHandle. */ - if constexpr (std::is_same::value) { + if constexpr (std::is_same::value) { constexpr auto HandleIndex = CommandMeta::InMessageHandleIndex + CommandMeta::NumInCopyHandles + Info.in_move_handle_index; return T(message_buffer.GetHandle(HandleIndex)); - } else if constexpr (std::is_same::value) { + } else if constexpr (std::is_same::value) { constexpr auto HandleIndex = CommandMeta::InMessageHandleIndex + Info.in_copy_handle_index; return T(message_buffer.GetHandle(HandleIndex)); } else { @@ -508,9 +513,9 @@ namespace ams::tipc::impl { } } else if constexpr (Info.arg_type == ArgumentType::OutHandle) { /* New OutHandle. */ - if constexpr (std::is_same>::value) { + if constexpr (std::is_same>::value) { return T(out_handles_holder.template GetMoveHandlePointer()); - } else if constexpr (std::is_same>::value) { + } else if constexpr (std::is_same>::value) { return T(out_handles_holder.template GetCopyHandlePointer()); } else { static_assert(!std::is_same::value, "Invalid OutHandle kind"); @@ -518,16 +523,17 @@ namespace ams::tipc::impl { } else if constexpr (Info.arg_type == ArgumentType::Buffer) { /* NOTE: There are currently no tipc commands which use buffers-with-attributes */ /* If these are added (e.g., NonSecure buffers), implement checking here? */ + constexpr size_t MapAliasDescriptorSize = svc::ipc::MessageBuffer::MapAliasDescriptor::GetDataSize(); if constexpr (Info.is_send_buffer) { /* Input send buffer. */ - constexpr auto BufferIndex = CommandMeta::InMessageBufferIndex + (Info.send_map_alias_index * MapAliasDescriptor::GetDataSize() / sizeof(util::BitPack32)); + constexpr auto BufferIndex = CommandMeta::InMessageBufferIndex + (Info.send_map_alias_index * MapAliasDescriptorSize / sizeof(util::BitPack32)); const svc::ipc::MessageBuffer::MapAliasDescriptor descriptor(message_buffer, BufferIndex); return T(tipc::PointerAndSize(descriptor.GetAddress(), descriptor.GetSize())); } else { /* Input receive buffer. */ - constexpr auto BufferIndex = CommandMeta::InMessageBufferIndex + ((CommandMeta::NumInBuffers + Info.recv_map_alias_index) * MapAliasDescriptor::GetDataSize() / sizeof(util::BitPack32)); + constexpr auto BufferIndex = CommandMeta::InMessageBufferIndex + ((CommandMeta::NumInBuffers + Info.recv_map_alias_index) * MapAliasDescriptorSize / sizeof(util::BitPack32)); const svc::ipc::MessageBuffer::MapAliasDescriptor descriptor(message_buffer, BufferIndex); return T(tipc::PointerAndSize(descriptor.GetAddress(), descriptor.GetSize())); @@ -540,8 +546,8 @@ namespace ams::tipc::impl { } template - static ALWAYS_INLINE ArgsTypeForInvoke DeserializeArgumentsImpl(const svc::ipc::MessageBuffer &message_buffer, const OutRawHolderType &out_raw_holder, OutHandleHolderType &out_handles_holder, std::index_sequence) { - return ArgsTypeForInvoke { DeserializeArgumentImpl(message_buffer, out_raw_holder, out_handles_holder, in_out_objects_holder)..., }; + static ALWAYS_INLINE ArgsType DeserializeArgumentsImpl(const svc::ipc::MessageBuffer &message_buffer, const OutRawHolderType &out_raw_holder, OutHandleHolderType &out_handles_holder, std::index_sequence) { + return ArgsType { DeserializeArgumentImpl(message_buffer, out_raw_holder, out_handles_holder)..., }; } public: static ALWAYS_INLINE Result ValidateCommandFormat(const svc::ipc::MessageBuffer &message_buffer) { @@ -555,16 +561,35 @@ namespace ams::tipc::impl { constexpr auto SpecialHeaderIndex = svc::ipc::MessageBuffer::MessageHeader::GetDataSize() / sizeof(util::BitPack32); R_UNLESS(message_buffer.Get32(SpecialHeaderIndex) == ExpectedSpecialHeader, tipc::ResultInvalidMessageFormat()); } + + return ResultSuccess(); } static ALWAYS_INLINE ArgsType DeserializeArguments(const svc::ipc::MessageBuffer &message_buffer, const OutRawHolderType &out_raw_holder, OutHandleHolderType &out_handles_holder) { return DeserializeArgumentsImpl(message_buffer, out_raw_holder, out_handles_holder, std::make_index_sequence::value>{}); } + + static ALWAYS_INLINE void SerializeResults(const svc::ipc::MessageBuffer &message_buffer, const Result &result, const OutRawHolderType &out_raw_holder, const OutHandleHolderType &out_handles_holder) { + /* Set output headers. */ + message_buffer.Set(CommandMeta::OutMessageHeader); + if constexpr (CommandMeta::HasOutSpecialHeader) { + message_buffer.Set(CommandMeta::OutSpecialHeader); + } + + /* Set output handles. */ + out_handles_holder.CopyTo(message_buffer); + + /* Set output data. */ + out_raw_holder.CopyTo(message_buffer); + + /* Set output result. */ + message_buffer.Set(CommandMeta::OutMessageResultIndex, result.GetValue()); + } }; - template - constexpr ALWAYS_INLINE Result InvokeServiceCommandImpl(ClassType *object) { - using CommandMeta = CommandMetaInfo; + template + constexpr ALWAYS_INLINE Result InvokeServiceCommandImpl(ClassType *object, const svc::ipc::MessageBuffer &message_buffer) { + using CommandMeta = CommandMetaInfo<_CommmandId, Arguments...>; using Processor = CommandProcessor; /* TODO: ValidateClassType is valid? */ @@ -572,16 +597,13 @@ namespace ams::tipc::impl { constexpr bool ReturnsVoid = std::is_same::value; static_assert(ReturnsResult || ReturnsVoid, "Service Commands must return Result or void."); - /* Create accessor to the message buffer. */ - svc::ipc::MessageBuffer message_buffer(svc::ipc::GetMessageBuffer()); - /* Validate that the command is valid. */ R_TRY(Processor::ValidateCommandFormat(message_buffer)); /* Deserialize arguments. */ - Processor::OutRawHolderType out_raw_holder; - Processor::OutHandleHolderType out_handles_holder; - const Result command_result = [object](std::index_sequence) ALWAYS_INLINE_LAMBDA { + typename Processor::OutRawHolderType out_raw_holder; + typename Processor::OutHandleHolderType out_handles_holder; + const Result command_result = [&](std::index_sequence) ALWAYS_INLINE_LAMBDA { auto args_tuple = Processor::DeserializeArguments(message_buffer, out_raw_holder, out_handles_holder); using TrueArgumentsTuple = std::tuple; @@ -595,22 +617,7 @@ namespace ams::tipc::impl { }(std::make_index_sequence::value>()); /* Serialize output. */ - { - /* Set output headers. */ - message_buffer.Set(CommandMeta::OutMessageHeader); - if constexpr (CommandMeta::HasOutSpecialHeader) { - message_buffer.Set(CommandMeta::OutSpecialHeader); - } - - /* Set output handles. */ - out_handles_holder.CopyTo(message_buffer); - - /* Set output data. */ - out_raw_holder.CopyTo(message_buffer); - - /* Set output result. */ - message_buffer.Set(CommandMeta::OutMessageResultIndex, command_result.GetValue()); - } + Processor::SerializeResults(message_buffer, command_result, out_raw_holder, out_handles_holder); return ResultSuccess(); } diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_buffers.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_buffers.hpp new file mode 100644 index 000000000..b859138cb --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_buffers.hpp @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include +#include + +namespace ams::tipc { + + namespace impl { + + /* Buffer utilities. */ + struct BufferBaseTag{}; + + } + + namespace impl { + + class BufferBase : public BufferBaseTag { + public: + static constexpr u32 AdditionalAttributes = 0; + private: + const tipc::PointerAndSize pas; + protected: + constexpr ALWAYS_INLINE uintptr_t GetAddressImpl() const { + return this->pas.GetAddress(); + } + + template + constexpr ALWAYS_INLINE size_t GetSizeImpl() const { + return this->pas.GetSize() / sizeof(Entry); + } + public: + constexpr ALWAYS_INLINE BufferBase() : pas() { /* ... */ } + constexpr ALWAYS_INLINE BufferBase(const tipc::PointerAndSize &_pas) : pas(_pas) { /* ... */ } + constexpr ALWAYS_INLINE BufferBase(uintptr_t ptr, size_t sz) : pas(ptr, sz) { /* ... */ } + }; + + class InBufferBase : public BufferBase { + public: + using BaseType = BufferBase; + static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes | + SfBufferAttr_In; + public: + constexpr ALWAYS_INLINE InBufferBase() : BaseType() { /* ... */ } + constexpr ALWAYS_INLINE InBufferBase(const tipc::PointerAndSize &_pas) : BaseType(_pas) { /* ... */ } + constexpr ALWAYS_INLINE InBufferBase(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } + + constexpr ALWAYS_INLINE InBufferBase(const void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + constexpr ALWAYS_INLINE InBufferBase(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + }; + + class OutBufferBase : public BufferBase { + public: + using BaseType = BufferBase; + static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes | + SfBufferAttr_Out; + public: + constexpr ALWAYS_INLINE OutBufferBase() : BaseType() { /* ... */ } + constexpr ALWAYS_INLINE OutBufferBase(const tipc::PointerAndSize &_pas) : BaseType(_pas) { /* ... */ } + constexpr ALWAYS_INLINE OutBufferBase(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } + + constexpr ALWAYS_INLINE OutBufferBase(void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + constexpr ALWAYS_INLINE OutBufferBase(u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + }; + + template + class InBufferImpl : public InBufferBase { + public: + using BaseType = InBufferBase; + static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes | + ExtraAttributes; + public: + constexpr ALWAYS_INLINE InBufferImpl() : BaseType() { /* ... */ } + constexpr ALWAYS_INLINE InBufferImpl(const tipc::PointerAndSize &_pas) : BaseType(_pas) { /* ... */ } + constexpr ALWAYS_INLINE InBufferImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } + + constexpr ALWAYS_INLINE InBufferImpl(const void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + constexpr ALWAYS_INLINE InBufferImpl(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + + constexpr ALWAYS_INLINE const u8 *GetPointer() const { + return reinterpret_cast(this->GetAddressImpl()); + } + + constexpr ALWAYS_INLINE size_t GetSize() const { + return this->GetSizeImpl(); + } + }; + + template + class OutBufferImpl : public OutBufferBase { + public: + using BaseType = OutBufferBase; + static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes | + ExtraAttributes; + public: + constexpr ALWAYS_INLINE OutBufferImpl() : BaseType() { /* ... */ } + constexpr ALWAYS_INLINE OutBufferImpl(const tipc::PointerAndSize &_pas) : BaseType(_pas) { /* ... */ } + constexpr ALWAYS_INLINE OutBufferImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } + + constexpr ALWAYS_INLINE OutBufferImpl(void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + constexpr ALWAYS_INLINE OutBufferImpl(u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + + constexpr ALWAYS_INLINE u8 *GetPointer() const { + return reinterpret_cast(this->GetAddressImpl()); + } + + constexpr ALWAYS_INLINE size_t GetSize() const { + return this->GetSizeImpl(); + } + }; + + template + struct InArrayImpl : public InBufferBase { + public: + using BaseType = InBufferBase; + static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes; + public: + constexpr ALWAYS_INLINE InArrayImpl() : BaseType() { /* ... */ } + constexpr ALWAYS_INLINE InArrayImpl(const tipc::PointerAndSize &_pas) : BaseType(_pas) { /* ... */ } + constexpr ALWAYS_INLINE InArrayImpl(const T *ptr, size_t num_elements) : BaseType(reinterpret_cast(ptr), num_elements * sizeof(T)) { /* ... */ } + + constexpr ALWAYS_INLINE const T *GetPointer() const { + return reinterpret_cast(this->GetAddressImpl()); + } + + constexpr ALWAYS_INLINE size_t GetSize() const { + return this->GetSizeImpl(); + } + + constexpr ALWAYS_INLINE const T &operator[](size_t i) const { + return this->GetPointer()[i]; + } + + constexpr explicit ALWAYS_INLINE operator Span() const { + return {this->GetPointer(), this->GetSize()}; + } + + constexpr ALWAYS_INLINE Span ToSpan() const { + return {this->GetPointer(), this->GetSize()}; + } + }; + + template + struct OutArrayImpl : public OutBufferBase { + public: + using BaseType = OutBufferBase; + static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes; + public: + constexpr ALWAYS_INLINE OutArrayImpl() : BaseType() { /* ... */ } + constexpr ALWAYS_INLINE OutArrayImpl(const tipc::PointerAndSize &_pas) : BaseType(_pas) { /* ... */ } + constexpr ALWAYS_INLINE OutArrayImpl(T *ptr, size_t num_elements) : BaseType(reinterpret_cast(ptr), num_elements * sizeof(T)) { /* ... */ } + + constexpr ALWAYS_INLINE T *GetPointer() const { + return reinterpret_cast(this->GetAddressImpl()); + } + + constexpr ALWAYS_INLINE size_t GetSize() const { + return this->GetSizeImpl(); + } + + constexpr ALWAYS_INLINE T &operator[](size_t i) const { + return this->GetPointer()[i]; + } + + constexpr explicit ALWAYS_INLINE operator Span() const { + return {this->GetPointer(), this->GetSize()}; + } + + constexpr ALWAYS_INLINE Span ToSpan() const { + return {this->GetPointer(), this->GetSize()}; + } + }; + + } + + /* Buffer Types. */ + using InBuffer = typename impl::InBufferImpl<>; + // using InNonSecureBuffer = typename impl::InBufferImpl; + // using InNonDeviceBuffer = typename impl::InBufferImpl; + + using OutBuffer = typename impl::OutBufferImpl<>; + //using OutNonSecureBuffer = typename impl::OutBufferImpl; + //using OutNonDeviceBuffer = typename impl::OutBufferImpl; + + template + using InArray = typename impl::InArrayImpl; + + template + using OutArray = typename impl::OutArrayImpl; + + /* Attribute serialization structs. */ + template + concept IsBuffer = std::derived_from; + + template requires IsBuffer + constexpr inline u32 BufferAttributes = SfBufferAttr_HipcMapAlias | T::AdditionalAttributes; + +} diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_common.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_common.hpp new file mode 100644 index 000000000..fe3415a04 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_common.hpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include +#include +#include \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_handles.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_handles.hpp new file mode 100644 index 000000000..6efb74b80 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_handles.hpp @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include +#include + +namespace ams::tipc { + + namespace impl { + + struct InHandleTag{}; + struct OutHandleTag{}; + + template + struct InHandle : public InHandleTag { + ::Handle handle; + + constexpr InHandle() : handle(INVALID_HANDLE) { /* ... */ } + constexpr InHandle(::Handle h) : handle(h) { /* ... */ } + constexpr InHandle(const InHandle &o) : handle(o.handle) { /* ... */ } + + constexpr void operator=(const ::Handle &h) { this->handle = h; } + constexpr void operator=(const InHandle &o) { this->handle = o.handle; } + + constexpr /* TODO: explicit? */ operator ::Handle() const { return this->handle; } + constexpr ::Handle GetValue() const { return this->handle; } + }; + + template + class OutHandleImpl : public OutHandleTag { + static_assert(std::is_base_of::value, "OutHandleImpl requires InHandle base"); + private: + T *ptr; + public: + constexpr OutHandleImpl(T *p) : ptr(p) { /* ... */ } + + constexpr void SetValue(const Handle &value) { + *this->ptr = value; + } + + constexpr void SetValue(const T &value) { + *this->ptr = value; + } + + constexpr const T &GetValue() const { + return *this->ptr; + } + + constexpr T *GetPointer() const { + return this->ptr; + } + + constexpr Handle *GetHandlePointer() const { + return &this->ptr->handle; + } + + constexpr T &operator *() const { + return *this->ptr; + } + + constexpr T *operator ->() const { + return this->ptr; + } + }; + + } + + using MoveHandle = typename impl::InHandle; + using CopyHandle = typename impl::InHandle; + + static_assert(sizeof(MoveHandle) == sizeof(::Handle), "sizeof(MoveHandle)"); + static_assert(sizeof(CopyHandle) == sizeof(::Handle), "sizeof(CopyHandle)"); + + template<> + class IsOutForceEnabled : public std::true_type{}; + template<> + class IsOutForceEnabled : public std::true_type{}; + + template<> + class Out : public impl::OutHandleImpl { + private: + using T = MoveHandle; + using Base = impl::OutHandleImpl; + public: + constexpr Out(T *p) : Base(p) { /* ... */ } + + constexpr void SetValue(const Handle &value) { + Base::SetValue(value); + } + + constexpr void SetValue(const T &value) { + Base::SetValue(value); + } + + constexpr const T &GetValue() const { + return Base::GetValue(); + } + + constexpr T *GetPointer() const { + return Base::GetPointer(); + } + + constexpr Handle *GetHandlePointer() const { + return Base::GetHandlePointer(); + } + + constexpr T &operator *() const { + return Base::operator*(); + } + + constexpr T *operator ->() const { + return Base::operator->(); + } + }; + + template<> + class Out : public impl::OutHandleImpl { + private: + using T = CopyHandle; + using Base = impl::OutHandleImpl; + public: + constexpr Out(T *p) : Base(p) { /* ... */ } + + constexpr void SetValue(const Handle &value) { + Base::SetValue(value); + } + + constexpr void SetValue(const T &value) { + Base::SetValue(value); + } + + constexpr const T &GetValue() const { + return Base::GetValue(); + } + + constexpr T *GetPointer() const { + return Base::GetPointer(); + } + + constexpr Handle *GetHandlePointer() const { + return Base::GetHandlePointer(); + } + + constexpr T &operator *() const { + return Base::operator*(); + } + + constexpr T *operator ->() const { + return Base::operator->(); + } + }; + + using OutMoveHandle = tipc::Out; + using OutCopyHandle = tipc::Out; + +} diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_out.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_out.hpp new file mode 100644 index 000000000..96072a5a5 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_out.hpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include + +namespace ams::tipc { + + namespace impl { + + struct OutBaseTag{}; + + } + + template + struct IsOutForceEnabled : public std::false_type{}; + + template<> + struct IsOutForceEnabled<::ams::Result> : public std::true_type{}; + + template + concept OutEnabled = (std::is_trivial::value || IsOutForceEnabled::value) && !std::is_pointer::value; + + template + class Out : public impl::OutBaseTag { + static_assert(OutEnabled); + public: + static constexpr size_t TypeSize = sizeof(T); + private: + T *ptr; + public: + constexpr Out(uintptr_t p) : ptr(reinterpret_cast(p)) { /* ... */ } + constexpr Out(T *p) : ptr(p) { /* ... */ } + constexpr Out(const tipc::PointerAndSize &pas) : ptr(reinterpret_cast(pas.GetAddress())) { /* TODO: Is AMS_ABORT_UNLESS(pas.GetSize() >= sizeof(T)); necessary? */ } + + ALWAYS_INLINE void SetValue(const T& value) const { + *this->ptr = value; + } + + ALWAYS_INLINE const T &GetValue() const { + return *this->ptr; + } + + ALWAYS_INLINE T *GetPointer() const { + return this->ptr; + } + + /* Convenience operators. */ + ALWAYS_INLINE T &operator*() const { + return *this->ptr; + } + + ALWAYS_INLINE T *operator->() const { + return this->ptr; + } + }; + + template + class Out { + static_assert(!std::is_same::value, "Invalid tipc::Out (Raw Pointer)"); + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_pointer_and_size.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_pointer_and_size.hpp new file mode 100644 index 000000000..407b25a3c --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_pointer_and_size.hpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::tipc { + + class PointerAndSize { + private: + uintptr_t pointer; + size_t size; + public: + constexpr PointerAndSize() : pointer(0), size(0) { /* ... */ } + constexpr PointerAndSize(uintptr_t ptr, size_t sz) : pointer(ptr), size(sz) { /* ... */ } + constexpr PointerAndSize(void *ptr, size_t sz) : PointerAndSize(reinterpret_cast(ptr), sz) { /* ... */ } + + constexpr ALWAYS_INLINE void *GetPointer() const { + return reinterpret_cast(this->pointer); + } + + constexpr ALWAYS_INLINE uintptr_t GetAddress() const { + return this->pointer; + } + + constexpr ALWAYS_INLINE size_t GetSize() const { + return this->size; + } + }; + +} diff --git a/libraries/libstratosphere/source/_test/test_tipc_serializer.cpp b/libraries/libstratosphere/source/_test/test_tipc_serializer.cpp new file mode 100644 index 000000000..07ac29545 --- /dev/null +++ b/libraries/libstratosphere/source/_test/test_tipc_serializer.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::_test { + + class UserInterfaceFacade { + public: + Result RegisterClient(const tipc::ClientProcessId &process_id); + Result GetServiceHandle(tipc::OutMoveHandle out_h, sm::ServiceName service); + Result RegisterService(tipc::OutMoveHandle out_h, sm::ServiceName service, u32 max_sessions, bool is_light); + Result UnregisterService(sm::ServiceName service); + }; + + Result TestRegisterClient(UserInterfaceFacade *facade, const svc::ipc::MessageBuffer &message_buffer) { + return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::RegisterClient, 16, Result, UserInterfaceFacade, const tipc::ClientProcessId &>(facade, message_buffer); + } + + Result TestGetServiceHandle(UserInterfaceFacade *facade, const svc::ipc::MessageBuffer &message_buffer) { + return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::GetServiceHandle, 17, Result, UserInterfaceFacade, tipc::OutMoveHandle, sm::ServiceName>(facade, message_buffer); + } + + Result TestRegisterService(UserInterfaceFacade *facade, const svc::ipc::MessageBuffer &message_buffer) { + return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::RegisterService, 18, Result, UserInterfaceFacade, tipc::OutMoveHandle, sm::ServiceName, u32, bool>(facade, message_buffer); + } + + Result TestUnregisterService(UserInterfaceFacade *facade, const svc::ipc::MessageBuffer &message_buffer) { + return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::UnregisterService, 19, Result, UserInterfaceFacade, sm::ServiceName>(facade, message_buffer); + } + + Result TestManualDispatch(UserInterfaceFacade *facade) { + svc::ipc::MessageBuffer message_buffer(svc::ipc::GetMessageBuffer()); + + switch (svc::ipc::MessageBuffer::MessageHeader(message_buffer).GetTag()) { + case 16: + return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::RegisterClient, 16, Result, UserInterfaceFacade, const tipc::ClientProcessId &>(facade, message_buffer); + case 17: + return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::GetServiceHandle, 17, Result, UserInterfaceFacade, tipc::OutMoveHandle, sm::ServiceName>(facade, message_buffer); + case 18: + return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::RegisterService, 18, Result, UserInterfaceFacade, tipc::OutMoveHandle, sm::ServiceName, u32, bool>(facade, message_buffer); + case 19: + return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::UnregisterService, 19, Result, UserInterfaceFacade, sm::ServiceName>(facade, message_buffer); + default: + return tipc::ResultInvalidMethod(); + } + } + + +} \ No newline at end of file diff --git a/libraries/libvapours/include/vapours/svc/ipc/svc_message_buffer.hpp b/libraries/libvapours/include/vapours/svc/ipc/svc_message_buffer.hpp index 092f785aa..3be077c81 100644 --- a/libraries/libvapours/include/vapours/svc/ipc/svc_message_buffer.hpp +++ b/libraries/libvapours/include/vapours/svc/ipc/svc_message_buffer.hpp @@ -152,6 +152,14 @@ namespace ams::svc::ipc { this->header.Set(move); } + consteval explicit SpecialHeader(bool pid, s32 copy, s32 move, bool _has_header) : header{0}, has_header(_has_header) { + this->header.Set(pid); + this->header.Set(copy); + this->header.Set(move); + + AMS_ASSUME(this->has_header == (this->GetHasProcessId() || this->GetCopyHandleCount() > 0 || this->GetMoveHandleCount() > 0)); + } + ALWAYS_INLINE explicit SpecialHeader(const MessageBuffer &buf, const MessageHeader &hdr) : header{0}, has_header(hdr.GetHasSpecialHeader()) { if (this->has_header) { buf.Get(MessageHeader::GetDataSize() / sizeof(util::BitPack32), std::addressof(this->header), sizeof(this->header) / sizeof(util::BitPack32)); @@ -410,11 +418,7 @@ namespace ams::svc::ipc { template ALWAYS_INLINE const T &GetRaw(s32 index) const { - if constexpr (!std::same_as) { - return *reinterpret_cast(this->buffer + index); - } else { - return *reinterpret_cast(this->buffer + index) & 1; - } + return *reinterpret_cast(this->buffer + index); } template