diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 5e7fc68f9..854ab9a05 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -36,6 +36,10 @@ ResultVal> ServiceManager::RegisterService std::string name, unsigned int max_sessions) { CASCADE_CODE(ValidateServiceName(name)); + + if (registered_services.find(name) != registered_services.end()) + return ERR_ALREADY_REGISTERED; + Kernel::SharedPtr server_port; Kernel::SharedPtr client_port; std::tie(server_port, client_port) = Kernel::ServerPort::CreatePortPair(max_sessions, name); diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 8f0dbf2db..9f60a7965 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -32,6 +32,9 @@ constexpr ResultCode ERR_ACCESS_DENIED(6, ErrorModule::SRV, ErrorSummary::Invali ErrorLevel::Permanent); // 0xD8E06406 constexpr ResultCode ERR_NAME_CONTAINS_NUL(7, ErrorModule::SRV, ErrorSummary::WrongArgument, ErrorLevel::Permanent); // 0xD9006407 +constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorDescription::AlreadyExists, ErrorModule::OS, + ErrorSummary::WrongArgument, + ErrorLevel::Permanent); // 0xD9001BFC class ServiceManager { public: diff --git a/src/core/hle/service/sm/srv.cpp b/src/core/hle/service/sm/srv.cpp index 352941e69..5c955cf54 100644 --- a/src/core/hle/service/sm/srv.cpp +++ b/src/core/hle/service/sm/srv.cpp @@ -13,6 +13,7 @@ #include "core/hle/kernel/errors.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/semaphore.h" +#include "core/hle/kernel/server_port.h" #include "core/hle/kernel/server_session.h" #include "core/hle/service/sm/sm.h" #include "core/hle/service/sm/srv.h" @@ -184,12 +185,35 @@ void SRV::PublishToSubscriber(Kernel::HLERequestContext& ctx) { flags); } +void SRV::RegisterService(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x3, 4, 0); + + auto name_buf = rp.PopRaw>(); + size_t name_len = rp.Pop(); + u32 max_sessions = rp.Pop(); + + std::string name(name_buf.data(), std::min(name_len, name_buf.size())); + + auto port = service_manager->RegisterService(name, max_sessions); + + if (port.Failed()) { + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(port.Code()); + LOG_ERROR(Service_SRV, "called service=%s -> error 0x%08X", name.c_str(), port.Code().raw); + return; + } + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushObjects(port.Unwrap()); +} + SRV::SRV(std::shared_ptr service_manager) : ServiceFramework("srv:", 4), service_manager(std::move(service_manager)) { static const FunctionInfo functions[] = { {0x00010002, &SRV::RegisterClient, "RegisterClient"}, {0x00020000, &SRV::EnableNotification, "EnableNotification"}, - {0x00030100, nullptr, "RegisterService"}, + {0x00030100, &SRV::RegisterService, "RegisterService"}, {0x000400C0, nullptr, "UnregisterService"}, {0x00050100, &SRV::GetServiceHandle, "GetServiceHandle"}, {0x000600C2, nullptr, "RegisterPort"}, diff --git a/src/core/hle/service/sm/srv.h b/src/core/hle/service/sm/srv.h index 75cca5184..aad839563 100644 --- a/src/core/hle/service/sm/srv.h +++ b/src/core/hle/service/sm/srv.h @@ -28,6 +28,7 @@ private: void Subscribe(Kernel::HLERequestContext& ctx); void Unsubscribe(Kernel::HLERequestContext& ctx); void PublishToSubscriber(Kernel::HLERequestContext& ctx); + void RegisterService(Kernel::HLERequestContext& ctx); std::shared_ptr service_manager; Kernel::SharedPtr notification_semaphore;