skyline/app/src/main/cpp/skyline/services/base_service.h
Billy Laws 51f4e7662e Add support for the TIPC protocol introduced in HOS 12.0.0
TIPC is a much lighter layer ontop of the Horizon IPC system than CMIF and is used by SM in 12.0.0+. This implementation is slightly hacky since it doesn't really keep a seperation between the underlying kernel IPC stuff and userspace like CMIF/TIPC, this should be fixed eventually, probably together with an IPC dispatch rewrite to avoid the mess of frozen maps.

Tested with Hentai Uni, which now crashes needing 'ldr:ro'.
2022-09-02 23:13:23 +01:00

92 lines
5.3 KiB
C++

// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#pragma once
#include <kernel/ipc.h>
constexpr static skyline::u32 TipcFunctionIdFlag{1U << 31}; //!< Flag applied to the stored service function ID to differentiate between TIPC and HIPC functions
#define SERVICE_STRINGIFY(string) #string
#define SFUNC(id, Class, Function) std::pair<u32, std::pair<Result(Class::*)(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &), const char*>>{id, {&Class::Function, SERVICE_STRINGIFY(Class::Function)}}
#define SFUNC_TIPC(id, Class, Function) std::pair<u32, std::pair<Result(Class::*)(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &), const char*>>{TipcFunctionIdFlag | id, {&Class::Function, SERVICE_STRINGIFY(Class::Function)}}
#define SFUNC_BASE(id, Class, BaseClass, Function) std::pair<u32, std::pair<Result(Class::*)(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &), const char*>>{id, {&Class::CallBaseFunction<BaseClass, decltype(&BaseClass::Function), &BaseClass::Function>, SERVICE_STRINGIFY(Class::Function)}}
#define SERVICE_DECL_AUTO(name, value) decltype(value) name = value
#define SERVICE_DECL(...) \
private: \
template<typename BaseClass, typename BaseFunctionType, BaseFunctionType BaseFunction> \
Result CallBaseFunction(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { \
return (static_cast<BaseClass *>(this)->*BaseFunction)(session, request, response); \
} \
SERVICE_DECL_AUTO(functions, frozen::make_unordered_map({__VA_ARGS__})); \
protected: \
ServiceFunctionDescriptor GetServiceFunction(u32 id, bool isTipc) override { \
auto& function{functions.at((isTipc ? TipcFunctionIdFlag : 0U) | id)}; \
return ServiceFunctionDescriptor{ \
reinterpret_cast<DerivedService*>(this), \
reinterpret_cast<decltype(ServiceFunctionDescriptor::function)>(function.first), \
function.second \
}; \
}
#define SRVREG(class, ...) std::make_shared<class>(state, manager, ##__VA_ARGS__)
namespace skyline::kernel::type {
class KSession;
}
namespace skyline::service {
using namespace kernel;
using ServiceName = u64; //!< Service names are a maximum of 8 bytes so we use a u64 to store them
class ServiceManager;
/**
* @brief The base class for the HOS service interfaces hosted by sysmodules
*/
class BaseService : public std::enable_shared_from_this<BaseService> {
private:
std::string name; //!< The name of the service, it's only assigned after GetName is called and shouldn't be used directly
protected:
const DeviceState &state;
ServiceManager &manager;
class DerivedService; //!< A placeholder derived class which is used for class function semantics
/**
* @brief A per-function descriptor for HLE service functions
*/
struct ServiceFunctionDescriptor {
DerivedService *clazz; //!< A pointer to the class that this was derived from, it's used as the 'this' pointer for the function
Result (DerivedService::*function)(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &); //!< A function pointer to a HLE implementation of the service function
const char *name; //!< A pointer to a static string in the format "Class::Function" for the specific service class/function
constexpr Result operator()(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
return (clazz->*function)(session, request, response);
}
};
public:
BaseService(const DeviceState &state, ServiceManager &manager) : state(state), manager(manager) {}
/**
* @note To be able to extract the name of the underlying class and ensure correct destruction order
*/
virtual ~BaseService() = default;
virtual ServiceFunctionDescriptor GetServiceFunction(u32 id, bool isTipc) {
throw std::out_of_range("GetServiceFunction not implemented");
}
/**
* @return A string with the name of the service class
* @note The lifetime of the returned string is tied to that of the class
*/
const std::string &GetName();
/**
* @brief Handles an IPC Request to a service
*/
Result HandleRequest(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
};
}