service.h 8.8 KB

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