aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-27 12:52:39 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-27 12:52:39 -0400
commit13699c7328657248fdec8155b3dc68fe96241fa5 (patch)
tree7eb662868a31c8986382875ec3d8da3f115353c6 /src
parentfd4e5a855ca208325f8b3e468eb63b1af59319f0 (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.txt1
-rw-r--r--src/core/hle/service/am/service/application_proxy.cpp12
-rw-r--r--src/core/hle/service/am/service/application_proxy.h1
-rw-r--r--src/core/hle/service/am/service/application_proxy_service.cpp2
-rw-r--r--src/core/hle/service/nx2_stub_interface.h55
-rw-r--r--src/core/hle/service/service.cpp3
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);