service.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <cstddef>
  6. #include <mutex>
  7. #include <string>
  8. #include <boost/container/flat_map.hpp>
  9. #include "common/common_types.h"
  10. #include "common/spin_lock.h"
  11. #include "core/hle/kernel/hle_ipc.h"
  12. ////////////////////////////////////////////////////////////////////////////////////////////////////
  13. // Namespace Service
  14. namespace Core {
  15. class System;
  16. }
  17. namespace Kernel {
  18. class HLERequestContext;
  19. class KClientPort;
  20. class KServerSession;
  21. } // namespace Kernel
  22. namespace Service {
  23. namespace FileSystem {
  24. class FileSystemController;
  25. }
  26. namespace NVFlinger {
  27. class NVFlinger;
  28. }
  29. namespace SM {
  30. class ServiceManager;
  31. }
  32. static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
  33. /// Arbitrary default number of maximum connections to an HLE service.
  34. static const u32 DefaultMaxSessions = 10;
  35. /**
  36. * This is an non-templated base of ServiceFramework to reduce code bloat and compilation times, it
  37. * is not meant to be used directly.
  38. *
  39. * @see ServiceFramework
  40. */
  41. class ServiceFrameworkBase : public Kernel::SessionRequestHandler {
  42. public:
  43. /// Returns the string identifier used to connect to the service.
  44. std::string GetServiceName() const {
  45. return service_name;
  46. }
  47. /**
  48. * Returns the maximum number of sessions that can be connected to this service at the same
  49. * time.
  50. */
  51. u32 GetMaxSessions() const {
  52. return max_sessions;
  53. }
  54. /// Creates a port pair and registers this service with the given ServiceManager.
  55. void InstallAsService(SM::ServiceManager& service_manager);
  56. /// Invokes a service request routine using the HIPC protocol.
  57. void InvokeRequest(Kernel::HLERequestContext& ctx);
  58. /// Invokes a service request routine using the HIPC protocol.
  59. void InvokeRequestTipc(Kernel::HLERequestContext& ctx);
  60. /// Creates a port pair and registers it on the kernel's global port registry.
  61. Kernel::KClientPort& CreatePort(Kernel::KernelCore& kernel);
  62. /// Handles a synchronization request for the service.
  63. ResultCode HandleSyncRequest(Kernel::KServerSession& session,
  64. Kernel::HLERequestContext& context) override;
  65. protected:
  66. /// Member-function pointer type of SyncRequest handlers.
  67. template <typename Self>
  68. using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&);
  69. /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
  70. [[nodiscard]] std::scoped_lock<Common::SpinLock> LockService() {
  71. return std::scoped_lock{lock_service};
  72. }
  73. /// System context that the service operates under.
  74. Core::System& system;
  75. private:
  76. template <typename T>
  77. friend class ServiceFramework;
  78. struct FunctionInfoBase {
  79. u32 expected_header;
  80. HandlerFnP<ServiceFrameworkBase> handler_callback;
  81. const char* name;
  82. };
  83. using InvokerFn = void(ServiceFrameworkBase* object, HandlerFnP<ServiceFrameworkBase> member,
  84. Kernel::HLERequestContext& ctx);
  85. explicit ServiceFrameworkBase(Core::System& system_, const char* service_name_,
  86. u32 max_sessions_, InvokerFn* handler_invoker_);
  87. ~ServiceFrameworkBase() override;
  88. void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n);
  89. void RegisterHandlersBaseTipc(const FunctionInfoBase* functions, std::size_t n);
  90. void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info);
  91. /// Identifier string used to connect to the service.
  92. std::string service_name;
  93. /// Maximum number of concurrent sessions that this service can handle.
  94. u32 max_sessions;
  95. /// Flag to store if a port was already create/installed to detect multiple install attempts,
  96. /// which is not supported.
  97. bool port_installed = false;
  98. /// Function used to safely up-cast pointers to the derived class before invoking a handler.
  99. InvokerFn* handler_invoker;
  100. boost::container::flat_map<u32, FunctionInfoBase> handlers;
  101. boost::container::flat_map<u32, FunctionInfoBase> handlers_tipc;
  102. /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
  103. Common::SpinLock lock_service;
  104. };
  105. /**
  106. * Framework for implementing HLE services. Dispatches on the header id of incoming SyncRequests
  107. * based on a table mapping header ids to handler functions. Service implementations should inherit
  108. * from ServiceFramework using the CRTP (`class Foo : public ServiceFramework<Foo> { ... };`) and
  109. * populate it with handlers by calling #RegisterHandlers.
  110. *
  111. * In order to avoid duplicating code in the binary and exposing too many implementation details in
  112. * the header, this class is split into a non-templated base (ServiceFrameworkBase) and a template
  113. * deriving from it (ServiceFramework). The functions in this class will mostly only erase the type
  114. * of the passed in function pointers and then delegate the actual work to the implementation in the
  115. * base class.
  116. */
  117. template <typename Self>
  118. class ServiceFramework : public ServiceFrameworkBase {
  119. protected:
  120. /// Contains information about a request type which is handled by the service.
  121. struct FunctionInfo : FunctionInfoBase {
  122. // TODO(yuriks): This function could be constexpr, but clang is the only compiler that
  123. // doesn't emit an ICE or a wrong diagnostic because of the static_cast.
  124. /**
  125. * Constructs a FunctionInfo for a function.
  126. *
  127. * @param expected_header_ request header in the command buffer which will trigger dispatch
  128. * to this handler
  129. * @param handler_callback_ member function in this service which will be called to handle
  130. * the request
  131. * @param name_ human-friendly name for the request. Used mostly for logging purposes.
  132. */
  133. FunctionInfo(u32 expected_header_, HandlerFnP<Self> handler_callback_, const char* name_)
  134. : FunctionInfoBase{
  135. expected_header_,
  136. // Type-erase member function pointer by casting it down to the base class.
  137. static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback_), name_} {}
  138. };
  139. /**
  140. * Initializes the handler with no functions installed.
  141. *
  142. * @param system_ The system context to construct this service under.
  143. * @param service_name_ Name of the service.
  144. * @param max_sessions_ Maximum number of sessions that can be
  145. * connected to this service at the same time.
  146. */
  147. explicit ServiceFramework(Core::System& system_, const char* service_name_,
  148. u32 max_sessions_ = DefaultMaxSessions)
  149. : ServiceFrameworkBase(system_, service_name_, max_sessions_, Invoker) {}
  150. /// Registers handlers in the service.
  151. template <std::size_t N>
  152. void RegisterHandlers(const FunctionInfo (&functions)[N]) {
  153. RegisterHandlers(functions, N);
  154. }
  155. /**
  156. * Registers handlers in the service. Usually prefer using the other RegisterHandlers
  157. * overload in order to avoid needing to specify the array size.
  158. */
  159. void RegisterHandlers(const FunctionInfo* functions, std::size_t n) {
  160. RegisterHandlersBase(functions, n);
  161. }
  162. /// Registers handlers in the service.
  163. template <std::size_t N>
  164. void RegisterHandlersTipc(const FunctionInfo (&functions)[N]) {
  165. RegisterHandlersTipc(functions, N);
  166. }
  167. /**
  168. * Registers handlers in the service. Usually prefer using the other RegisterHandlers
  169. * overload in order to avoid needing to specify the array size.
  170. */
  171. void RegisterHandlersTipc(const FunctionInfo* functions, std::size_t n) {
  172. RegisterHandlersBaseTipc(functions, n);
  173. }
  174. private:
  175. /**
  176. * This function is used to allow invocation of pointers to handlers stored in the base class
  177. * without needing to expose the type of this derived class. Pointers-to-member may require a
  178. * fixup when being up or downcast, and thus code that does that needs to know the concrete type
  179. * of the derived class in order to invoke one of it's functions through a pointer.
  180. */
  181. static void Invoker(ServiceFrameworkBase* object, HandlerFnP<ServiceFrameworkBase> member,
  182. Kernel::HLERequestContext& ctx) {
  183. // Cast back up to our original types and call the member function
  184. (static_cast<Self*>(object)->*static_cast<HandlerFnP<Self>>(member))(ctx);
  185. }
  186. };
  187. /**
  188. * The purpose of this class is to own any objects that need to be shared across the other service
  189. * implementations. Will be torn down when the global system instance is shutdown.
  190. */
  191. class Services final {
  192. public:
  193. explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system);
  194. ~Services();
  195. private:
  196. std::unique_ptr<NVFlinger::NVFlinger> nv_flinger;
  197. };
  198. } // namespace Service