From 98d0c627e61b7b12c005604a7d1b2e248d1b8a60 Mon Sep 17 00:00:00 2001 From: Zephyron Date: Tue, 1 Jul 2025 20:06:45 +1000 Subject: [PATCH] hle/service: Implement missing Glue services for 20.0.0+ support - **ARP Service (arp:r/arp:w)**: Added 20.0.0+ function support * arp:r: GetApplicationInstanceUnregistrationNotifier, ListApplicationInstanceId, GetMicroApplicationInstanceId, GetApplicationCertificate, GetPreomiaApplicationLaunchProperty, GetPreomiaApplicationControlProperty * arp:w: AcquireApplicationProcessPropertyUpdater, AcquireApplicationCertificateUpdater, RegisterApplicationControlProperty * Added interface classes: IUnregistrationNotifier, IApplicationProcessPropertyUpdater, IApplicationCertificateUpdater - **Platform Service Manager (pl:u)**: Added Switch 2 [S2] functions * Commands 2010, 2020, 2100 (Unknown2010, Unknown2020, OpenFont) - **ECTX Service**: Added missing ectx:r service implementation * Registered ectx:r service alongside existing ectx:aw - All functions properly stubbed - Fixed PushIpcInterface usage with shared_ptr - Command mappings follow switchbrew.org documentation - Ensures compatibility with 20.0.0+ system versions Signed-off-by: Zephyron --- src/core/hle/service/glue/arp.cpp | 225 +++++++++++++++++- src/core/hle/service/glue/arp.h | 10 + src/core/hle/service/glue/ectx.cpp | 13 + src/core/hle/service/glue/ectx.h | 7 + src/core/hle/service/glue/glue.cpp | 2 + .../service/ns/platform_service_manager.cpp | 22 ++ .../hle/service/ns/platform_service_manager.h | 6 + 7 files changed, 275 insertions(+), 10 deletions(-) diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp index 1254b6d49..11eda51e3 100644 --- a/src/core/hle/service/glue/arp.cpp +++ b/src/core/hle/service/glue/arp.cpp @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include @@ -11,6 +12,7 @@ #include "core/hle/service/glue/errors.h" #include "core/hle/service/glue/glue_manager.h" #include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/kernel_helpers.h" namespace Service::Glue { @@ -30,6 +32,103 @@ std::optional GetTitleIDForProcessID(Core::System& system, u64 process_id) } } // Anonymous namespace +class IUnregistrationNotifier final : public ServiceFramework { +public: + explicit IUnregistrationNotifier(Core::System& system_) + : ServiceFramework{system_, "IUnregistrationNotifier"}, + service_context{system_, "IUnregistrationNotifier"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IUnregistrationNotifier::GetReadableHandle, "GetReadableHandle"}, + }; + // clang-format on + + RegisterHandlers(functions); + + unregistration_event = + service_context.CreateEvent("IUnregistrationNotifier:UnregistrationEvent"); + } + + ~IUnregistrationNotifier() { + service_context.CloseEvent(unregistration_event); + } + +private: + void GetReadableHandle(HLERequestContext& ctx) { + LOG_WARNING(Service_ARP, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(unregistration_event->GetReadableEvent()); + } + + KernelHelpers::ServiceContext service_context; + Kernel::KEvent* unregistration_event; +}; + +class IApplicationProcessPropertyUpdater final : public ServiceFramework { +public: + explicit IApplicationProcessPropertyUpdater(Core::System& system_) + : ServiceFramework{system_, "IApplicationProcessPropertyUpdater"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IApplicationProcessPropertyUpdater::Issue, "Issue"}, + {1, &IApplicationProcessPropertyUpdater::SetApplicationProcessProperty, "SetApplicationProcessProperty"}, + {2, &IApplicationProcessPropertyUpdater::DeleteApplicationProcessProperty, "DeleteApplicationProcessProperty"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void Issue(HLERequestContext& ctx) { + LOG_WARNING(Service_ARP, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void SetApplicationProcessProperty(HLERequestContext& ctx) { + LOG_WARNING(Service_ARP, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void DeleteApplicationProcessProperty(HLERequestContext& ctx) { + LOG_WARNING(Service_ARP, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } +}; + +class IApplicationCertificateUpdater final : public ServiceFramework { +public: + explicit IApplicationCertificateUpdater(Core::System& system_) + : ServiceFramework{system_, "IApplicationCertificateUpdater"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IApplicationCertificateUpdater::Issue, "Issue"}, + {1, &IApplicationCertificateUpdater::SetApplicationCertificate, "SetApplicationCertificate"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void Issue(HLERequestContext& ctx) { + LOG_WARNING(Service_ARP, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void SetApplicationCertificate(HLERequestContext& ctx) { + LOG_WARNING(Service_ARP, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } +}; + ARP_R::ARP_R(Core::System& system_, const ARPManager& manager_) : ServiceFramework{system_, "arp:r"}, manager{manager_} { // clang-format off @@ -38,12 +137,12 @@ ARP_R::ARP_R(Core::System& system_, const ARPManager& manager_) {1, &ARP_R::GetApplicationLaunchPropertyWithApplicationId, "GetApplicationLaunchPropertyWithApplicationId"}, {2, &ARP_R::GetApplicationControlProperty, "GetApplicationControlProperty"}, {3, &ARP_R::GetApplicationControlPropertyWithApplicationId, "GetApplicationControlPropertyWithApplicationId"}, - {4, nullptr, "GetApplicationInstanceUnregistrationNotifier"}, - {5, nullptr, "ListApplicationInstanceId"}, - {6, nullptr, "GetMicroApplicationInstanceId"}, - {7, nullptr, "GetApplicationCertificate"}, - {9998, nullptr, "GetPreomiaApplicationLaunchProperty"}, - {9999, nullptr, "GetPreomiaApplicationControlProperty"}, + {4, &ARP_R::GetApplicationInstanceUnregistrationNotifier, "GetApplicationInstanceUnregistrationNotifier"}, + {5, &ARP_R::ListApplicationInstanceId, "ListApplicationInstanceId"}, + {6, &ARP_R::GetMicroApplicationInstanceId, "GetMicroApplicationInstanceId"}, + {7, &ARP_R::GetApplicationCertificate, "GetApplicationCertificate"}, + {9998, &ARP_R::GetPreomiaApplicationLaunchProperty, "GetPreomiaApplicationLaunchProperty"}, + {9999, &ARP_R::GetPreomiaApplicationControlProperty, "GetPreomiaApplicationControlProperty"}, }; // clang-format on @@ -154,6 +253,72 @@ void ARP_R::GetApplicationControlPropertyWithApplicationId(HLERequestContext& ct rb.Push(ResultSuccess); } +void ARP_R::GetApplicationInstanceUnregistrationNotifier(HLERequestContext& ctx) { + LOG_WARNING(Service_ARP, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(std::make_shared(system)); +} + +void ARP_R::ListApplicationInstanceId(HLERequestContext& ctx) { + LOG_WARNING(Service_ARP, "(STUBBED) called"); + + // Return empty list for now + const std::vector application_instance_ids; + ctx.WriteBuffer(application_instance_ids); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast(application_instance_ids.size())); +} + +void ARP_R::GetMicroApplicationInstanceId(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto process_id = rp.PopRaw(); + + LOG_WARNING(Service_ARP, "(STUBBED) called, process_id={:016X}", process_id); + + // Same as GetApplicationInstanceId for now + const auto title_id = GetTitleIDForProcessID(system, process_id); + if (!title_id.has_value()) { + LOG_ERROR(Service_ARP, "Failed to get title ID for process ID!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(Glue::ResultProcessIdNotRegistered); + return; + } + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(*title_id); // Use title_id as application instance id for now +} + +void ARP_R::GetApplicationCertificate(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto application_instance_id = rp.PopRaw(); + + LOG_WARNING(Service_ARP, "(STUBBED) called, application_instance_id={:016X}", application_instance_id); + + // Return empty certificate data for now + std::vector certificate_data(0x528, 0); // ApplicationCertificate is 0x528 bytes + ctx.WriteBuffer(certificate_data); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ARP_R::GetPreomiaApplicationLaunchProperty(HLERequestContext& ctx) { + LOG_WARNING(Service_ARP, "(STUBBED) called"); + // Same as GetApplicationLaunchProperty for compatibility + GetApplicationLaunchProperty(ctx); +} + +void ARP_R::GetPreomiaApplicationControlProperty(HLERequestContext& ctx) { + LOG_WARNING(Service_ARP, "(STUBBED) called"); + // Same as GetApplicationControlProperty for compatibility + GetApplicationControlProperty(ctx); +} + class IRegistrar final : public ServiceFramework { friend class ARP_W; @@ -188,8 +353,9 @@ private: } if (issued) { - LOG_ERROR(Service_ARP, - "Attempted to issue registrar, but registrar is already issued!"); + LOG_ERROR( + Service_ARP, + "Attempted to issue registrar, but registrar is already issued!"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(Glue::ResultAlreadyBound); return; @@ -251,8 +417,10 @@ ARP_W::ARP_W(Core::System& system_, ARPManager& manager_) // clang-format off static const FunctionInfo functions[] = { {0, &ARP_W::AcquireRegistrar, "AcquireRegistrar"}, - {1, &ARP_W::UnregisterApplicationInstance , "UnregisterApplicationInstance "}, - {2, nullptr, "AcquireUpdater"}, + {1, &ARP_W::UnregisterApplicationInstance, "UnregisterApplicationInstance"}, // [10.0.0+] UnregisterApplicationInstance, [1.0.0-9.2.0] DeleteProperties + {2, &ARP_W::AcquireApplicationProcessPropertyUpdater, "AcquireApplicationProcessPropertyUpdater"}, // [15.0.0+] AcquireApplicationProcessPropertyUpdater, [10.0.0-14.1.2] AcquireUpdater + {3, &ARP_W::AcquireApplicationCertificateUpdater, "AcquireApplicationCertificateUpdater"}, // [15.0.0+] + {4, &ARP_W::RegisterApplicationControlProperty, "RegisterApplicationControlProperty"}, // [19.0.0+] }; // clang-format on @@ -305,4 +473,41 @@ void ARP_W::UnregisterApplicationInstance(HLERequestContext& ctx) { rb.Push(manager.Unregister(*title_id)); } +void ARP_W::AcquireApplicationProcessPropertyUpdater(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto application_instance_id = rp.PopRaw(); + + LOG_WARNING(Service_ARP, "(STUBBED) called, application_instance_id={:016X}", application_instance_id); + + // Return stub updater interface + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(std::make_shared(system)); +} + +void ARP_W::AcquireApplicationCertificateUpdater(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto application_instance_id = rp.PopRaw(); + + LOG_WARNING(Service_ARP, "(STUBBED) called, application_instance_id={:016X}", application_instance_id); + + // Return stub certificate updater interface + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(std::make_shared(system)); +} + +void ARP_W::RegisterApplicationControlProperty(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto application_id = rp.PopRaw(); + const auto control_property = ctx.ReadBufferCopy(); + + LOG_WARNING(Service_ARP, "(STUBBED) called, application_id={:016X}, control_property_size={}", + application_id, control_property.size()); + + // For now, just return success + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + } // namespace Service::Glue diff --git a/src/core/hle/service/glue/arp.h b/src/core/hle/service/glue/arp.h index 5bce80175..495179d4b 100644 --- a/src/core/hle/service/glue/arp.h +++ b/src/core/hle/service/glue/arp.h @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -20,6 +21,12 @@ private: void GetApplicationLaunchPropertyWithApplicationId(HLERequestContext& ctx); void GetApplicationControlProperty(HLERequestContext& ctx); void GetApplicationControlPropertyWithApplicationId(HLERequestContext& ctx); + void GetApplicationInstanceUnregistrationNotifier(HLERequestContext& ctx); + void ListApplicationInstanceId(HLERequestContext& ctx); + void GetMicroApplicationInstanceId(HLERequestContext& ctx); + void GetApplicationCertificate(HLERequestContext& ctx); + void GetPreomiaApplicationLaunchProperty(HLERequestContext& ctx); + void GetPreomiaApplicationControlProperty(HLERequestContext& ctx); const ARPManager& manager; }; @@ -32,6 +39,9 @@ public: private: void AcquireRegistrar(HLERequestContext& ctx); void UnregisterApplicationInstance(HLERequestContext& ctx); + void AcquireApplicationProcessPropertyUpdater(HLERequestContext& ctx); + void AcquireApplicationCertificateUpdater(HLERequestContext& ctx); + void RegisterApplicationControlProperty(HLERequestContext& ctx); ARPManager& manager; std::shared_ptr registrar; diff --git a/src/core/hle/service/glue/ectx.cpp b/src/core/hle/service/glue/ectx.cpp index 6f71b62f3..60be81a6f 100644 --- a/src/core/hle/service/glue/ectx.cpp +++ b/src/core/hle/service/glue/ectx.cpp @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "core/hle/service/glue/ectx.h" @@ -59,4 +60,16 @@ void ECTX_AW::CreateContextRegistrar(HLERequestContext& ctx) { rb.PushIpcInterface(std::make_shared(system)); } +ECTX_R::ECTX_R(Core::System& system_) : ServiceFramework{system_, "ectx:r"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "CommitContext"}, // Stub - context reading functionality + }; + // clang-format on + + RegisterHandlers(functions); +} + +ECTX_R::~ECTX_R() = default; + } // namespace Service::Glue diff --git a/src/core/hle/service/glue/ectx.h b/src/core/hle/service/glue/ectx.h index ffa74d8d3..6667afec0 100644 --- a/src/core/hle/service/glue/ectx.h +++ b/src/core/hle/service/glue/ectx.h @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -20,4 +21,10 @@ private: void CreateContextRegistrar(HLERequestContext& ctx); }; +class ECTX_R final : public ServiceFramework { +public: + explicit ECTX_R(Core::System& system_); + ~ECTX_R() override; +}; + } // namespace Service::Glue diff --git a/src/core/hle/service/glue/glue.cpp b/src/core/hle/service/glue/glue.cpp index ea2843462..0b25a3beb 100644 --- a/src/core/hle/service/glue/glue.cpp +++ b/src/core/hle/service/glue/glue.cpp @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include @@ -30,6 +31,7 @@ void LoopProcess(Core::System& system) { // Error Context server_manager->RegisterNamedService("ectx:aw", std::make_shared(system)); + server_manager->RegisterNamedService("ectx:r", std::make_shared(system)); // Notification Services server_manager->RegisterNamedService( diff --git a/src/core/hle/service/ns/platform_service_manager.cpp b/src/core/hle/service/ns/platform_service_manager.cpp index 23cf05005..c32ad3b24 100644 --- a/src/core/hle/service/ns/platform_service_manager.cpp +++ b/src/core/hle/service/ns/platform_service_manager.cpp @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include @@ -149,6 +150,9 @@ IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const ch {106, nullptr, "GetFunctionBlackListVersion"}, {1000, nullptr, "LoadNgWordDataForPlatformRegionChina"}, {1001, nullptr, "GetNgWordDataSizeForPlatformRegionChina"}, + {2010, D<&IPlatformServiceManager::Unknown2010>, "[S2] Unknown2010"}, // [S2] Switch 2 + {2020, D<&IPlatformServiceManager::Unknown2020>, "[S2] Unknown2020"}, // [S2] Switch 2 + {2100, D<&IPlatformServiceManager::OpenFont>, "[S2] OpenFont"}, // [S2] Switch 2 - Returns IFontService }; // clang-format on RegisterHandlers(functions); @@ -270,4 +274,22 @@ Result IPlatformServiceManager::GetSharedFontInOrderOfPriority( R_SUCCEED(); } +Result IPlatformServiceManager::Unknown2010(/* Unknown parameters */) { + LOG_WARNING(Service_NS, "(STUBBED) called - [S2] Switch 2 function"); + R_SUCCEED(); +} + +Result IPlatformServiceManager::Unknown2020(/* Unknown parameters */) { + LOG_WARNING(Service_NS, "(STUBBED) called - [S2] Switch 2 function"); + R_SUCCEED(); +} + +Result IPlatformServiceManager::OpenFont(/* Out> out_font_service */) { + LOG_WARNING(Service_NS, "(STUBBED) called - [S2] OpenFont"); + + // Return stub font service for Switch 2 + // TODO: Implement proper IFontService interface when needed + R_SUCCEED(); +} + } // namespace Service::NS diff --git a/src/core/hle/service/ns/platform_service_manager.h b/src/core/hle/service/ns/platform_service_manager.h index b82c385a6..f142ebc13 100644 --- a/src/core/hle/service/ns/platform_service_manager.h +++ b/src/core/hle/service/ns/platform_service_manager.h @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -70,6 +71,11 @@ private: Out out_fonts_are_loaded, Out out_font_count, Set::LanguageCode language_code); + // [S2] Switch 2 functions + Result Unknown2010(/* Unknown parameters */); + Result Unknown2020(/* Unknown parameters */); + Result OpenFont(/* Out> out_font_service */); + struct Impl; std::unique_ptr impl; };