From 2c1e119c4a57fdd26dc8249d9b5fca3111195777 Mon Sep 17 00:00:00 2001 From: bunnei <bunneidev@gmail.com> Date: Mon, 10 May 2021 16:18:30 -0700 Subject: [PATCH] hle: service: sm: Add TIPC support. - Fixes our error checking of names as well. --- src/core/hle/service/sm/sm.cpp | 102 ++++++++++++++++++++------------- src/core/hle/service/sm/sm.h | 9 ++- 2 files changed, 68 insertions(+), 43 deletions(-) diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 726bef4c33..391db48b1d 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -9,6 +9,7 @@ #include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_client_session.h" #include "core/hle/kernel/k_port.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_server_port.h" #include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_session.h" @@ -18,6 +19,7 @@ namespace Service::SM { +constexpr ResultCode ERR_NOT_INITIALIZED(ErrorModule::SM, 2); 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); @@ -34,20 +36,17 @@ static ResultCode ValidateServiceName(const std::string& name) { LOG_ERROR(Service_SM, "Invalid service name! service={}", name); return ERR_INVALID_NAME; } - if (name.rfind('\0') != std::string::npos) { - LOG_ERROR(Service_SM, "A non null terminated service was passed"); - return ERR_INVALID_NAME; - } return RESULT_SUCCESS; } -void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system) { - ASSERT(self->sm_interface.expired()); +Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core::System& system) { + ASSERT(self.sm_interface.expired()); auto sm = std::make_shared<SM>(self, system); - sm->InstallAsNamedPort(system.Kernel()); - self->sm_interface = sm; - self->controller_interface = std::make_unique<Controller>(system); + self.sm_interface = sm; + self.controller_interface = std::make_unique<Controller>(system); + + return sm->CreatePort(system.Kernel()); } ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name, @@ -114,21 +113,47 @@ void SM::Initialize(Kernel::HLERequestContext& ctx) { } void SM::GetService(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - 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); - - auto result = service_manager->GetServicePort(name); - if (result.Failed()) { + auto result = GetServiceImpl(ctx); + if (result.Succeeded()) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; + rb.Push(result.Code()); + rb.PushMoveObjects(result.Unwrap()); + } else { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result.Code()); + } +} + +void SM::GetServiceTipc(Kernel::HLERequestContext& ctx) { + auto result = GetServiceImpl(ctx); + IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; + rb.Push(result.Code()); + rb.PushMoveObjects(result.Succeeded() ? result.Unwrap() : nullptr); +} + +static std::string PopServiceName(IPC::RequestParser& rp) { + auto name_buf = rp.PopRaw<std::array<char, 8>>(); + std::string result; + for (const auto& c : name_buf) { + if (c >= ' ' && c <= '~') { + result.push_back(c); + } + } + return result; +} + +ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& ctx) { + if (!is_initialized) { + return ERR_NOT_INITIALIZED; + } + + IPC::RequestParser rp{ctx}; + std::string name(PopServiceName(rp)); + + auto result = service_manager.GetServicePort(name); + if (result.Failed()) { LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw); - if (name.length() == 0) - return; // LibNX Fix - UNIMPLEMENTED(); - return; + return result.Code(); } auto* port = result.Unwrap(); @@ -150,18 +175,12 @@ void SM::GetService(Kernel::HLERequestContext& ctx) { } LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); - IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; - rb.Push(RESULT_SUCCESS); - rb.PushMoveObjects(session->GetClientSession()); + return MakeResult(&session->GetClientSession()); } 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); + std::string name(PopServiceName(rp)); const auto is_light = static_cast<bool>(rp.PopRaw<u32>()); const auto max_session_count = rp.PopRaw<u32>(); @@ -169,7 +188,7 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name, max_session_count, is_light); - auto handle = service_manager->RegisterService(name, max_session_count); + auto handle = service_manager.RegisterService(name, max_session_count); if (handle.Failed()) { LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", handle.Code().raw); @@ -187,28 +206,31 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) { void SM::UnregisterService(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; + std::string name(PopServiceName(rp)); - 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); LOG_DEBUG(Service_SM, "called with name={}", name); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(service_manager->UnregisterService(name)); + rb.Push(service_manager.UnregisterService(name)); } -SM::SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_) +SM::SM(ServiceManager& service_manager_, Core::System& system_) : ServiceFramework{system_, "sm:", 4}, - service_manager{std::move(service_manager_)}, kernel{system_.Kernel()} { - static const FunctionInfo functions[] = { + service_manager{service_manager_}, kernel{system_.Kernel()} { + RegisterHandlers({ {0, &SM::Initialize, "Initialize"}, {1, &SM::GetService, "GetService"}, {2, &SM::RegisterService, "RegisterService"}, {3, &SM::UnregisterService, "UnregisterService"}, {4, nullptr, "DetachClient"}, - }; - RegisterHandlers(functions); + }); + RegisterHandlersTipc({ + {0, &SM::Initialize, "Initialize"}, + {1, &SM::GetServiceTipc, "GetService"}, + {2, &SM::RegisterService, "RegisterService"}, + {3, &SM::UnregisterService, "UnregisterService"}, + {4, nullptr, "DetachClient"}, + }); } } // namespace Service::SM diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index fed65af4f2..60f0b3f8a8 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -34,23 +34,26 @@ class Controller; /// Interface to "sm:" service class SM final : public ServiceFramework<SM> { public: - explicit SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_); + explicit SM(ServiceManager& service_manager_, Core::System& system_); ~SM() override; private: void Initialize(Kernel::HLERequestContext& ctx); void GetService(Kernel::HLERequestContext& ctx); + void GetServiceTipc(Kernel::HLERequestContext& ctx); void RegisterService(Kernel::HLERequestContext& ctx); void UnregisterService(Kernel::HLERequestContext& ctx); - std::shared_ptr<ServiceManager> service_manager; + ResultVal<Kernel::KClientSession*> GetServiceImpl(Kernel::HLERequestContext& ctx); + + ServiceManager& service_manager; bool is_initialized{}; Kernel::KernelCore& kernel; }; class ServiceManager { public: - static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system); + static Kernel::KClientPort& InterfaceFactory(ServiceManager& self, Core::System& system); explicit ServiceManager(Kernel::KernelCore& kernel_); ~ServiceManager();