sm.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <tuple>
  5. #include "common/assert.h"
  6. #include "core/core.h"
  7. #include "core/hle/ipc_helpers.h"
  8. #include "core/hle/kernel/k_client_port.h"
  9. #include "core/hle/kernel/k_client_session.h"
  10. #include "core/hle/kernel/k_port.h"
  11. #include "core/hle/kernel/k_scoped_resource_reservation.h"
  12. #include "core/hle/kernel/k_server_port.h"
  13. #include "core/hle/kernel/k_server_session.h"
  14. #include "core/hle/kernel/k_session.h"
  15. #include "core/hle/result.h"
  16. #include "core/hle/service/sm/controller.h"
  17. #include "core/hle/service/sm/sm.h"
  18. namespace Service::SM {
  19. constexpr ResultCode ERR_NOT_INITIALIZED(ErrorModule::SM, 2);
  20. constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::SM, 4);
  21. constexpr ResultCode ERR_INVALID_NAME(ErrorModule::SM, 6);
  22. constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7);
  23. ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} {}
  24. ServiceManager::~ServiceManager() = default;
  25. void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) {
  26. controller_interface->InvokeRequest(context);
  27. }
  28. static ResultCode ValidateServiceName(const std::string& name) {
  29. if (name.empty() || name.size() > 8) {
  30. LOG_ERROR(Service_SM, "Invalid service name! service={}", name);
  31. return ERR_INVALID_NAME;
  32. }
  33. return RESULT_SUCCESS;
  34. }
  35. Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core::System& system) {
  36. ASSERT(self.sm_interface.expired());
  37. auto sm = std::make_shared<SM>(self, system);
  38. self.sm_interface = sm;
  39. self.controller_interface = std::make_unique<Controller>(system);
  40. return sm->CreatePort(system.Kernel());
  41. }
  42. ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name,
  43. u32 max_sessions) {
  44. CASCADE_CODE(ValidateServiceName(name));
  45. if (registered_services.find(name) != registered_services.end()) {
  46. LOG_ERROR(Service_SM, "Service is already registered! service={}", name);
  47. return ERR_ALREADY_REGISTERED;
  48. }
  49. auto* port = Kernel::KPort::Create(kernel);
  50. port->Initialize(max_sessions, false, name);
  51. registered_services.emplace(std::move(name), port);
  52. return MakeResult(&port->GetServerPort());
  53. }
  54. ResultCode ServiceManager::UnregisterService(const std::string& name) {
  55. CASCADE_CODE(ValidateServiceName(name));
  56. const auto iter = registered_services.find(name);
  57. if (iter == registered_services.end()) {
  58. LOG_ERROR(Service_SM, "Server is not registered! service={}", name);
  59. return ERR_SERVICE_NOT_REGISTERED;
  60. }
  61. iter->second->Close();
  62. registered_services.erase(iter);
  63. return RESULT_SUCCESS;
  64. }
  65. ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name) {
  66. CASCADE_CODE(ValidateServiceName(name));
  67. auto it = registered_services.find(name);
  68. if (it == registered_services.end()) {
  69. LOG_ERROR(Service_SM, "Server is not registered! service={}", name);
  70. return ERR_SERVICE_NOT_REGISTERED;
  71. }
  72. return MakeResult(it->second);
  73. }
  74. SM::~SM() = default;
  75. /**
  76. * SM::Initialize service function
  77. * Inputs:
  78. * 0: 0x00000000
  79. * Outputs:
  80. * 0: ResultCode
  81. */
  82. void SM::Initialize(Kernel::HLERequestContext& ctx) {
  83. LOG_DEBUG(Service_SM, "called");
  84. is_initialized = true;
  85. IPC::ResponseBuilder rb{ctx, 2};
  86. rb.Push(RESULT_SUCCESS);
  87. }
  88. void SM::GetService(Kernel::HLERequestContext& ctx) {
  89. auto result = GetServiceImpl(ctx);
  90. if (result.Succeeded()) {
  91. IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
  92. rb.Push(result.Code());
  93. rb.PushMoveObjects(result.Unwrap());
  94. } else {
  95. IPC::ResponseBuilder rb{ctx, 2};
  96. rb.Push(result.Code());
  97. }
  98. }
  99. void SM::GetServiceTipc(Kernel::HLERequestContext& ctx) {
  100. auto result = GetServiceImpl(ctx);
  101. IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
  102. rb.Push(result.Code());
  103. rb.PushMoveObjects(result.Succeeded() ? result.Unwrap() : nullptr);
  104. }
  105. static std::string PopServiceName(IPC::RequestParser& rp) {
  106. auto name_buf = rp.PopRaw<std::array<char, 8>>();
  107. std::string result;
  108. for (const auto& c : name_buf) {
  109. if (c >= ' ' && c <= '~') {
  110. result.push_back(c);
  111. }
  112. }
  113. return result;
  114. }
  115. ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& ctx) {
  116. if (!is_initialized) {
  117. return ERR_NOT_INITIALIZED;
  118. }
  119. IPC::RequestParser rp{ctx};
  120. std::string name(PopServiceName(rp));
  121. auto result = service_manager.GetServicePort(name);
  122. if (result.Failed()) {
  123. LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw);
  124. return result.Code();
  125. }
  126. auto* port = result.Unwrap();
  127. // Kernel::KScopedResourceReservation session_reservation(
  128. // kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions);
  129. // R_UNLESS(session_reservation.Succeeded(), Kernel::ResultLimitReached);
  130. auto* session = Kernel::KSession::Create(kernel);
  131. session->Initialize(&port->GetClientPort(), std::move(name));
  132. // Commit the session reservation.
  133. // session_reservation.Commit();
  134. if (port->GetServerPort().GetHLEHandler()) {
  135. port->GetServerPort().GetHLEHandler()->ClientConnected(&session->GetServerSession());
  136. } else {
  137. port->EnqueueSession(&session->GetServerSession());
  138. }
  139. LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId());
  140. return MakeResult(&session->GetClientSession());
  141. }
  142. void SM::RegisterService(Kernel::HLERequestContext& ctx) {
  143. IPC::RequestParser rp{ctx};
  144. std::string name(PopServiceName(rp));
  145. const auto is_light = static_cast<bool>(rp.PopRaw<u32>());
  146. const auto max_session_count = rp.PopRaw<u32>();
  147. LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name,
  148. max_session_count, is_light);
  149. auto handle = service_manager.RegisterService(name, max_session_count);
  150. if (handle.Failed()) {
  151. LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}",
  152. handle.Code().raw);
  153. IPC::ResponseBuilder rb{ctx, 2};
  154. rb.Push(handle.Code());
  155. return;
  156. }
  157. IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
  158. rb.Push(handle.Code());
  159. auto server_port = handle.Unwrap();
  160. rb.PushMoveObjects(server_port);
  161. }
  162. void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
  163. IPC::RequestParser rp{ctx};
  164. std::string name(PopServiceName(rp));
  165. LOG_DEBUG(Service_SM, "called with name={}", name);
  166. IPC::ResponseBuilder rb{ctx, 2};
  167. rb.Push(service_manager.UnregisterService(name));
  168. }
  169. SM::SM(ServiceManager& service_manager_, Core::System& system_)
  170. : ServiceFramework{system_, "sm:", 4},
  171. service_manager{service_manager_}, kernel{system_.Kernel()} {
  172. RegisterHandlers({
  173. {0, &SM::Initialize, "Initialize"},
  174. {1, &SM::GetService, "GetService"},
  175. {2, &SM::RegisterService, "RegisterService"},
  176. {3, &SM::UnregisterService, "UnregisterService"},
  177. {4, nullptr, "DetachClient"},
  178. });
  179. RegisterHandlersTipc({
  180. {0, &SM::Initialize, "Initialize"},
  181. {1, &SM::GetServiceTipc, "GetService"},
  182. {2, &SM::RegisterService, "RegisterService"},
  183. {3, &SM::UnregisterService, "UnregisterService"},
  184. {4, nullptr, "DetachClient"},
  185. });
  186. }
  187. } // namespace Service::SM