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 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<Controller>(kernel.System());
@ -157,9 +158,10 @@ void SM::GetServiceTipc(HLERequestContext& ctx) {
}
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;
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 <= '~') {
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"},
});
}

View file

@ -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,