mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-27 12:46:03 +00:00
tipc: implement service object interface generation
This commit is contained in:
parent
ec988c5a99
commit
315b7bdf22
4 changed files with 207 additions and 26 deletions
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* 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/tipc/tipc_service_object_base.hpp>
|
||||
#include <stratosphere/tipc/impl/tipc_impl_command_serialization.hpp>
|
||||
|
||||
namespace ams::tipc::impl {
|
||||
|
||||
template<typename T>
|
||||
concept HasDefaultServiceCommandProcessor = requires (T &t, const svc::ipc::MessageBuffer &message_buffer) {
|
||||
{ t.ProcessDefaultServiceCommand(message_buffer) } -> std::same_as<Result>;
|
||||
};
|
||||
|
||||
struct SyncFunctionTraits {
|
||||
public:
|
||||
template<typename R, typename C, typename... A>
|
||||
static std::tuple<A...> GetArgsImpl(R(C::*)(A...));
|
||||
};
|
||||
|
||||
template<auto F>
|
||||
using SyncFunctionArgsType = decltype(SyncFunctionTraits::GetArgsImpl(F));
|
||||
|
||||
#define AMS_TIPC_IMPL_DEFINE_SYNC_METHOD_HOLDER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
|
||||
struct NAME##ArgumentsFunctionHolder { RETURN f ARGS; };
|
||||
|
||||
#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_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) \
|
||||
};
|
||||
|
||||
#define AMS_TIPC_IMPL_DEFINE_CONCEPT_HELPERS(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
|
||||
template<typename T, typename... Args> \
|
||||
concept Is##CLASSNAME##__##NAME##Impl = requires (T &t, Args &&... args) { \
|
||||
{ t.NAME(std::forward<Args>(args)...) } -> std::same_as<RETURN>; \
|
||||
}; \
|
||||
\
|
||||
template<typename T, typename A> \
|
||||
struct Is##CLASSNAME##__##NAME##Holder : std::false_type{}; \
|
||||
\
|
||||
template<typename T, typename... Args> requires std::same_as<std::tuple<Args...>, CLASSNAME::NAME##ArgumentsType> \
|
||||
struct Is##CLASSNAME##__##NAME##Holder<T, std::tuple<Args...>> : std::bool_constant<Is##CLASSNAME##__##NAME##Impl<T, Args...>>{}; \
|
||||
\
|
||||
template<typename T> \
|
||||
static constexpr inline bool Is##CLASSNAME##__##NAME = Is##CLASSNAME##__##NAME##Holder<T, CLASSNAME::NAME##ArgumentsType>::value;
|
||||
|
||||
#define AMS_TIPC_IMPL_CHECK_CONCEPT_HELPER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
|
||||
Is##CLASSNAME##__##NAME<T> &&
|
||||
|
||||
#define AMS_TIPC_IMPL_DEFINE_CONCEPT(CLASSNAME, CMD_MACRO) \
|
||||
CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_DEFINE_CONCEPT_HELPERS) \
|
||||
\
|
||||
template<typename T> \
|
||||
concept Is##CLASSNAME = CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_CHECK_CONCEPT_HELPER) true;
|
||||
|
||||
#define AMS_TIPC_IMPL_PROCESS_METHOD_REQUEST(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
|
||||
if (constexpr u16 TipcCommandId = CMD_ID + 0x10; tag == TipcCommandId) { \
|
||||
return this->ProcessMethodById<TipcCommandId, ImplType>(impl, message_buffer, fw_ver); \
|
||||
}
|
||||
|
||||
#define AMS_TIPC_IMPL_PROCESS_METHOD_REQUEST_BY_ID(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
|
||||
if constexpr (constexpr u16 TipcCommandId = CMD_ID + 0x10; CommandId == TipcCommandId) { \
|
||||
constexpr bool AlwaysValid = VERSION_MIN == hos::Version_Min && VERSION_MAX == hos::Version_Max; \
|
||||
if (AlwaysValid || (VERSION_MIN <= fw_ver && fw_ver <= VERSION_MAX)) { \
|
||||
return ::ams::tipc::impl::InvokeServiceCommandImpl<TipcCommandId, &ImplType::NAME, ImplType>(impl, message_buffer); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define AMS_TIPC_DEFINE_INTERFACE_WITH_DEFAULT_BASE(NAMESPACE, INTERFACE, BASE, CMD_MACRO) \
|
||||
namespace NAMESPACE { \
|
||||
\
|
||||
AMS_TIPC_IMPL_DEFINE_INTERFACE(BASE, INTERFACE, CMD_MACRO) \
|
||||
AMS_TIPC_IMPL_DEFINE_CONCEPT(INTERFACE, CMD_MACRO) \
|
||||
\
|
||||
} \
|
||||
\
|
||||
namespace ams::tipc::impl { \
|
||||
\
|
||||
template<typename Base, typename ImplHolder, typename ImplGetter, typename Root> \
|
||||
class ImplTemplateBaseT<::NAMESPACE::INTERFACE, Base, ImplHolder, ImplGetter, Root> : public Base, public ImplHolder { \
|
||||
public: \
|
||||
template<typename... Args> \
|
||||
constexpr explicit ImplTemplateBaseT(Args &&...args) : ImplHolder(std::forward<Args>(args)...) { /* ... */ } \
|
||||
private: \
|
||||
template<typename ImplType> \
|
||||
ALWAYS_INLINE Result ProcessDefaultMethod(ImplType *impl, const svc::ipc::MessageBuffer &message_buffer) const { \
|
||||
/* Handle a default command. */ \
|
||||
if constexpr (HasDefaultServiceCommandProcessor<ImplType>) { \
|
||||
return impl->ProcessDefaultServiceCommand(message_buffer); \
|
||||
} else { \
|
||||
return tipc::ResultInvalidMethod(); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
template<u16 CommandId, typename ImplType> \
|
||||
ALWAYS_INLINE Result ProcessMethodById(ImplType *impl, const svc::ipc::MessageBuffer &message_buffer, hos::Version fw_ver) const { \
|
||||
CMD_MACRO(ImplType, AMS_TIPC_IMPL_PROCESS_METHOD_REQUEST_BY_ID) \
|
||||
\
|
||||
return this->ProcessDefaultMethod<ImplType>(impl, message_buffer); \
|
||||
} \
|
||||
public: \
|
||||
virtual Result ProcessRequest() override { \
|
||||
/* Get the implementation object. */ \
|
||||
auto * const impl = ImplGetter::GetImplPointer(static_cast<ImplHolder *>(this)); \
|
||||
\
|
||||
/* Get the implementation type. */ \
|
||||
using ImplType = typename std::remove_reference<decltype(*impl)>::type; \
|
||||
static_assert(::NAMESPACE::Is##INTERFACE<ImplType>); \
|
||||
\
|
||||
/* Get accessor to the message buffer. */ \
|
||||
svc::ipc::MessageBuffer message_buffer(svc::ipc::GetMessageBuffer()); \
|
||||
\
|
||||
/* Get decision variables. */ \
|
||||
const auto tag = svc::ipc::MessageBuffer::MessageHeader(message_buffer).GetTag(); \
|
||||
const auto fw_ver = hos::GetVersion(); \
|
||||
\
|
||||
/* Process against the command ids. */ \
|
||||
if (false) { } \
|
||||
CMD_MACRO(ImplType, AMS_TIPC_IMPL_PROCESS_METHOD_REQUEST) \
|
||||
else { \
|
||||
return this->ProcessDefaultMethod<ImplType>(impl, message_buffer); \
|
||||
} \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
}
|
||||
|
||||
|
||||
#define AMS_TIPC_DEFINE_INTERFACE(NAMESPACE, INTERFACE, CMD_MACRO) \
|
||||
AMS_TIPC_DEFINE_INTERFACE_WITH_DEFAULT_BASE(NAMESPACE, INTERFACE, ::ams::tipc::ServiceObjectBase, CMD_MACRO)
|
||||
|
||||
#define AMS_TIPC_METHOD_INFO_7(CLASSNAME, HANDLER, CMD_ID, RETURN, NAME, ARGS, ARGNAMES) \
|
||||
HANDLER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, hos::Version_Min, hos::Version_Max)
|
||||
|
||||
#define AMS_TIPC_METHOD_INFO_8(CLASSNAME, HANDLER, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN) \
|
||||
HANDLER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, hos::Version_Max)
|
||||
|
||||
#define AMS_TIPC_METHOD_INFO_9(CLASSNAME, HANDLER, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
|
||||
HANDLER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX)
|
||||
|
||||
#define AMS_TIPC_METHOD_INFO_X(_, _0, _1, _2, _3, _4, _5, _6, _7, _8, FUNC, ...) FUNC
|
||||
|
||||
#define AMS_TIPC_METHOD_INFO(...) \
|
||||
AMS_TIPC_METHOD_INFO_X(, ## __VA_ARGS__, AMS_TIPC_METHOD_INFO_9(__VA_ARGS__), AMS_TIPC_METHOD_INFO_8(__VA_ARGS__), AMS_TIPC_METHOD_INFO_7(__VA_ARGS__))
|
||||
|
||||
}
|
|
@ -237,8 +237,11 @@ namespace ams::tipc::impl {
|
|||
size_t out_copy_handle_index;
|
||||
};
|
||||
|
||||
template<u16 _CommandId, typename ArgumentsTuple>
|
||||
struct CommandMetaInfo;
|
||||
|
||||
template<u16 _CommandId, typename... Arguments>
|
||||
struct CommandMetaInfo {
|
||||
struct CommandMetaInfo<_CommandId, std::tuple<Arguments...>> {
|
||||
public:
|
||||
static constexpr u16 CommandId = _CommandId;
|
||||
|
||||
|
@ -587,10 +590,22 @@ namespace ams::tipc::impl {
|
|||
}
|
||||
};
|
||||
|
||||
template<auto ServiceCommandImpl, u16 _CommmandId, typename Return, typename ClassType, typename... Arguments>
|
||||
struct FunctionTraits {
|
||||
public:
|
||||
template<typename R, typename C, typename... A>
|
||||
static std::tuple<A...> GetArgumentsImpl(R(C::*)(A...));
|
||||
|
||||
template<typename R, typename C, typename... A>
|
||||
static R GetReturnImpl(R(C::*)(A...));
|
||||
};
|
||||
|
||||
template<u16 _CommmandId, auto ServiceCommandImpl, typename ClassType>
|
||||
constexpr ALWAYS_INLINE Result InvokeServiceCommandImpl(ClassType *object, const svc::ipc::MessageBuffer &message_buffer) {
|
||||
using CommandMeta = CommandMetaInfo<_CommmandId, Arguments...>;
|
||||
using Processor = CommandProcessor<CommandMeta>;
|
||||
using Return = decltype(FunctionTraits::GetReturnImpl(ServiceCommandImpl));
|
||||
using TrueArgumentsTuple = decltype(FunctionTraits::GetArgumentsImpl(ServiceCommandImpl));
|
||||
|
||||
using CommandMeta = CommandMetaInfo<_CommmandId, TrueArgumentsTuple>;
|
||||
using Processor = CommandProcessor<CommandMeta>;
|
||||
/* TODO: ValidateClassType is valid? */
|
||||
|
||||
constexpr bool ReturnsResult = std::is_same<Return, Result>::value;
|
||||
|
@ -606,8 +621,6 @@ namespace ams::tipc::impl {
|
|||
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...>;
|
||||
|
||||
if constexpr (ReturnsResult) {
|
||||
return (object->*ServiceCommandImpl)(std::forward<typename std::tuple_element<Ix, TrueArgumentsTuple>::type>(std::get<Ix>(args_tuple))...);
|
||||
} else {
|
||||
|
|
|
@ -24,7 +24,8 @@ namespace ams::tipc {
|
|||
|
||||
template<typename Impl>
|
||||
class EmplacedImplHolderBaseGetter {
|
||||
using Type = Impl;
|
||||
public:
|
||||
using Type = Impl;
|
||||
};
|
||||
|
||||
template<typename Impl>
|
||||
|
|
|
@ -14,6 +14,16 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include <stratosphere/tipc/impl/tipc_autogen_interface_macros.hpp>
|
||||
|
||||
#define AMS_TEST_I_USER_INTERFACE_INTERFACE_INFO(C, H) \
|
||||
AMS_TIPC_METHOD_INFO(C, H, 0, Result, RegisterClient, (const tipc::ClientProcessId &client_process_id), (client_process_id)) \
|
||||
AMS_TIPC_METHOD_INFO(C, H, 1, Result, GetServiceHandle, (tipc::OutMoveHandle out_h, sm::ServiceName service), (out_h, service)) \
|
||||
AMS_TIPC_METHOD_INFO(C, H, 2, Result, RegisterService, (tipc::OutMoveHandle out_h, sm::ServiceName service, u32 max_sessions, bool is_light), (out_h, service, max_sessions, is_light)) \
|
||||
AMS_TIPC_METHOD_INFO(C, H, 3, Result, UnregisterService, (sm::ServiceName service), (service))
|
||||
|
||||
AMS_TIPC_DEFINE_INTERFACE(ams::_test::impl, IUserInterface, AMS_TEST_I_USER_INTERFACE_INTERFACE_INFO)
|
||||
|
||||
|
||||
namespace ams::_test {
|
||||
|
||||
|
@ -24,39 +34,31 @@ namespace ams::_test {
|
|||
Result RegisterService(tipc::OutMoveHandle out_h, sm::ServiceName service, u32 max_sessions, bool is_light);
|
||||
Result UnregisterService(sm::ServiceName service);
|
||||
};
|
||||
static_assert(impl::IsIUserInterface<UserInterfaceFacade>);
|
||||
|
||||
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);
|
||||
return tipc::impl::InvokeServiceCommandImpl<16, &UserInterfaceFacade::RegisterClient, UserInterfaceFacade>(facade, message_buffer);
|
||||
case 17:
|
||||
return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::GetServiceHandle, 17, Result, UserInterfaceFacade, tipc::OutMoveHandle, sm::ServiceName>(facade, message_buffer);
|
||||
return tipc::impl::InvokeServiceCommandImpl<17, &UserInterfaceFacade::GetServiceHandle, UserInterfaceFacade>(facade, message_buffer);
|
||||
case 18:
|
||||
return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::RegisterService, 18, Result, UserInterfaceFacade, tipc::OutMoveHandle, sm::ServiceName, u32, bool>(facade, message_buffer);
|
||||
return tipc::impl::InvokeServiceCommandImpl<18, &UserInterfaceFacade::RegisterService, UserInterfaceFacade>(facade, message_buffer);
|
||||
case 19:
|
||||
return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::UnregisterService, 19, Result, UserInterfaceFacade, sm::ServiceName>(facade, message_buffer);
|
||||
return tipc::impl::InvokeServiceCommandImpl<19, &UserInterfaceFacade::UnregisterService, UserInterfaceFacade>(facade, message_buffer);
|
||||
default:
|
||||
return tipc::ResultInvalidMethod();
|
||||
}
|
||||
}
|
||||
|
||||
using UserInterfaceObject = ::ams::tipc::ServiceObject<impl::IUserInterface, UserInterfaceFacade>;
|
||||
|
||||
Result TestAutomaticDispatch(UserInterfaceObject *object) {
|
||||
return object->ProcessRequest();
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in a new issue