diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-29 19:50:18 -0400 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-29 20:49:49 -0400 |
| commit | 04a64dee831e4ba94f63e0b8b77e26d181a71966 (patch) | |
| tree | af64b87359d5385a90bdb7b1dfbd196f75302b7b /src | |
| parent | fe662906633671768910486001e1ea959e43a083 (diff) | |
sm: give Switch 2 programs a stub for services Eden does not have
Newer Mario Kart World updates open chat:u (GameChat) while booting. Eden
never registers it, so the request was deferred until the service shows
up and the game sat on its loading screen forever. For Switch 2 callers,
hand out an INx2StubInterface session instead, whose commands are all
auto-stubbed like their unknown commands on existing services.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/sm/sm.cpp | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index c75c5437df..60f0dd89cb 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -11,11 +11,19 @@ #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_process.h" +#include "core/hle/kernel/k_resource_limit.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" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/result.h" #include "core/hle/service/cmif_types.h" +#include "core/hle/service/hle_ipc.h" #include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/nx2_stub_interface.h" #include "core/hle/service/server_manager.h" #include "core/hle/service/sm/sm.h" #include "core/hle/service/sm/sm_controller.h" @@ -170,6 +178,30 @@ static std::string PopServiceName(IPC::RequestParser& rp) { return result; } +namespace { + +// A session served by a Switch 2 stub interface named after the missing service (see +// nx2_stub_interface.h), set up like a session handed out by a service. +Kernel::KClientSession* CreateStubSession(Core::System& system, HLERequestContext& ctx, + const std::string& name) { + auto& kernel = system.Kernel(); + ASSERT(Kernel::GetCurrentProcess(kernel).GetResourceLimit()->Reserve( + kernel, Kernel::LimitableResource::SessionCountMax, 1)); + + auto* session = Kernel::KSession::Create(kernel); + session->Initialize(kernel, nullptr, 0); + Kernel::KSession::Register(kernel, session); + + auto manager = + std::make_shared<SessionRequestManager>(kernel, ctx.GetManager()->GetServerManager()); + manager->SetSessionHandler(std::make_shared<INx2StubInterface>( + system, INx2StubInterface::InternName(fmt::format("{}{}", Nx2StubPrefix, name)))); + ctx.GetManager()->GetServerManager().RegisterSession(&session->GetServerSession(), manager); + return &session->GetClientSession(); +} + +} // namespace + Result SM::GetServiceImpl(Kernel::KClientSession** out_client_session, HLERequestContext& ctx) { if (!ctx.GetManager()->GetIsInitializedForSm()) { return Service::SM::ResultInvalidClient; @@ -187,6 +219,17 @@ Result SM::GetServiceImpl(Kernel::KClientSession** out_client_session, HLEReques } if (port_result != ResultSuccess) { + // Switch 2 programs also ask for services Eden does not have at all (newer Mario Kart + // World updates open chat:u, GameChat, while booting). Nothing ever registers those, so + // waiting would hang them for good: hand out a placeholder whose commands are all + // auto-stubbed, like their unknown commands on existing services. + const auto* const caller = ctx.GetThread().GetOwnerProcess(); + if (caller != nullptr && caller->IsSwitch2()) { + LOG_WARNING(Service_SM, "(STUBBED) Switch 2 service {} does not exist, returning a stub", + name); + *out_client_session = CreateStubSession(system, ctx, name); + return ResultSuccess; + } LOG_INFO(Service_SM, "Waiting for service {} to become available", name); ctx.SetIsDeferred(); return Service::SM::ResultNotRegistered; |
