sm.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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_server_session.h"
  11. #include "core/hle/kernel/k_session.h"
  12. #include "core/hle/kernel/server_port.h"
  13. #include "core/hle/result.h"
  14. #include "core/hle/service/sm/controller.h"
  15. #include "core/hle/service/sm/sm.h"
  16. namespace Service::SM {
  17. constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::SM, 4);
  18. constexpr ResultCode ERR_INVALID_NAME(ErrorModule::SM, 6);
  19. constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7);
  20. ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} {}
  21. ServiceManager::~ServiceManager() = default;
  22. void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) {
  23. controller_interface->InvokeRequest(context);
  24. }
  25. static ResultCode ValidateServiceName(const std::string& name) {
  26. if (name.empty() || name.size() > 8) {
  27. LOG_ERROR(Service_SM, "Invalid service name! service={}", name);
  28. return ERR_INVALID_NAME;
  29. }
  30. if (name.rfind('\0') != std::string::npos) {
  31. LOG_ERROR(Service_SM, "A non null terminated service was passed");
  32. return ERR_INVALID_NAME;
  33. }
  34. return RESULT_SUCCESS;
  35. }
  36. void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system) {
  37. ASSERT(self->sm_interface.expired());
  38. auto sm = std::make_shared<SM>(self, system);
  39. sm->InstallAsNamedPort(system.Kernel());
  40. self->sm_interface = sm;
  41. self->controller_interface = std::make_unique<Controller>(system);
  42. }
  43. ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(std::string name,
  44. u32 max_sessions) {
  45. CASCADE_CODE(ValidateServiceName(name));
  46. if (registered_services.find(name) != registered_services.end()) {
  47. LOG_ERROR(Service_SM, "Service is already registered! service={}", name);
  48. return ERR_ALREADY_REGISTERED;
  49. }
  50. auto [server_port, client_port] =
  51. Kernel::ServerPort::CreatePortPair(kernel, max_sessions, name);
  52. client_port->Open();
  53. registered_services.emplace(std::move(name), std::move(client_port));
  54. return MakeResult(std::move(server_port));
  55. }
  56. ResultCode ServiceManager::UnregisterService(const std::string& name) {
  57. CASCADE_CODE(ValidateServiceName(name));
  58. const auto iter = registered_services.find(name);
  59. if (iter == registered_services.end()) {
  60. LOG_ERROR(Service_SM, "Server is not registered! service={}", name);
  61. return ERR_SERVICE_NOT_REGISTERED;
  62. }
  63. iter->second->Close();
  64. registered_services.erase(iter);
  65. return RESULT_SUCCESS;
  66. }
  67. ResultVal<Kernel::KClientPort*> ServiceManager::GetServicePort(const std::string& name) {
  68. CASCADE_CODE(ValidateServiceName(name));
  69. auto it = registered_services.find(name);
  70. if (it == registered_services.end()) {
  71. LOG_ERROR(Service_SM, "Server is not registered! service={}", name);
  72. return ERR_SERVICE_NOT_REGISTERED;
  73. }
  74. return MakeResult(it->second);
  75. }
  76. SM::~SM() = default;
  77. /**
  78. * SM::Initialize service function
  79. * Inputs:
  80. * 0: 0x00000000
  81. * Outputs:
  82. * 0: ResultCode
  83. */
  84. void SM::Initialize(Kernel::HLERequestContext& ctx) {
  85. LOG_DEBUG(Service_SM, "called");
  86. IPC::ResponseBuilder rb{ctx, 2};
  87. rb.Push(RESULT_SUCCESS);
  88. }
  89. void SM::GetService(Kernel::HLERequestContext& ctx) {
  90. IPC::RequestParser rp{ctx};
  91. auto name_buf = rp.PopRaw<std::array<char, 8>>();
  92. auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
  93. std::string name(name_buf.begin(), end);
  94. auto client_port = service_manager->GetServicePort(name);
  95. if (client_port.Failed()) {
  96. IPC::ResponseBuilder rb{ctx, 2};
  97. rb.Push(client_port.Code());
  98. LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, client_port.Code().raw);
  99. if (name.length() == 0)
  100. return; // LibNX Fix
  101. UNIMPLEMENTED();
  102. return;
  103. }
  104. auto* session = Kernel::KSession::Create(kernel);
  105. session->Initialize(std::move(name));
  106. const auto& server_port = client_port.Unwrap()->GetServerPort();
  107. if (server_port->GetHLEHandler()) {
  108. server_port->GetHLEHandler()->ClientConnected(session);
  109. } else {
  110. server_port->AppendPendingSession(&session->GetServerSession());
  111. }
  112. LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetObjectId());
  113. IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
  114. rb.Push(RESULT_SUCCESS);
  115. rb.PushMoveObjects(session->GetClientSession());
  116. }
  117. void SM::RegisterService(Kernel::HLERequestContext& ctx) {
  118. IPC::RequestParser rp{ctx};
  119. const auto name_buf = rp.PopRaw<std::array<char, 8>>();
  120. const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
  121. const std::string name(name_buf.begin(), end);
  122. const auto is_light = static_cast<bool>(rp.PopRaw<u32>());
  123. const auto max_session_count = rp.PopRaw<u32>();
  124. LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name,
  125. max_session_count, is_light);
  126. auto handle = service_manager->RegisterService(name, max_session_count);
  127. if (handle.Failed()) {
  128. LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}",
  129. handle.Code().raw);
  130. IPC::ResponseBuilder rb{ctx, 2};
  131. rb.Push(handle.Code());
  132. return;
  133. }
  134. IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
  135. rb.Push(handle.Code());
  136. auto server_port = handle.Unwrap();
  137. rb.PushMoveObjects(server_port.get());
  138. }
  139. void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
  140. IPC::RequestParser rp{ctx};
  141. const auto name_buf = rp.PopRaw<std::array<char, 8>>();
  142. const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
  143. const std::string name(name_buf.begin(), end);
  144. LOG_DEBUG(Service_SM, "called with name={}", name);
  145. IPC::ResponseBuilder rb{ctx, 2};
  146. rb.Push(service_manager->UnregisterService(name));
  147. }
  148. SM::SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_)
  149. : ServiceFramework{system_, "sm:", 4},
  150. service_manager{std::move(service_manager_)}, kernel{system_.Kernel()} {
  151. static const FunctionInfo functions[] = {
  152. {0, &SM::Initialize, "Initialize"},
  153. {1, &SM::GetService, "GetService"},
  154. {2, &SM::RegisterService, "RegisterService"},
  155. {3, &SM::UnregisterService, "UnregisterService"},
  156. {4, nullptr, "DetachClient"},
  157. };
  158. RegisterHandlers(functions);
  159. }
  160. } // namespace Service::SM