From 5ba970b574f6df377b57716781ec966a3c8feff1 Mon Sep 17 00:00:00 2001 From: Zephyron Date: Sat, 25 Jan 2025 15:20:01 +1000 Subject: [PATCH] service: sm: Update to match official IPC interface Updates the SM service implementation to better match the official "nn::sm::detail::IUserInterface" interface. Key changes include: - Replace Initialize with RegisterClient command (cmd 0) - Add DetachClient command implementation (cmd 4) - Update service name handling to use u64-encoded names - Add proper PID descriptor handling for RegisterClient/DetachClient - Add ResultNotAllowed error code - Update handler registration for both CMIF and TIPC This brings the implementation closer to the official documentation while maintaining compatibility with existing code. Refs: switchbrew.org/wiki/Services_API#sm: --- src/core/hle/service/sm/sm.cpp | 40 +++++++++++++++++++++++++++++----- src/core/hle/service/sm/sm.h | 2 ++ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 1095dcf6c..14e0a03c8 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -22,6 +22,7 @@ constexpr Result ResultInvalidClient(ErrorModule::SM, 2); constexpr Result ResultAlreadyRegistered(ErrorModule::SM, 4); constexpr Result ResultInvalidServiceName(ErrorModule::SM, 6); constexpr Result ResultNotRegistered(ErrorModule::SM, 7); +constexpr Result ResultNotAllowed(ErrorModule::SM, 1); ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} { controller_interface = std::make_unique(kernel.System()); @@ -157,9 +158,10 @@ void SM::GetServiceTipc(HLERequestContext& ctx) { } static std::string PopServiceName(IPC::RequestParser& rp) { - auto name_buf = rp.PopRaw>(); + const u64 name_encoded = rp.PopRaw(); std::string result; - for (const auto& c : name_buf) { + for (int i = 0; i < 8; i++) { + const char c = static_cast((name_encoded >> (i * 8)) & 0xFF); if (c >= ' ' && c <= '~') { result.push_back(c); } @@ -250,22 +252,48 @@ void SM::UnregisterService(HLERequestContext& ctx) { rb.Push(service_manager.UnregisterService(name)); } +void SM::RegisterClient(HLERequestContext& ctx) { + LOG_DEBUG(Service_SM, "called"); + + IPC::RequestParser rp{ctx}; + + // Read PID descriptor + rp.Skip(2, false); // Skip PID descriptor and reserved u64 + + ctx.GetManager()->SetIsInitializedForSm(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void SM::DetachClient(HLERequestContext& ctx) { + LOG_DEBUG(Service_SM, "called"); + + IPC::RequestParser rp{ctx}; + rp.Skip(2, false); // Skip PID descriptor and reserved u64 + + ctx.GetManager()->SetIsInitializedForSm(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + SM::SM(ServiceManager& service_manager_, Core::System& system_) : ServiceFramework{system_, "sm:", 4}, service_manager{service_manager_}, kernel{system_.Kernel()} { RegisterHandlers({ - {0, &SM::Initialize, "Initialize"}, + {0, &SM::RegisterClient, "RegisterClient"}, {1, &SM::GetServiceCmif, "GetService"}, {2, &SM::RegisterServiceCmif, "RegisterService"}, {3, &SM::UnregisterService, "UnregisterService"}, - {4, nullptr, "DetachClient"}, + {4, &SM::DetachClient, "DetachClient"}, }); RegisterHandlersTipc({ - {0, &SM::Initialize, "Initialize"}, + {0, &SM::RegisterClient, "RegisterClient"}, {1, &SM::GetServiceTipc, "GetService"}, {2, &SM::RegisterServiceTipc, "RegisterService"}, {3, &SM::UnregisterService, "UnregisterService"}, - {4, nullptr, "DetachClient"}, + {4, &SM::DetachClient, "DetachClient"}, }); } diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 32c218638..d73eac08e 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -38,12 +38,14 @@ public: ~SM() override; private: + void RegisterClient(HLERequestContext& ctx); void Initialize(HLERequestContext& ctx); void GetServiceCmif(HLERequestContext& ctx); void GetServiceTipc(HLERequestContext& ctx); void RegisterServiceCmif(HLERequestContext& ctx); void RegisterServiceTipc(HLERequestContext& ctx); void UnregisterService(HLERequestContext& ctx); + void DetachClient(HLERequestContext& ctx); Result GetServiceImpl(Kernel::KClientSession** out_client_session, HLERequestContext& ctx); void RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_session_count,