| 
									
										
										
										
											2018-01-13 16:22:39 -05:00
										 |  |  | // Copyright 2018 yuzu emulator team
 | 
					
						
							| 
									
										
										
										
											2017-06-05 23:31:59 -07:00
										 |  |  | // Licensed under GPLv2 or any later version
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <tuple>
 | 
					
						
							| 
									
										
										
										
											2017-06-06 21:25:28 -07:00
										 |  |  | #include "common/assert.h"
 | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  | #include "core/core.h"
 | 
					
						
							| 
									
										
										
										
											2017-10-14 22:18:42 -04:00
										 |  |  | #include "core/hle/ipc_helpers.h"
 | 
					
						
							| 
									
										
										
										
											2017-06-06 01:29:46 -07:00
										 |  |  | #include "core/hle/kernel/client_port.h"
 | 
					
						
							| 
									
										
										
										
											2017-06-05 23:31:59 -07:00
										 |  |  | #include "core/hle/kernel/client_session.h"
 | 
					
						
							|  |  |  | #include "core/hle/kernel/server_port.h"
 | 
					
						
							|  |  |  | #include "core/hle/result.h"
 | 
					
						
							| 
									
										
										
										
											2017-10-14 22:18:42 -04:00
										 |  |  | #include "core/hle/service/sm/controller.h"
 | 
					
						
							| 
									
										
										
										
											2017-06-05 23:31:59 -07:00
										 |  |  | #include "core/hle/service/sm/sm.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-19 21:41:44 -04:00
										 |  |  | namespace Service::SM { | 
					
						
							| 
									
										
										
										
											2017-06-05 23:31:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-14 01:43:59 -04:00
										 |  |  | constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::SM, 4); | 
					
						
							|  |  |  | constexpr ResultCode ERR_INVALID_NAME(ErrorModule::SM, 6); | 
					
						
							|  |  |  | constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-06 14:32:25 -04:00
										 |  |  | ServiceManager::ServiceManager() = default; | 
					
						
							| 
									
										
										
										
											2018-04-20 19:29:04 -04:00
										 |  |  | ServiceManager::~ServiceManager() = default; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-14 22:18:42 -04:00
										 |  |  | void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) { | 
					
						
							|  |  |  |     controller_interface->InvokeRequest(context); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-05 23:31:59 -07:00
										 |  |  | static ResultCode ValidateServiceName(const std::string& name) { | 
					
						
							|  |  |  |     if (name.size() <= 0 || name.size() > 8) { | 
					
						
							| 
									
										
										
										
											2020-04-29 11:15:21 +10:00
										 |  |  |         LOG_ERROR(Service_SM, "Invalid service name! service={}", name); | 
					
						
							| 
									
										
										
										
											2018-09-14 01:43:59 -04:00
										 |  |  |         return ERR_INVALID_NAME; | 
					
						
							| 
									
										
										
										
											2017-06-05 23:31:59 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (name.find('\0') != std::string::npos) { | 
					
						
							| 
									
										
										
										
											2020-04-29 11:15:21 +10:00
										 |  |  |         LOG_ERROR(Service_SM, "A non null terminated service was passed"); | 
					
						
							| 
									
										
										
										
											2018-09-14 01:43:59 -04:00
										 |  |  |         return ERR_INVALID_NAME; | 
					
						
							| 
									
										
										
										
											2017-06-05 23:31:59 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     return RESULT_SUCCESS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-25 18:28:48 -05:00
										 |  |  | void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self, | 
					
						
							|  |  |  |                                        Kernel::KernelCore& kernel) { | 
					
						
							| 
									
										
										
										
											2017-10-14 22:18:42 -04:00
										 |  |  |     ASSERT(self->sm_interface.expired()); | 
					
						
							| 
									
										
										
										
											2017-06-06 21:25:28 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-25 18:28:48 -05:00
										 |  |  |     auto sm = std::make_shared<SM>(self, kernel); | 
					
						
							| 
									
										
										
										
											2017-10-14 22:18:42 -04:00
										 |  |  |     sm->InstallAsNamedPort(); | 
					
						
							|  |  |  |     self->sm_interface = sm; | 
					
						
							|  |  |  |     self->controller_interface = std::make_unique<Controller>(); | 
					
						
							| 
									
										
										
										
											2017-06-06 21:25:28 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-24 20:15:51 -05:00
										 |  |  | ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService( | 
					
						
							| 
									
										
										
										
											2017-06-05 23:31:59 -07:00
										 |  |  |     std::string name, unsigned int max_sessions) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     CASCADE_CODE(ValidateServiceName(name)); | 
					
						
							| 
									
										
										
										
											2017-09-24 00:12:58 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-29 11:15:21 +10:00
										 |  |  |     if (registered_services.find(name) != registered_services.end()) { | 
					
						
							|  |  |  |         LOG_ERROR(Service_SM, "Service is already registered! service={}", name); | 
					
						
							| 
									
										
										
										
											2017-09-24 00:12:58 -05:00
										 |  |  |         return ERR_ALREADY_REGISTERED; | 
					
						
							| 
									
										
										
										
											2020-04-29 11:15:21 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-24 00:12:58 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |     auto& kernel = Core::System::GetInstance().Kernel(); | 
					
						
							| 
									
										
										
										
											2018-12-06 01:29:17 -05:00
										 |  |  |     auto [server_port, client_port] = | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |         Kernel::ServerPort::CreatePortPair(kernel, max_sessions, name); | 
					
						
							| 
									
										
										
										
											2017-06-05 23:31:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-06 21:25:28 -07:00
										 |  |  |     registered_services.emplace(std::move(name), std::move(client_port)); | 
					
						
							| 
									
										
										
										
											2018-12-06 01:33:19 -05:00
										 |  |  |     return MakeResult(std::move(server_port)); | 
					
						
							| 
									
										
										
										
											2017-06-05 23:31:59 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-24 00:04:07 -05:00
										 |  |  | ResultCode ServiceManager::UnregisterService(const std::string& name) { | 
					
						
							| 
									
										
										
										
											2018-11-03 20:02:18 -04:00
										 |  |  |     CASCADE_CODE(ValidateServiceName(name)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const auto iter = registered_services.find(name); | 
					
						
							| 
									
										
										
										
											2020-04-29 11:15:21 +10:00
										 |  |  |     if (iter == registered_services.end()) { | 
					
						
							|  |  |  |         LOG_ERROR(Service_SM, "Server is not registered! service={}", name); | 
					
						
							| 
									
										
										
										
											2018-11-03 20:02:18 -04:00
										 |  |  |         return ERR_SERVICE_NOT_REGISTERED; | 
					
						
							| 
									
										
										
										
											2020-04-29 11:15:21 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-11-03 20:02:18 -04:00
										 |  |  |     registered_services.erase(iter); | 
					
						
							|  |  |  |     return RESULT_SUCCESS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-24 20:15:51 -05:00
										 |  |  | ResultVal<std::shared_ptr<Kernel::ClientPort>> ServiceManager::GetServicePort( | 
					
						
							| 
									
										
										
										
											2017-06-05 23:31:59 -07:00
										 |  |  |     const std::string& name) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     CASCADE_CODE(ValidateServiceName(name)); | 
					
						
							|  |  |  |     auto it = registered_services.find(name); | 
					
						
							|  |  |  |     if (it == registered_services.end()) { | 
					
						
							| 
									
										
										
										
											2020-04-29 11:15:21 +10:00
										 |  |  |         LOG_ERROR(Service_SM, "Server is not registered! service={}", name); | 
					
						
							| 
									
										
										
										
											2017-06-05 23:31:59 -07:00
										 |  |  |         return ERR_SERVICE_NOT_REGISTERED; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-06 01:33:19 -05:00
										 |  |  |     return MakeResult(it->second); | 
					
						
							| 
									
										
										
										
											2017-06-05 23:31:59 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-24 20:15:51 -05:00
										 |  |  | ResultVal<std::shared_ptr<Kernel::ClientSession>> ServiceManager::ConnectToService( | 
					
						
							| 
									
										
										
										
											2017-06-05 23:31:59 -07:00
										 |  |  |     const std::string& name) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     CASCADE_RESULT(auto client_port, GetServicePort(name)); | 
					
						
							|  |  |  |     return client_port->Connect(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 19:29:04 -04:00
										 |  |  | SM::~SM() = default; | 
					
						
							| 
									
										
										
										
											2017-06-05 23:31:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-14 22:18:42 -04:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * SM::Initialize service function | 
					
						
							|  |  |  |  *  Inputs: | 
					
						
							|  |  |  |  *      0: 0x00000000 | 
					
						
							|  |  |  |  *  Outputs: | 
					
						
							| 
									
										
										
										
											2017-10-15 01:24:22 -04:00
										 |  |  |  *      0: ResultCode | 
					
						
							| 
									
										
										
										
											2017-10-14 22:18:42 -04:00
										 |  |  |  */ | 
					
						
							|  |  |  | void SM::Initialize(Kernel::HLERequestContext& ctx) { | 
					
						
							| 
									
										
										
										
											2018-11-26 17:06:13 +11:00
										 |  |  |     LOG_DEBUG(Service_SM, "called"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-23 19:52:18 -05:00
										 |  |  |     IPC::ResponseBuilder rb{ctx, 2}; | 
					
						
							| 
									
										
										
										
											2017-10-14 22:18:42 -04:00
										 |  |  |     rb.Push(RESULT_SUCCESS); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SM::GetService(Kernel::HLERequestContext& ctx) { | 
					
						
							|  |  |  |     IPC::RequestParser rp{ctx}; | 
					
						
							| 
									
										
										
										
											2018-01-07 09:57:41 -05:00
										 |  |  |     auto name_buf = rp.PopRaw<std::array<char, 8>>(); | 
					
						
							|  |  |  |     auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     std::string name(name_buf.begin(), end); | 
					
						
							| 
									
										
										
										
											2017-10-14 22:18:42 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     auto client_port = service_manager->GetServicePort(name); | 
					
						
							|  |  |  |     if (client_port.Failed()) { | 
					
						
							| 
									
										
										
										
											2018-09-19 15:09:59 +10:00
										 |  |  |         IPC::ResponseBuilder rb{ctx, 2}; | 
					
						
							| 
									
										
										
										
											2017-10-14 22:18:42 -04:00
										 |  |  |         rb.Push(client_port.Code()); | 
					
						
							| 
									
										
										
										
											2018-07-02 10:20:50 -06:00
										 |  |  |         LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, client_port.Code().raw); | 
					
						
							| 
									
										
										
										
											2018-02-05 02:03:22 -08:00
										 |  |  |         if (name.length() == 0) | 
					
						
							|  |  |  |             return; // LibNX Fix
 | 
					
						
							| 
									
										
										
										
											2018-01-19 16:35:25 -08:00
										 |  |  |         UNIMPLEMENTED(); | 
					
						
							| 
									
										
										
										
											2017-10-14 22:18:42 -04:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-25 18:28:48 -05:00
										 |  |  |     auto [client, server] = Kernel::Session::Create(kernel, name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const auto& server_port = client_port.Unwrap()->GetServerPort(); | 
					
						
							|  |  |  |     if (server_port->GetHLEHandler()) { | 
					
						
							|  |  |  |         server_port->GetHLEHandler()->ClientConnected(server); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         server_port->AppendPendingSession(server); | 
					
						
							| 
									
										
										
										
											2017-10-14 22:18:42 -04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-11-25 18:28:48 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Wake the threads waiting on the ServerPort
 | 
					
						
							|  |  |  |     server_port->WakeupAllWaitingThreads(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     LOG_DEBUG(Service_SM, "called service={} -> session={}", name, client->GetObjectId()); | 
					
						
							|  |  |  |     IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; | 
					
						
							|  |  |  |     rb.Push(RESULT_SUCCESS); | 
					
						
							|  |  |  |     rb.PushMoveObjects(std::move(client)); | 
					
						
							| 
									
										
										
										
											2017-10-14 22:18:42 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-03 20:02:18 -04:00
										 |  |  | void SM::RegisterService(Kernel::HLERequestContext& ctx) { | 
					
						
							|  |  |  |     IPC::RequestParser rp{ctx}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const auto name_buf = rp.PopRaw<std::array<char, 8>>(); | 
					
						
							|  |  |  |     const auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const std::string name(name_buf.begin(), end); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-17 23:04:35 -05:00
										 |  |  |     const auto is_light = static_cast<bool>(rp.PopRaw<u32>()); | 
					
						
							|  |  |  |     const auto max_session_count = rp.PopRaw<u32>(); | 
					
						
							| 
									
										
										
										
											2018-11-03 20:02:18 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-17 23:04:35 -05:00
										 |  |  |     LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name, | 
					
						
							|  |  |  |               max_session_count, is_light); | 
					
						
							| 
									
										
										
										
											2018-11-03 20:02:18 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-17 23:04:35 -05:00
										 |  |  |     auto handle = service_manager->RegisterService(name, max_session_count); | 
					
						
							| 
									
										
										
										
											2018-11-03 20:02:18 -04:00
										 |  |  |     if (handle.Failed()) { | 
					
						
							|  |  |  |         LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", | 
					
						
							|  |  |  |                   handle.Code().raw); | 
					
						
							|  |  |  |         IPC::ResponseBuilder rb{ctx, 2}; | 
					
						
							|  |  |  |         rb.Push(handle.Code()); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; | 
					
						
							|  |  |  |     rb.Push(handle.Code()); | 
					
						
							|  |  |  |     rb.PushMoveObjects(std::move(handle).Unwrap()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SM::UnregisterService(Kernel::HLERequestContext& ctx) { | 
					
						
							|  |  |  |     IPC::RequestParser rp{ctx}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const auto name_buf = rp.PopRaw<std::array<char, 8>>(); | 
					
						
							|  |  |  |     const auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const std::string name(name_buf.begin(), end); | 
					
						
							| 
									
										
										
										
											2018-11-26 17:06:13 +11:00
										 |  |  |     LOG_DEBUG(Service_SM, "called with name={}", name); | 
					
						
							| 
									
										
										
										
											2018-11-03 20:02:18 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     IPC::ResponseBuilder rb{ctx, 2}; | 
					
						
							|  |  |  |     rb.Push(service_manager->UnregisterService(name)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-25 18:28:48 -05:00
										 |  |  | SM::SM(std::shared_ptr<ServiceManager> service_manager, Kernel::KernelCore& kernel) | 
					
						
							|  |  |  |     : ServiceFramework{"sm:", 4}, service_manager{std::move(service_manager)}, kernel{kernel} { | 
					
						
							| 
									
										
										
										
											2017-10-14 22:18:42 -04:00
										 |  |  |     static const FunctionInfo functions[] = { | 
					
						
							|  |  |  |         {0x00000000, &SM::Initialize, "Initialize"}, | 
					
						
							|  |  |  |         {0x00000001, &SM::GetService, "GetService"}, | 
					
						
							| 
									
										
										
										
											2018-11-03 20:02:18 -04:00
										 |  |  |         {0x00000002, &SM::RegisterService, "RegisterService"}, | 
					
						
							|  |  |  |         {0x00000003, &SM::UnregisterService, "UnregisterService"}, | 
					
						
							| 
									
										
										
										
											2017-10-14 22:18:42 -04:00
										 |  |  |     }; | 
					
						
							|  |  |  |     RegisterHandlers(functions); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-19 21:41:44 -04:00
										 |  |  | } // namespace Service::SM
 |