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:
This commit is contained in:
Zephyron 2025-01-25 15:20:01 +10:00
parent 58ed33dd9f
commit 5ba970b574
2 changed files with 36 additions and 6 deletions

View file

@ -22,6 +22,7 @@ constexpr Result ResultInvalidClient(ErrorModule::SM, 2);
constexpr Result ResultAlreadyRegistered(ErrorModule::SM, 4); constexpr Result ResultAlreadyRegistered(ErrorModule::SM, 4);
constexpr Result ResultInvalidServiceName(ErrorModule::SM, 6); constexpr Result ResultInvalidServiceName(ErrorModule::SM, 6);
constexpr Result ResultNotRegistered(ErrorModule::SM, 7); constexpr Result ResultNotRegistered(ErrorModule::SM, 7);
constexpr Result ResultNotAllowed(ErrorModule::SM, 1);
ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} { ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} {
controller_interface = std::make_unique<Controller>(kernel.System()); controller_interface = std::make_unique<Controller>(kernel.System());
@ -157,9 +158,10 @@ void SM::GetServiceTipc(HLERequestContext& ctx) {
} }
static std::string PopServiceName(IPC::RequestParser& rp) { static std::string PopServiceName(IPC::RequestParser& rp) {
auto name_buf = rp.PopRaw<std::array<char, 8>>(); const u64 name_encoded = rp.PopRaw<u64>();
std::string result; std::string result;
for (const auto& c : name_buf) { for (int i = 0; i < 8; i++) {
const char c = static_cast<char>((name_encoded >> (i * 8)) & 0xFF);
if (c >= ' ' && c <= '~') { if (c >= ' ' && c <= '~') {
result.push_back(c); result.push_back(c);
} }
@ -250,22 +252,48 @@ void SM::UnregisterService(HLERequestContext& ctx) {
rb.Push(service_manager.UnregisterService(name)); 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_) SM::SM(ServiceManager& service_manager_, Core::System& system_)
: ServiceFramework{system_, "sm:", 4}, : ServiceFramework{system_, "sm:", 4},
service_manager{service_manager_}, kernel{system_.Kernel()} { service_manager{service_manager_}, kernel{system_.Kernel()} {
RegisterHandlers({ RegisterHandlers({
{0, &SM::Initialize, "Initialize"}, {0, &SM::RegisterClient, "RegisterClient"},
{1, &SM::GetServiceCmif, "GetService"}, {1, &SM::GetServiceCmif, "GetService"},
{2, &SM::RegisterServiceCmif, "RegisterService"}, {2, &SM::RegisterServiceCmif, "RegisterService"},
{3, &SM::UnregisterService, "UnregisterService"}, {3, &SM::UnregisterService, "UnregisterService"},
{4, nullptr, "DetachClient"}, {4, &SM::DetachClient, "DetachClient"},
}); });
RegisterHandlersTipc({ RegisterHandlersTipc({
{0, &SM::Initialize, "Initialize"}, {0, &SM::RegisterClient, "RegisterClient"},
{1, &SM::GetServiceTipc, "GetService"}, {1, &SM::GetServiceTipc, "GetService"},
{2, &SM::RegisterServiceTipc, "RegisterService"}, {2, &SM::RegisterServiceTipc, "RegisterService"},
{3, &SM::UnregisterService, "UnregisterService"}, {3, &SM::UnregisterService, "UnregisterService"},
{4, nullptr, "DetachClient"}, {4, &SM::DetachClient, "DetachClient"},
}); });
} }

View file

@ -38,12 +38,14 @@ public:
~SM() override; ~SM() override;
private: private:
void RegisterClient(HLERequestContext& ctx);
void Initialize(HLERequestContext& ctx); void Initialize(HLERequestContext& ctx);
void GetServiceCmif(HLERequestContext& ctx); void GetServiceCmif(HLERequestContext& ctx);
void GetServiceTipc(HLERequestContext& ctx); void GetServiceTipc(HLERequestContext& ctx);
void RegisterServiceCmif(HLERequestContext& ctx); void RegisterServiceCmif(HLERequestContext& ctx);
void RegisterServiceTipc(HLERequestContext& ctx); void RegisterServiceTipc(HLERequestContext& ctx);
void UnregisterService(HLERequestContext& ctx); void UnregisterService(HLERequestContext& ctx);
void DetachClient(HLERequestContext& ctx);
Result GetServiceImpl(Kernel::KClientSession** out_client_session, HLERequestContext& ctx); Result GetServiceImpl(Kernel::KClientSession** out_client_session, HLERequestContext& ctx);
void RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_session_count, void RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_session_count,