diff --git a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_autogen_interface_macros.hpp b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_autogen_interface_macros.hpp index 845d68381..6705ddec2 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_autogen_interface_macros.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_autogen_interface_macros.hpp @@ -40,12 +40,28 @@ namespace ams::tipc::impl { #define AMS_TIPC_IMPL_EXTRACT_SYNC_METHOD_ARGUMENTS(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ using NAME##ArgumentsType = ::ams::tipc::impl::SyncFunctionArgsType<&NAME##ArgumentsFunctionHolder::f>; + #define AMS_TIPC_IMPL_GET_MAXIMUM_REQUEST_SIZE(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ + , ::ams::tipc::impl::CommandMetaInfo::InMessageTotalSize + + #define AMS_TIPC_IMPL_GET_MAXIMUM_RESPONSE_SIZE(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ + , ::ams::tipc::impl::CommandMetaInfo::OutMessageTotalSize + #define AMS_TIPC_IMPL_DEFINE_INTERFACE(BASECLASS, CLASSNAME, CMD_MACRO) \ class CLASSNAME : public BASECLASS { \ private: \ CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_DEFINE_SYNC_METHOD_HOLDER) \ public: \ CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_EXTRACT_SYNC_METHOD_ARGUMENTS) \ + public: \ + static constexpr size_t MaximumRequestSize = std::max({ \ + 0 \ + CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_GET_MAXIMUM_REQUEST_SIZE) \ + }); \ + \ + static constexpr size_t MaximumResponseSize = std::max({ \ + 0 \ + CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_GET_MAXIMUM_RESPONSE_SIZE) \ + }); \ }; #define AMS_TIPC_IMPL_DEFINE_CONCEPT_HELPERS(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ 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 52b4515ee..1a4b3504e 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 @@ -319,6 +319,9 @@ namespace ams::tipc::impl { static constexpr auto OutMessageResultIndex = svc::ipc::MessageBuffer::GetRawDataIndex(OutMessageHeader, OutSpecialHeader); static constexpr auto OutMessageRawDataIndex = OutMessageResultIndex + 1; + static constexpr size_t InMessageTotalSize = (InMessageRawDataIndex * sizeof(u32)) + InDataSize; + static constexpr size_t OutMessageTotalSize = (OutMessageRawDataIndex * sizeof(u32)) + OutDataSize; + /* Construction of argument serialization structs. */ private: template diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_deferral_manager.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_deferral_manager.hpp index e07f4d4af..dc70f8a72 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/tipc_deferral_manager.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_deferral_manager.hpp @@ -44,16 +44,17 @@ namespace ams::tipc { } - class DeferrableBase : public impl::DeferrableBaseTag { + class DeferrableBaseImpl : public impl::DeferrableBaseTag { private: DeferralManagerBase *m_deferral_manager; ObjectHolder m_object_holder; uintptr_t m_resume_key; - u8 m_message_buffer[svc::ipc::MessageBufferSize]; + const u32 m_message_buffer_size; + u8 m_message_buffer_base[0]; public: - ALWAYS_INLINE DeferrableBase() : m_deferral_manager(nullptr), m_object_holder(), m_resume_key() { /* ... */ } + ALWAYS_INLINE DeferrableBaseImpl(u32 mb_size) : m_deferral_manager(nullptr), m_object_holder(), m_resume_key(), m_message_buffer_size(mb_size) { /* ... */ } - ~DeferrableBase(); + ~DeferrableBaseImpl(); ALWAYS_INLINE void SetDeferralManager(DeferralManagerBase *manager, os::NativeHandle reply_target, ServiceObjectBase *object) { m_deferral_manager = manager; @@ -67,7 +68,7 @@ namespace ams::tipc { template ALWAYS_INLINE void RegisterRetry(ResumeKey key) { m_resume_key = ConvertToInternalResumeKey(key); - std::memcpy(m_message_buffer, svc::ipc::GetMessageBuffer(), sizeof(m_message_buffer)); + std::memcpy(m_message_buffer_base, svc::ipc::GetMessageBuffer(), m_message_buffer_size); } template @@ -85,12 +86,42 @@ namespace ams::tipc { m_resume_key = 0; /* Restore message buffer. */ - std::memcpy(svc::ipc::GetMessageBuffer(), m_message_buffer, sizeof(m_message_buffer)); + std::memcpy(svc::ipc::GetMessageBuffer(), m_message_buffer_base, m_message_buffer_size); /* Process the request. */ return port_manager->ProcessDeferredRequest(m_object_holder); } + protected: + static consteval size_t GetMessageBufferOffsetBase(); }; + static_assert(std::is_standard_layout::value); + + template + class DeferrableBase : public DeferrableBaseImpl { + private: + static constexpr size_t MessageBufferRequiredSize = Interface::MaximumRequestSize; + private: + u8 m_message_buffer[MessageBufferRequiredSize]; + public: + DeferrableBase(); + private: + static consteval size_t GetMessageBufferOffset(); + }; + + consteval size_t DeferrableBaseImpl::GetMessageBufferOffsetBase() { + return AMS_OFFSETOF(DeferrableBaseImpl, m_message_buffer_base); + } + + template + consteval size_t DeferrableBase::GetMessageBufferOffset() { + return AMS_OFFSETOF(DeferrableBase, m_message_buffer); + } + + template + ALWAYS_INLINE DeferrableBase::DeferrableBase() : DeferrableBaseImpl(MessageBufferRequiredSize) { + static_assert(GetMessageBufferOffsetBase() == GetMessageBufferOffset()); + static_assert(sizeof(DeferrableBase) >= sizeof(DeferrableBaseImpl) + MessageBufferRequiredSize); + } template concept IsDeferrable = std::derived_from; @@ -100,11 +131,11 @@ namespace ams::tipc { NON_MOVEABLE(DeferralManagerBase); private: size_t m_object_count; - DeferrableBase *m_objects_base[0]; + DeferrableBaseImpl *m_objects_base[0]; public: ALWAYS_INLINE DeferralManagerBase() : m_object_count(0) { /* ... */ } - void AddObject(DeferrableBase &object, os::NativeHandle reply_target, ServiceObjectBase *service_object) { + void AddObject(DeferrableBaseImpl &object, os::NativeHandle reply_target, ServiceObjectBase *service_object) { /* Set ourselves as the manager for the object. */ object.SetDeferralManager(this, reply_target, service_object); @@ -113,7 +144,7 @@ namespace ams::tipc { m_objects_base[m_object_count++] = std::addressof(object); } - void RemoveObject(DeferrableBase *object) { + void RemoveObject(DeferrableBaseImpl *object) { /* If the object is present, remove it. */ for (size_t i = 0; i < m_object_count; ++i) { if (m_objects_base[i] == object) { @@ -148,7 +179,7 @@ namespace ams::tipc { }; static_assert(std::is_standard_layout::value); - inline DeferrableBase::~DeferrableBase() { + inline DeferrableBaseImpl::~DeferrableBaseImpl() { AMS_ASSUME(m_deferral_manager != nullptr); m_deferral_manager->RemoveObject(this); } @@ -156,7 +187,7 @@ namespace ams::tipc { template requires (N > 0) class DeferralManager final : public DeferralManagerBase { private: - DeferrableBase *m_objects[N]; + DeferrableBaseImpl *m_objects[N]; public: DeferralManager(); private: @@ -175,7 +206,7 @@ namespace ams::tipc { template requires (N > 0) inline DeferralManager::DeferralManager() : DeferralManagerBase() { static_assert(GetObjectPointersOffset() == GetObjectPointersOffsetBase()); - static_assert(sizeof(DeferralManager) == sizeof(DeferralManagerBase) + N * sizeof(DeferrableBase *)); + static_assert(sizeof(DeferralManager) == sizeof(DeferralManagerBase) + N * sizeof(DeferrableBaseImpl *)); } } diff --git a/stratosphere/sm/source/sm_user_service.hpp b/stratosphere/sm/source/sm_user_service.hpp index 32c4144c4..5d615b5b5 100644 --- a/stratosphere/sm/source/sm_user_service.hpp +++ b/stratosphere/sm/source/sm_user_service.hpp @@ -20,7 +20,7 @@ namespace ams::sm { /* Service definition. */ - class UserService : public tipc::DeferrableBase { + class UserService : public tipc::DeferrableBase { private: os::ProcessId m_process_id; bool m_initialized;