diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-27 12:52:39 -0400 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-27 12:52:39 -0400 |
| commit | 13699c7328657248fdec8155b3dc68fe96241fa5 (patch) | |
| tree | 7eb662868a31c8986382875ec3d8da3f115353c6 /src | |
| parent | fd4e5a855ca208325f8b3e468eb63b1af59319f0 (diff) | |
am: Switch 2 appletOE/IApplicationProxy entry points
- appletOE command 10 opens the application proxy (same arguments as 0).
- IApplicationProxy commands 40/50/.../90 are new getters; return an
INx2StubInterface (nx2_stub_interface.h). Interfaces whose name starts
with nx2: answer every call with an empty success and log it.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/core/hle/service/am/service/application_proxy.cpp | 12 | ||||
| -rw-r--r-- | src/core/hle/service/am/service/application_proxy.h | 1 | ||||
| -rw-r--r-- | src/core/hle/service/am/service/application_proxy_service.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nx2_stub_interface.h | 55 | ||||
| -rw-r--r-- | src/core/hle/service/service.cpp | 3 |
6 files changed, 73 insertions, 1 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1b578f67ba..0c37a561cf 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1033,6 +1033,7 @@ add_library(core STATIC hle/service/server_manager.h hle/service/service.cpp hle/service/service.h + hle/service/nx2_stub_interface.h hle/service/services.cpp hle/service/services.h hle/service/set/factory_settings_server.cpp diff --git a/src/core/hle/service/am/service/application_proxy.cpp b/src/core/hle/service/am/service/application_proxy.cpp index df438e1e17..80a21c0d05 100644 --- a/src/core/hle/service/am/service/application_proxy.cpp +++ b/src/core/hle/service/am/service/application_proxy.cpp @@ -16,6 +16,7 @@ #include "core/hle/service/am/service/self_controller.h" #include "core/hle/service/am/service/window_controller.h" #include "core/hle/service/cmif_serialization.h" +#include "core/hle/service/nx2_stub_interface.h" namespace Service::AM { @@ -33,6 +34,13 @@ IApplicationProxy::IApplicationProxy(Core::System& system_, std::shared_ptr<Appl {10, D<&IApplicationProxy::GetProcessWindingController>, "GetProcessWindingController"}, {11, D<&IApplicationProxy::GetLibraryAppletCreator>, "GetLibraryAppletCreator"}, {20, D<&IApplicationProxy::GetApplicationFunctions>, "GetApplicationFunctions"}, + // Switch 2-only getters; see nx2_stub_interface.h. + {40, &IApplicationProxy::GetNx2Interface, "Nx2Getter40"}, + {50, &IApplicationProxy::GetNx2Interface, "Nx2Getter50"}, + {60, &IApplicationProxy::GetNx2Interface, "Nx2Getter60"}, + {70, &IApplicationProxy::GetNx2Interface, "Nx2Getter70"}, + {80, &IApplicationProxy::GetNx2Interface, "Nx2Getter80"}, + {90, &IApplicationProxy::GetNx2Interface, "Nx2Getter90"}, {1000, D<&IApplicationProxy::GetDebugFunctions>, "GetDebugFunctions"}, }; // clang-format on @@ -42,6 +50,10 @@ IApplicationProxy::IApplicationProxy(Core::System& system_, std::shared_ptr<Appl IApplicationProxy::~IApplicationProxy() = default; +void IApplicationProxy::GetNx2Interface(HLERequestContext& ctx) { + ReturnNx2StubInterface(system, ctx, "IApplicationProxy"); +} + Result IApplicationProxy::GetAudioController( Out<SharedPointer<IAudioController>> out_audio_controller) { LOG_DEBUG(Service_AM, "called"); diff --git a/src/core/hle/service/am/service/application_proxy.h b/src/core/hle/service/am/service/application_proxy.h index b56f597605..04f4b4e175 100644 --- a/src/core/hle/service/am/service/application_proxy.h +++ b/src/core/hle/service/am/service/application_proxy.h @@ -30,6 +30,7 @@ public: ~IApplicationProxy(); private: + void GetNx2Interface(HLERequestContext& ctx); Result GetAudioController(Out<SharedPointer<IAudioController>> out_audio_controller); Result GetDisplayController(Out<SharedPointer<IDisplayController>> out_display_controller); Result GetProcessWindingController( diff --git a/src/core/hle/service/am/service/application_proxy_service.cpp b/src/core/hle/service/am/service/application_proxy_service.cpp index 7727951d8c..67306aadc0 100644 --- a/src/core/hle/service/am/service/application_proxy_service.cpp +++ b/src/core/hle/service/am/service/application_proxy_service.cpp @@ -19,6 +19,8 @@ IApplicationProxyService::IApplicationProxyService(Core::System& system_, : ServiceFramework{system_, "appletOE"}, m_window_system{window_system} { static const FunctionInfo functions[] = { {0, D<&IApplicationProxyService::OpenApplicationProxy>, "OpenApplicationProxy"}, + // Switch 2 SDKs open the proxy with command 10, same arguments. + {10, D<&IApplicationProxyService::OpenApplicationProxy>, "OpenApplicationProxy (Switch 2)"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/nx2_stub_interface.h b/src/core/hle/service/nx2_stub_interface.h new file mode 100644 index 0000000000..6890298d1b --- /dev/null +++ b/src/core/hle/service/nx2_stub_interface.h @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <deque> +#include <mutex> +#include <string> +#include <string_view> + +#include <fmt/format.h> + +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/service.h" + +namespace Service { + +// Prefix of placeholder interfaces for Switch 2-only IPC. ReportUnimplementedFunction answers +// every call on such an interface with an empty success, so boot can go on while the log shows +// which commands are used. +inline constexpr std::string_view Nx2StubPrefix = "nx2:"; + +class INx2StubInterface final : public ServiceFramework<INx2StubInterface> { +public: + explicit INx2StubInterface(Core::System& system_, const char* name) + : ServiceFramework{system_, name} {} + + // Names must outlive the interface, so they are interned here. + static const char* InternName(std::string name) { + static std::mutex mutex; + static std::deque<std::string> names; + std::scoped_lock lk{mutex}; + for (const auto& n : names) { + if (n == name) { + return n.c_str(); + } + } + return names.emplace_back(std::move(name)).c_str(); + } +}; + +// Handler for an unknown Switch 2 command that returns an interface: hands back a stub named +// after the owning service and the command id. +inline void ReturnNx2StubInterface(Core::System& system, HLERequestContext& ctx, + std::string_view owner) { + const char* name = + INx2StubInterface::InternName(fmt::format("{}{}::{}", Nx2StubPrefix, owner, ctx.GetCommand())); + LOG_WARNING(Service, "(STUBBED) Switch 2 {}::{} -> stub interface {}", owner, ctx.GetCommand(), + name); + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<INx2StubInterface>(ctx, system, name); +} + +} // namespace Service diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index b4fe2b3ed5..373b8a2545 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -13,6 +13,7 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/service.h" +#include "core/hle/service/nx2_stub_interface.h" #include "core/hle/service/sm/sm.h" #include "core/reporter.h" @@ -69,7 +70,7 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(HLERequestContext& ctx, system.GetReporter().SaveUnimplementedFunctionReport(ctx, ctx.GetCommand(), function_name, service_name); UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf)); - if (Settings::values.use_auto_stub) { + if (Settings::values.use_auto_stub || std::string_view{service_name}.starts_with(Nx2StubPrefix)) { LOG_WARNING(Service, "Using auto stub fallback!"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); |
