tipc: fix compilation issues with core serialization routines

This commit is contained in:
Michael Scire 2021-04-08 15:24:08 -07:00 committed by SciresM
parent e93d71d932
commit 21b883a75c
10 changed files with 662 additions and 68 deletions

View file

@ -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)

View file

@ -13,7 +13,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere/tipc/impl/tipc_impl_command_serialization.hpp>

View file

@ -15,6 +15,10 @@
*/
#pragma once
#include <vapours.hpp>
#include <stratosphere/tipc/tipc_common.hpp>
#include <stratosphere/tipc/tipc_out.hpp>
#include <stratosphere/tipc/tipc_buffers.hpp>
#include <stratosphere/tipc/tipc_handles.hpp>
namespace ams::tipc {
@ -72,13 +76,13 @@ namespace ams::tipc::impl {
constexpr inline ArgumentType GetArgumentType = [] {
if constexpr (tipc::IsBuffer<T>) {
return ArgumentType::Buffer;
} else if constexpr (std::is_base_of<sf::impl::InHandleTag, T>::value) {
} else if constexpr (std::is_base_of<tipc::impl::InHandleTag, T>::value) {
return ArgumentType::InHandle;
} else if constexpr (std::is_base_of<sf::impl::OutHandleTag, T>::value) {
} else if constexpr (std::is_base_of<tipc::impl::OutHandleTag, T>::value) {
return ArgumentType::OutHandle;
} else if constexpr (std::is_base_of<sf::impl::OutBaseTag, T>::value) {
} else if constexpr (std::is_base_of<tipc::impl::OutBaseTag, T>::value) {
return ArgumentType::OutData;
} else if constexpr (std::same_as<tipc::ClientProcessId>) {
} else if constexpr (std::same_as<T, tipc::ClientProcessId>) {
return ArgumentType::ProcessId;
} else if constexpr (std::is_trivial<T>::value && !std::is_pointer<T>::value) {
return ArgumentType::InData;
@ -111,21 +115,21 @@ namespace ams::tipc::impl {
template<typename T>
using OutHandleFilter = ArgumentTypeFilter<T, ArgumentType::OutHandle>;
template<typename T>
using ProcessIdFilter = ArgumentTypeFilter<T, ArgumentType::ProcessId>;
/* Handle kind filters. */
template<typename T>
using InMoveHandleFilter = TypeEqualityFilter<T, sf::MoveHandle>;
using InMoveHandleFilter = TypeEqualityFilter<T, tipc::MoveHandle>;
template<typename T>
using InCopyHandleFilter = TypeEqualityFilter<T, sf::CopyHandle>;
using InCopyHandleFilter = TypeEqualityFilter<T, tipc::CopyHandle>;
template<typename T>
using OutMoveHandleFilter = TypeEqualityFilter<T, sf::Out<sf::MoveHandle>>;
using OutMoveHandleFilter = TypeEqualityFilter<T, tipc::Out<tipc::MoveHandle>>;
template<typename T>
using OutCopyHandleFilter = TypeEqualityFilter<T, sf::Out<sf::CopyHandle>>;
template<typename T>
struct ProcessIdFilter = ArgumentTypeFilter<T, ArgumentType::ProcessId>;
using OutCopyHandleFilter = TypeEqualityFilter<T, tipc::Out<tipc::CopyHandle>>;
template<typename>
struct BufferAttributeArrayGetter;
@ -236,7 +240,8 @@ namespace ams::tipc::impl {
template<u16 _CommandId, typename... Arguments>
struct CommandMetaInfo {
public:
using CommandId = _CommandId;
static constexpr u16 CommandId = _CommandId;
using ArgsType = std::tuple<typename std::decay<Arguments>::type...>;
using InDatas = TupleFilter<InDataFilter>::FilteredType<ArgsType>;
@ -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<u32, NumBuffers> BufferAttributes = BufferAttributeArrayGetter<Buffers>::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<T>;
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<T, sf::MoveHandle>::value) {
if constexpr (std::is_same<T, tipc::MoveHandle>::value) {
current_info.in_move_handle_index++;
} else if constexpr (std::is_same<T, sf::CopyHandle>::value) {
} else if constexpr (std::is_same<T, tipc::CopyHandle>::value) {
current_info.in_copy_handle_index++;
} else {
static_assert(!std::is_same<T, T>::value, "Invalid InHandle kind");
}
} else if constexpr (arg_type == ArgumentType::OutHandle) {
/* New OutHandle, increment the appropriate index. */
if constexpr (std::is_same<T, sf::Out<sf::MoveHandle>>::value) {
if constexpr (std::is_same<T, tipc::Out<tipc::MoveHandle>>::value) {
current_info.out_move_handle_index++;
} else if constexpr (std::is_same<T, sf::Out<sf::CopyHandle>>::value) {
} else if constexpr (std::is_same<T, tipc::Out<tipc::CopyHandle>>::value) {
current_info.out_copy_handle_index++;
} else {
static_assert(!std::is_same<T, T>::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<Value>();
return header.GetHeader()->Get<Value>();
}
/* Argument deserialization. */
template<size_t Index, typename T = typename std::tuple_element<Index, ArgsType>::type>
static ALWAYS_INLINE typename std::tuple_element<Index, ArgsTypeForInvoke>::type DeserializeArgumentImpl(const svc::ipc::MessageBuffer &message_buffer, const OutRawHolderType &out_raw_holder, OutHandleHolderType &out_handles_holder) {
static ALWAYS_INLINE typename std::tuple_element<Index, ArgsType>::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<T, bool>) {
return message_buffer.GetRaw<T>(CommandMeta::InMessageRawDataIndex + RawIndex);
} else {
return message_buffer.GetRaw<u8>(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<Offset, T::TypeSize>());
} else if constexpr (Info.arg_type == ArgumentType::InHandle) {
/* New InHandle. */
if constexpr (std::is_same<T, sf::MoveHandle>::value) {
if constexpr (std::is_same<T, tipc::MoveHandle>::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<T, sf::CopyHandle>::value) {
} else if constexpr (std::is_same<T, tipc::CopyHandle>::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<T, sf::Out<sf::MoveHandle>>::value) {
if constexpr (std::is_same<T, tipc::Out<tipc::MoveHandle>>::value) {
return T(out_handles_holder.template GetMoveHandlePointer<Info.out_move_handle_index>());
} else if constexpr (std::is_same<T, sf::Out<sf::CopyHandle>>::value) {
} else if constexpr (std::is_same<T, tipc::Out<tipc::CopyHandle>>::value) {
return T(out_handles_holder.template GetCopyHandlePointer<Info.out_copy_handle_index>());
} else {
static_assert(!std::is_same<T, T>::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<size_t... Is>
static ALWAYS_INLINE ArgsTypeForInvoke DeserializeArgumentsImpl(const svc::ipc::MessageBuffer &message_buffer, const OutRawHolderType &out_raw_holder, OutHandleHolderType &out_handles_holder, std::index_sequence<Is...>) {
return ArgsTypeForInvoke { DeserializeArgumentImpl<Is>(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<Is...>) {
return ArgsType { DeserializeArgumentImpl<Is>(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<std::tuple_size<ArgsType>::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<auto ServiceCommandImpl, typename Return, typename ClassType, typename... Arguments>
constexpr ALWAYS_INLINE Result InvokeServiceCommandImpl(ClassType *object) {
using CommandMeta = CommandMetaInfo<Arguments...>;
template<auto ServiceCommandImpl, u16 _CommmandId, typename Return, typename ClassType, typename... Arguments>
constexpr ALWAYS_INLINE Result InvokeServiceCommandImpl(ClassType *object, const svc::ipc::MessageBuffer &message_buffer) {
using CommandMeta = CommandMetaInfo<_CommmandId, Arguments...>;
using Processor = CommandProcessor<CommandMeta>;
/* TODO: ValidateClassType is valid? */
@ -572,16 +597,13 @@ namespace ams::tipc::impl {
constexpr bool ReturnsVoid = std::is_same<Return, void>::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]<size_t... Ix>(std::index_sequence<Ix...>) ALWAYS_INLINE_LAMBDA {
typename Processor::OutRawHolderType out_raw_holder;
typename Processor::OutHandleHolderType out_handles_holder;
const Result command_result = [&]<size_t... Ix>(std::index_sequence<Ix...>) ALWAYS_INLINE_LAMBDA {
auto args_tuple = Processor::DeserializeArguments(message_buffer, out_raw_holder, out_handles_holder);
using TrueArgumentsTuple = std::tuple<Arguments...>;
@ -595,22 +617,7 @@ namespace ams::tipc::impl {
}(std::make_index_sequence<std::tuple_size<typename CommandMeta::ArgsType>::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();
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere/tipc/tipc_common.hpp>
#include <stratosphere/tipc/tipc_out.hpp>
#include <stratosphere/tipc/tipc_pointer_and_size.hpp>
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<typename Entry>
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<uintptr_t>(ptr), sz) { /* ... */ }
constexpr ALWAYS_INLINE InBufferBase(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(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<uintptr_t>(ptr), sz) { /* ... */ }
constexpr ALWAYS_INLINE OutBufferBase(u8 *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ }
};
template<u32 ExtraAttributes = 0>
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<uintptr_t>(ptr), sz) { /* ... */ }
constexpr ALWAYS_INLINE InBufferImpl(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ }
constexpr ALWAYS_INLINE const u8 *GetPointer() const {
return reinterpret_cast<const u8 *>(this->GetAddressImpl());
}
constexpr ALWAYS_INLINE size_t GetSize() const {
return this->GetSizeImpl<u8>();
}
};
template<u32 ExtraAttributes = 0>
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<uintptr_t>(ptr), sz) { /* ... */ }
constexpr ALWAYS_INLINE OutBufferImpl(u8 *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ }
constexpr ALWAYS_INLINE u8 *GetPointer() const {
return reinterpret_cast<u8 *>(this->GetAddressImpl());
}
constexpr ALWAYS_INLINE size_t GetSize() const {
return this->GetSizeImpl<u8>();
}
};
template<typename T>
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<uintptr_t>(ptr), num_elements * sizeof(T)) { /* ... */ }
constexpr ALWAYS_INLINE const T *GetPointer() const {
return reinterpret_cast<const T *>(this->GetAddressImpl());
}
constexpr ALWAYS_INLINE size_t GetSize() const {
return this->GetSizeImpl<T>();
}
constexpr ALWAYS_INLINE const T &operator[](size_t i) const {
return this->GetPointer()[i];
}
constexpr explicit ALWAYS_INLINE operator Span<const T>() const {
return {this->GetPointer(), this->GetSize()};
}
constexpr ALWAYS_INLINE Span<const T> ToSpan() const {
return {this->GetPointer(), this->GetSize()};
}
};
template<typename T>
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<uintptr_t>(ptr), num_elements * sizeof(T)) { /* ... */ }
constexpr ALWAYS_INLINE T *GetPointer() const {
return reinterpret_cast<T *>(this->GetAddressImpl());
}
constexpr ALWAYS_INLINE size_t GetSize() const {
return this->GetSizeImpl<T>();
}
constexpr ALWAYS_INLINE T &operator[](size_t i) const {
return this->GetPointer()[i];
}
constexpr explicit ALWAYS_INLINE operator Span<T>() const {
return {this->GetPointer(), this->GetSize()};
}
constexpr ALWAYS_INLINE Span<T> ToSpan() const {
return {this->GetPointer(), this->GetSize()};
}
};
}
/* Buffer Types. */
using InBuffer = typename impl::InBufferImpl<>;
// using InNonSecureBuffer = typename impl::InBufferImpl<SfBufferAttr_HipcMapTransferAllowsNonSecure>;
// using InNonDeviceBuffer = typename impl::InBufferImpl<SfBufferAttr_HipcMapTransferAllowsNonDevice>;
using OutBuffer = typename impl::OutBufferImpl<>;
//using OutNonSecureBuffer = typename impl::OutBufferImpl<SfBufferAttr_HipcMapTransferAllowsNonSecure>;
//using OutNonDeviceBuffer = typename impl::OutBufferImpl<SfBufferAttr_HipcMapTransferAllowsNonDevice>;
template<typename T>
using InArray = typename impl::InArrayImpl<T>;
template<typename T>
using OutArray = typename impl::OutArrayImpl<T>;
/* Attribute serialization structs. */
template<typename T>
concept IsBuffer = std::derived_from<T, impl::BufferBaseTag>;
template<typename T> requires IsBuffer<T>
constexpr inline u32 BufferAttributes = SfBufferAttr_HipcMapAlias | T::AdditionalAttributes;
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <stratosphere/ams.hpp>
#include <stratosphere/os.hpp>
#include <stratosphere/sm/sm_types.hpp>

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere/tipc/tipc_common.hpp>
#include <stratosphere/tipc/tipc_out.hpp>
#include <stratosphere/tipc/tipc_pointer_and_size.hpp>
namespace ams::tipc {
namespace impl {
struct InHandleTag{};
struct OutHandleTag{};
template<u32 Attribute>
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<typename T>
class OutHandleImpl : public OutHandleTag {
static_assert(std::is_base_of<InHandleTag, T>::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<SfOutHandleAttr_HipcMove>;
using CopyHandle = typename impl::InHandle<SfOutHandleAttr_HipcCopy>;
static_assert(sizeof(MoveHandle) == sizeof(::Handle), "sizeof(MoveHandle)");
static_assert(sizeof(CopyHandle) == sizeof(::Handle), "sizeof(CopyHandle)");
template<>
class IsOutForceEnabled<MoveHandle> : public std::true_type{};
template<>
class IsOutForceEnabled<CopyHandle> : public std::true_type{};
template<>
class Out<MoveHandle> : public impl::OutHandleImpl<MoveHandle> {
private:
using T = MoveHandle;
using Base = impl::OutHandleImpl<T>;
public:
constexpr Out<T>(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<CopyHandle> : public impl::OutHandleImpl<CopyHandle> {
private:
using T = CopyHandle;
using Base = impl::OutHandleImpl<T>;
public:
constexpr Out<T>(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<tipc::MoveHandle>;
using OutCopyHandle = tipc::Out<tipc::CopyHandle>;
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere/tipc/tipc_common.hpp>
#include <stratosphere/tipc/tipc_pointer_and_size.hpp>
namespace ams::tipc {
namespace impl {
struct OutBaseTag{};
}
template<typename>
struct IsOutForceEnabled : public std::false_type{};
template<>
struct IsOutForceEnabled<::ams::Result> : public std::true_type{};
template<typename T>
concept OutEnabled = (std::is_trivial<T>::value || IsOutForceEnabled<T>::value) && !std::is_pointer<T>::value;
template<typename T>
class Out : public impl::OutBaseTag {
static_assert(OutEnabled<T>);
public:
static constexpr size_t TypeSize = sizeof(T);
private:
T *ptr;
public:
constexpr Out(uintptr_t p) : ptr(reinterpret_cast<T *>(p)) { /* ... */ }
constexpr Out(T *p) : ptr(p) { /* ... */ }
constexpr Out(const tipc::PointerAndSize &pas) : ptr(reinterpret_cast<T *>(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<typename T>
class Out<T *> {
static_assert(!std::is_same<T, T>::value, "Invalid tipc::Out<T> (Raw Pointer)");
};
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere/tipc/tipc_pointer_and_size.hpp>
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<uintptr_t>(ptr), sz) { /* ... */ }
constexpr ALWAYS_INLINE void *GetPointer() const {
return reinterpret_cast<void *>(this->pointer);
}
constexpr ALWAYS_INLINE uintptr_t GetAddress() const {
return this->pointer;
}
constexpr ALWAYS_INLINE size_t GetSize() const {
return this->size;
}
};
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
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();
}
}
}

View file

@ -152,6 +152,14 @@ namespace ams::svc::ipc {
this->header.Set<MoveHandleCount>(move);
}
consteval explicit SpecialHeader(bool pid, s32 copy, s32 move, bool _has_header) : header{0}, has_header(_has_header) {
this->header.Set<HasProcessId>(pid);
this->header.Set<CopyHandleCount>(copy);
this->header.Set<MoveHandleCount>(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<typename T>
ALWAYS_INLINE const T &GetRaw(s32 index) const {
if constexpr (!std::same_as<T, bool>) {
return *reinterpret_cast<const T *>(this->buffer + index);
} else {
return *reinterpret_cast<const u8 *>(this->buffer + index) & 1;
}
return *reinterpret_cast<const T *>(this->buffer + index);
}
template<typename T>