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