service.h 9.5 KB

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