diff options
Diffstat (limited to 'src/core/hle/service/am/service')
50 files changed, 4410 insertions, 0 deletions
diff --git a/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp b/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp new file mode 100644 index 000000000..eebd90ba2 --- /dev/null +++ b/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp @@ -0,0 +1,80 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/service/am/applet_manager.h" +#include "core/hle/service/am/service/all_system_applet_proxies_service.h" +#include "core/hle/service/am/service/library_applet_proxy.h" +#include "core/hle/service/am/service/system_applet_proxy.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::AM { + +IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_, + Nvnflinger::Nvnflinger& nvnflinger) + : ServiceFramework{system_, "appletAE"}, m_nvnflinger{nvnflinger} { + // clang-format off + static const FunctionInfo functions[] = { + {100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"}, + {200, D<&IAllSystemAppletProxiesService::OpenLibraryAppletProxyOld>, "OpenLibraryAppletProxyOld"}, + {201, D<&IAllSystemAppletProxiesService::OpenLibraryAppletProxy>, "OpenLibraryAppletProxy"}, + {300, nullptr, "OpenOverlayAppletProxy"}, + {350, nullptr, "OpenSystemApplicationProxy"}, + {400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"}, + {410, nullptr, "GetSystemAppletControllerForDebug"}, + {1000, nullptr, "GetDebugFunctions"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IAllSystemAppletProxiesService::~IAllSystemAppletProxiesService() = default; + +Result IAllSystemAppletProxiesService::OpenSystemAppletProxy( + Out<SharedPointer<ISystemAppletProxy>> out_system_applet_proxy, ClientProcessId pid, + InCopyHandle<Kernel::KProcess> process_handle) { + LOG_DEBUG(Service_AM, "called"); + + if (const auto applet = this->GetAppletFromProcessId(pid); applet) { + *out_system_applet_proxy = std::make_shared<ISystemAppletProxy>( + system, applet, process_handle.Get(), m_nvnflinger); + R_SUCCEED(); + } else { + UNIMPLEMENTED(); + R_THROW(ResultUnknown); + } +} + +Result IAllSystemAppletProxiesService::OpenLibraryAppletProxy( + Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy, ClientProcessId pid, + InCopyHandle<Kernel::KProcess> process_handle, + InLargeData<AppletAttribute, BufferAttr_HipcMapAlias> attribute) { + LOG_DEBUG(Service_AM, "called"); + + if (const auto applet = this->GetAppletFromProcessId(pid); applet) { + *out_library_applet_proxy = std::make_shared<ILibraryAppletProxy>( + system, applet, process_handle.Get(), m_nvnflinger); + R_SUCCEED(); + } else { + UNIMPLEMENTED(); + R_THROW(ResultUnknown); + } +} + +Result IAllSystemAppletProxiesService::OpenLibraryAppletProxyOld( + Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy, ClientProcessId pid, + InCopyHandle<Kernel::KProcess> process_handle) { + LOG_DEBUG(Service_AM, "called"); + + AppletAttribute attribute{}; + R_RETURN( + this->OpenLibraryAppletProxy(out_library_applet_proxy, pid, process_handle, attribute)); +} + +std::shared_ptr<Applet> IAllSystemAppletProxiesService::GetAppletFromProcessId( + ProcessId process_id) { + return system.GetAppletManager().GetByAppletResourceUserId(process_id.pid); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/all_system_applet_proxies_service.h b/src/core/hle/service/am/service/all_system_applet_proxies_service.h new file mode 100644 index 000000000..38b1ca2ea --- /dev/null +++ b/src/core/hle/service/am/service/all_system_applet_proxies_service.h @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Service { + +namespace Nvnflinger { +class Nvnflinger; +} + +namespace AM { + +struct Applet; +struct AppletAttribute; +class ILibraryAppletProxy; +class ISystemAppletProxy; + +class IAllSystemAppletProxiesService final + : public ServiceFramework<IAllSystemAppletProxiesService> { +public: + explicit IAllSystemAppletProxiesService(Core::System& system_, + Nvnflinger::Nvnflinger& nvnflinger); + ~IAllSystemAppletProxiesService() override; + +private: + Result OpenSystemAppletProxy(Out<SharedPointer<ISystemAppletProxy>> out_system_applet_proxy, + ClientProcessId pid, + InCopyHandle<Kernel::KProcess> process_handle); + Result OpenLibraryAppletProxy(Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy, + ClientProcessId pid, + InCopyHandle<Kernel::KProcess> process_handle, + InLargeData<AppletAttribute, BufferAttr_HipcMapAlias> attribute); + Result OpenLibraryAppletProxyOld( + Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy, ClientProcessId pid, + InCopyHandle<Kernel::KProcess> process_handle); + +private: + std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid); + Nvnflinger::Nvnflinger& m_nvnflinger; +}; + +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am/service/applet_common_functions.cpp b/src/core/hle/service/am/service/applet_common_functions.cpp new file mode 100644 index 000000000..0f29ab285 --- /dev/null +++ b/src/core/hle/service/am/service/applet_common_functions.cpp @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applet.h" +#include "core/hle/service/am/service/applet_common_functions.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::AM { + +IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_, + std::shared_ptr<Applet> applet_) + : ServiceFramework{system_, "IAppletCommonFunctions"}, applet{std::move(applet_)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "SetTerminateResult"}, + {10, nullptr, "ReadThemeStorage"}, + {11, nullptr, "WriteThemeStorage"}, + {20, nullptr, "PushToAppletBoundChannel"}, + {21, nullptr, "TryPopFromAppletBoundChannel"}, + {40, nullptr, "GetDisplayLogicalResolution"}, + {42, nullptr, "SetDisplayMagnification"}, + {50, nullptr, "SetHomeButtonDoubleClickEnabled"}, + {51, D<&IAppletCommonFunctions::GetHomeButtonDoubleClickEnabled>, "GetHomeButtonDoubleClickEnabled"}, + {52, nullptr, "IsHomeButtonShortPressedBlocked"}, + {60, nullptr, "IsVrModeCurtainRequired"}, + {61, nullptr, "IsSleepRequiredByHighTemperature"}, + {62, nullptr, "IsSleepRequiredByLowBattery"}, + {70, D<&IAppletCommonFunctions::SetCpuBoostRequestPriority>, "SetCpuBoostRequestPriority"}, + {80, nullptr, "SetHandlingCaptureButtonShortPressedMessageEnabledForApplet"}, + {81, nullptr, "SetHandlingCaptureButtonLongPressedMessageEnabledForApplet"}, + {90, nullptr, "OpenNamedChannelAsParent"}, + {91, nullptr, "OpenNamedChannelAsChild"}, + {100, nullptr, "SetApplicationCoreUsageMode"}, + {300, D<&IAppletCommonFunctions::GetCurrentApplicationId>, "GetCurrentApplicationId"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IAppletCommonFunctions::~IAppletCommonFunctions() = default; + +Result IAppletCommonFunctions::GetHomeButtonDoubleClickEnabled( + Out<bool> out_home_button_double_click_enabled) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_home_button_double_click_enabled = false; + R_SUCCEED(); +} + +Result IAppletCommonFunctions::SetCpuBoostRequestPriority(s32 priority) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + std::scoped_lock lk{applet->lock}; + applet->cpu_boost_request_priority = priority; + R_SUCCEED(); +} + +Result IAppletCommonFunctions::GetCurrentApplicationId(Out<u64> out_application_id) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_application_id = system.GetApplicationProcessProgramID() & ~0xFFFULL; + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/applet_common_functions.h b/src/core/hle/service/am/service/applet_common_functions.h new file mode 100644 index 000000000..4424fc83d --- /dev/null +++ b/src/core/hle/service/am/service/applet_common_functions.h @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +struct Applet; + +class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> { +public: + explicit IAppletCommonFunctions(Core::System& system_, std::shared_ptr<Applet> applet_); + ~IAppletCommonFunctions() override; + +private: + Result GetHomeButtonDoubleClickEnabled(Out<bool> out_home_button_double_click_enabled); + Result SetCpuBoostRequestPriority(s32 priority); + Result GetCurrentApplicationId(Out<u64> out_application_id); + + const std::shared_ptr<Applet> applet; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/application_accessor.cpp b/src/core/hle/service/am/service/application_accessor.cpp new file mode 100644 index 000000000..6e7d110e8 --- /dev/null +++ b/src/core/hle/service/am/service/application_accessor.cpp @@ -0,0 +1,138 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/result.h" +#include "core/hle/service/am/am_types.h" +#include "core/hle/service/am/applet.h" +#include "core/hle/service/am/applet_data_broker.h" +#include "core/hle/service/am/applet_manager.h" +#include "core/hle/service/am/service/application_accessor.h" +#include "core/hle/service/am/service/library_applet_accessor.h" +#include "core/hle/service/am/service/storage.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::AM { + +IApplicationAccessor::IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet) + : ServiceFramework{system_, "IApplicationAccessor"}, m_applet(std::move(applet)) { + // clang-format off + static const FunctionInfo functions[] = { + {0, D<&IApplicationAccessor::GetAppletStateChangedEvent>, "GetAppletStateChangedEvent"}, + {1, nullptr, "IsCompleted"}, + {10, D<&IApplicationAccessor::Start>, "Start"}, + {20, D<&IApplicationAccessor::RequestExit>, "RequestExit"}, + {25, D<&IApplicationAccessor::Terminate>, "Terminate"}, + {30, D<&IApplicationAccessor::GetResult>, "GetResult"}, + {101, D<&IApplicationAccessor::RequestForApplicationToGetForeground>, "RequestForApplicationToGetForeground"}, + {110, nullptr, "TerminateAllLibraryApplets"}, + {111, nullptr, "AreAnyLibraryAppletsLeft"}, + {112, D<&IApplicationAccessor::GetCurrentLibraryApplet>, "GetCurrentLibraryApplet"}, + {120, nullptr, "GetApplicationId"}, + {121, D<&IApplicationAccessor::PushLaunchParameter>, "PushLaunchParameter"}, + {122, D<&IApplicationAccessor::GetApplicationControlProperty>, "GetApplicationControlProperty"}, + {123, nullptr, "GetApplicationLaunchProperty"}, + {124, nullptr, "GetApplicationLaunchRequestInfo"}, + {130, D<&IApplicationAccessor::SetUsers>, "SetUsers"}, + {131, D<&IApplicationAccessor::CheckRightsEnvironmentAvailable>, "CheckRightsEnvironmentAvailable"}, + {132, D<&IApplicationAccessor::GetNsRightsEnvironmentHandle>, "GetNsRightsEnvironmentHandle"}, + {140, nullptr, "GetDesirableUids"}, + {150, D<&IApplicationAccessor::ReportApplicationExitTimeout>, "ReportApplicationExitTimeout"}, + {160, nullptr, "SetApplicationAttribute"}, + {170, nullptr, "HasSaveDataAccessPermission"}, + {180, nullptr, "PushToFriendInvitationStorageChannel"}, + {190, nullptr, "PushToNotificationStorageChannel"}, + {200, nullptr, "RequestApplicationSoftReset"}, + {201, nullptr, "RestartApplicationTimer"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IApplicationAccessor::~IApplicationAccessor() = default; + +Result IApplicationAccessor::Start() { + LOG_INFO(Service_AM, "called"); + m_applet->process->Run(); + R_SUCCEED(); +} + +Result IApplicationAccessor::RequestExit() { + LOG_INFO(Service_AM, "called"); + m_applet->message_queue.RequestExit(); + R_SUCCEED(); +} + +Result IApplicationAccessor::Terminate() { + LOG_INFO(Service_AM, "called"); + m_applet->process->Terminate(); + R_SUCCEED(); +} + +Result IApplicationAccessor::GetResult() { + LOG_INFO(Service_AM, "called"); + R_SUCCEED(); +} + +Result IApplicationAccessor::GetAppletStateChangedEvent( + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_INFO(Service_AM, "called"); + *out_event = m_applet->caller_applet_broker->GetStateChangedEvent().GetHandle(); + R_SUCCEED(); +} + +Result IApplicationAccessor::PushLaunchParameter(LaunchParameterKind kind, + SharedPointer<IStorage> storage) { + LOG_INFO(Service_AM, "called, kind={}", kind); + + switch (kind) { + case LaunchParameterKind::AccountPreselectedUser: + m_applet->preselected_user_launch_parameter.push_back(storage->GetData()); + R_SUCCEED(); + default: + R_THROW(ResultUnknown); + } +} + +Result IApplicationAccessor::GetApplicationControlProperty( + OutBuffer<BufferAttr_HipcMapAlias> out_control_property) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_THROW(ResultUnknown); +} + +Result IApplicationAccessor::SetUsers(bool enable, + InArray<Common::UUID, BufferAttr_HipcMapAlias> user_ids) { + LOG_INFO(Service_AM, "called, enable={} user_id_count={}", enable, user_ids.size()); + R_SUCCEED(); +} + +Result IApplicationAccessor::GetCurrentLibraryApplet( + Out<SharedPointer<ILibraryAppletAccessor>> out_accessor) { + LOG_INFO(Service_AM, "(STUBBED) called"); + *out_accessor = nullptr; + R_SUCCEED(); +} + +Result IApplicationAccessor::RequestForApplicationToGetForeground() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_THROW(ResultUnknown); +} + +Result IApplicationAccessor::CheckRightsEnvironmentAvailable(Out<bool> out_is_available) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_is_available = true; + R_SUCCEED(); +} + +Result IApplicationAccessor::GetNsRightsEnvironmentHandle(Out<u64> out_handle) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_handle = 0xdeadbeef; + R_SUCCEED(); +} + +Result IApplicationAccessor::ReportApplicationExitTimeout() { + LOG_ERROR(Service_AM, "called"); + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/application_accessor.h b/src/core/hle/service/am/service/application_accessor.h new file mode 100644 index 000000000..39a9b2153 --- /dev/null +++ b/src/core/hle/service/am/service/application_accessor.h @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/uuid.h" +#include "core/hle/service/am/am_types.h" +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +struct Applet; +class ILibraryAppletAccessor; +class IStorage; + +class IApplicationAccessor final : public ServiceFramework<IApplicationAccessor> { +public: + explicit IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet); + ~IApplicationAccessor() override; + +private: + Result Start(); + Result RequestExit(); + Result Terminate(); + Result GetResult(); + Result GetAppletStateChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); + Result PushLaunchParameter(LaunchParameterKind kind, SharedPointer<IStorage> storage); + Result GetApplicationControlProperty(OutBuffer<BufferAttr_HipcMapAlias> out_control_property); + Result SetUsers(bool enable, InArray<Common::UUID, BufferAttr_HipcMapAlias> user_ids); + Result GetCurrentLibraryApplet(Out<SharedPointer<ILibraryAppletAccessor>> out_accessor); + Result RequestForApplicationToGetForeground(); + Result CheckRightsEnvironmentAvailable(Out<bool> out_is_available); + Result GetNsRightsEnvironmentHandle(Out<u64> out_handle); + Result ReportApplicationExitTimeout(); + + const std::shared_ptr<Applet> m_applet; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/application_creator.cpp b/src/core/hle/service/am/service/application_creator.cpp new file mode 100644 index 000000000..568bb0122 --- /dev/null +++ b/src/core/hle/service/am/service/application_creator.cpp @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/am_types.h" +#include "core/hle/service/am/applet.h" +#include "core/hle/service/am/applet_manager.h" +#include "core/hle/service/am/service/application_accessor.h" +#include "core/hle/service/am/service/application_creator.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::AM { + +IApplicationCreator::IApplicationCreator(Core::System& system_) + : ServiceFramework{system_, "IApplicationCreator"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, D<&IApplicationCreator::CreateApplication>, "CreateApplication"}, + {1, nullptr, "PopLaunchRequestedApplication"}, + {10, nullptr, "CreateSystemApplication"}, + {100, nullptr, "PopFloatingApplicationForDevelopment"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IApplicationCreator::~IApplicationCreator() = default; + +Result IApplicationCreator::CreateApplication( + Out<SharedPointer<IApplicationAccessor>> out_application_accessor, u64 application_id) { + LOG_ERROR(Service_NS, "called, application_id={:x}", application_id); + R_THROW(ResultUnknown); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/application_creator.h b/src/core/hle/service/am/service/application_creator.h new file mode 100644 index 000000000..9f939ebf6 --- /dev/null +++ b/src/core/hle/service/am/service/application_creator.h @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IApplicationAccessor; +struct Applet; + +class IApplicationCreator final : public ServiceFramework<IApplicationCreator> { +public: + explicit IApplicationCreator(Core::System& system_); + ~IApplicationCreator() override; + +private: + Result CreateApplication(Out<SharedPointer<IApplicationAccessor>>, u64 application_id); +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/application_functions.cpp b/src/core/hle/service/am/service/application_functions.cpp new file mode 100644 index 000000000..b788fddd4 --- /dev/null +++ b/src/core/hle/service/am/service/application_functions.cpp @@ -0,0 +1,465 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/settings.h" +#include "common/uuid.h" +#include "core/file_sys/control_metadata.h" +#include "core/file_sys/patch_manager.h" +#include "core/file_sys/registered_cache.h" +#include "core/file_sys/savedata_factory.h" +#include "core/hle/kernel/k_transfer_memory.h" +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/applet.h" +#include "core/hle/service/am/service/application_functions.h" +#include "core/hle/service/am/service/storage.h" +#include "core/hle/service/cmif_serialization.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/filesystem/save_data_controller.h" +#include "core/hle/service/ns/ns.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::AM { + +IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet) + : ServiceFramework{system_, "IApplicationFunctions"}, m_applet{std::move(applet)} { + // clang-format off + static const FunctionInfo functions[] = { + {1, D<&IApplicationFunctions::PopLaunchParameter>, "PopLaunchParameter"}, + {10, nullptr, "CreateApplicationAndPushAndRequestToStart"}, + {11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"}, + {12, nullptr, "CreateApplicationAndRequestToStart"}, + {13, nullptr, "CreateApplicationAndRequestToStartForQuest"}, + {14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"}, + {15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"}, + {20, D<&IApplicationFunctions::EnsureSaveData>, "EnsureSaveData"}, + {21, D<&IApplicationFunctions::GetDesiredLanguage>, "GetDesiredLanguage"}, + {22, D<&IApplicationFunctions::SetTerminateResult>, "SetTerminateResult"}, + {23, D<&IApplicationFunctions::GetDisplayVersion>, "GetDisplayVersion"}, + {24, nullptr, "GetLaunchStorageInfoForDebug"}, + {25, D<&IApplicationFunctions::ExtendSaveData>, "ExtendSaveData"}, + {26, D<&IApplicationFunctions::GetSaveDataSize>, "GetSaveDataSize"}, + {27, D<&IApplicationFunctions::CreateCacheStorage>, "CreateCacheStorage"}, + {28, D<&IApplicationFunctions::GetSaveDataSizeMax>, "GetSaveDataSizeMax"}, + {29, nullptr, "GetCacheStorageMax"}, + {30, D<&IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed>, "BeginBlockingHomeButtonShortAndLongPressed"}, + {31, D<&IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed>, "EndBlockingHomeButtonShortAndLongPressed"}, + {32, D<&IApplicationFunctions::BeginBlockingHomeButton>, "BeginBlockingHomeButton"}, + {33, D<&IApplicationFunctions::EndBlockingHomeButton>, "EndBlockingHomeButton"}, + {34, nullptr, "SelectApplicationLicense"}, + {35, nullptr, "GetDeviceSaveDataSizeMax"}, + {36, nullptr, "GetLimitedApplicationLicense"}, + {37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"}, + {40, D<&IApplicationFunctions::NotifyRunning>, "NotifyRunning"}, + {50, D<&IApplicationFunctions::GetPseudoDeviceId>, "GetPseudoDeviceId"}, + {60, nullptr, "SetMediaPlaybackStateForApplication"}, + {65, D<&IApplicationFunctions::IsGamePlayRecordingSupported>, "IsGamePlayRecordingSupported"}, + {66, D<&IApplicationFunctions::InitializeGamePlayRecording>, "InitializeGamePlayRecording"}, + {67, D<&IApplicationFunctions::SetGamePlayRecordingState>, "SetGamePlayRecordingState"}, + {68, nullptr, "RequestFlushGamePlayingMovieForDebug"}, + {70, nullptr, "RequestToShutdown"}, + {71, nullptr, "RequestToReboot"}, + {72, nullptr, "RequestToSleep"}, + {80, nullptr, "ExitAndRequestToShowThanksMessage"}, + {90, D<&IApplicationFunctions::EnableApplicationCrashReport>, "EnableApplicationCrashReport"}, + {100, D<&IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer>, "InitializeApplicationCopyrightFrameBuffer"}, + {101, D<&IApplicationFunctions::SetApplicationCopyrightImage>, "SetApplicationCopyrightImage"}, + {102, D<&IApplicationFunctions::SetApplicationCopyrightVisibility>, "SetApplicationCopyrightVisibility"}, + {110, D<&IApplicationFunctions::QueryApplicationPlayStatistics>, "QueryApplicationPlayStatistics"}, + {111, D<&IApplicationFunctions::QueryApplicationPlayStatisticsByUid>, "QueryApplicationPlayStatisticsByUid"}, + {120, D<&IApplicationFunctions::ExecuteProgram>, "ExecuteProgram"}, + {121, D<&IApplicationFunctions::ClearUserChannel>, "ClearUserChannel"}, + {122, D<&IApplicationFunctions::UnpopToUserChannel>, "UnpopToUserChannel"}, + {123, D<&IApplicationFunctions::GetPreviousProgramIndex>, "GetPreviousProgramIndex"}, + {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, + {130, D<&IApplicationFunctions::GetGpuErrorDetectedSystemEvent>, "GetGpuErrorDetectedSystemEvent"}, + {131, nullptr, "SetDelayTimeToAbortOnGpuError"}, + {140, D<&IApplicationFunctions::GetFriendInvitationStorageChannelEvent>, "GetFriendInvitationStorageChannelEvent"}, + {141, D<&IApplicationFunctions::TryPopFromFriendInvitationStorageChannel>, "TryPopFromFriendInvitationStorageChannel"}, + {150, D<&IApplicationFunctions::GetNotificationStorageChannelEvent>, "GetNotificationStorageChannelEvent"}, + {151, nullptr, "TryPopFromNotificationStorageChannel"}, + {160, D<&IApplicationFunctions::GetHealthWarningDisappearedSystemEvent>, "GetHealthWarningDisappearedSystemEvent"}, + {170, nullptr, "SetHdcpAuthenticationActivated"}, + {180, nullptr, "GetLaunchRequiredVersion"}, + {181, nullptr, "UpgradeLaunchRequiredVersion"}, + {190, nullptr, "SendServerMaintenanceOverlayNotification"}, + {200, nullptr, "GetLastApplicationExitReason"}, + {500, nullptr, "StartContinuousRecordingFlushForDebug"}, + {1000, nullptr, "CreateMovieMaker"}, + {1001, D<&IApplicationFunctions::PrepareForJit>, "PrepareForJit"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IApplicationFunctions::~IApplicationFunctions() = default; + +Result IApplicationFunctions::PopLaunchParameter(Out<SharedPointer<IStorage>> out_storage, + LaunchParameterKind launch_parameter_kind) { + LOG_INFO(Service_AM, "called, kind={}", launch_parameter_kind); + + std::scoped_lock lk{m_applet->lock}; + + auto& channel = launch_parameter_kind == LaunchParameterKind::UserChannel + ? m_applet->user_channel_launch_parameter + : m_applet->preselected_user_launch_parameter; + + if (channel.empty()) { + LOG_WARNING(Service_AM, "Attempted to pop parameter {} but none was found!", + launch_parameter_kind); + R_THROW(AM::ResultNoDataInChannel); + } + + auto data = channel.back(); + channel.pop_back(); + + *out_storage = std::make_shared<IStorage>(system, std::move(data)); + R_SUCCEED(); +} + +Result IApplicationFunctions::EnsureSaveData(Out<u64> out_size, Common::UUID user_id) { + LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString()); + + FileSys::SaveDataAttribute attribute{}; + attribute.title_id = m_applet->program_id; + attribute.user_id = user_id.AsU128(); + attribute.type = FileSys::SaveDataType::SaveData; + + FileSys::VirtualDir save_data{}; + R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData( + &save_data, FileSys::SaveDataSpaceId::NandUser, attribute)); + + *out_size = 0; + R_SUCCEED(); +} + +Result IApplicationFunctions::GetDesiredLanguage(Out<u64> out_language_code) { + // FIXME: all of this stuff belongs to ns + // TODO(bunnei): This should be configurable + LOG_DEBUG(Service_AM, "called"); + + // Get supported languages from NACP, if possible + // Default to 0 (all languages supported) + u32 supported_languages = 0; + + const auto res = [this] { + const FileSys::PatchManager pm{m_applet->program_id, system.GetFileSystemController(), + system.GetContentProvider()}; + auto metadata = pm.GetControlMetadata(); + if (metadata.first != nullptr) { + return metadata; + } + + const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(m_applet->program_id), + system.GetFileSystemController(), + system.GetContentProvider()}; + return pm_update.GetControlMetadata(); + }(); + + if (res.first != nullptr) { + supported_languages = res.first->GetSupportedLanguages(); + } + + // Call IApplicationManagerInterface implementation. + auto& service_manager = system.ServiceManager(); + auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2"); + auto app_man = ns_am2->GetApplicationManagerInterface(); + + // Get desired application language + u8 desired_language{}; + R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages)); + + // Convert to settings language code. + R_TRY(app_man->ConvertApplicationLanguageToLanguageCode(out_language_code, desired_language)); + + LOG_DEBUG(Service_AM, "got desired_language={:016X}", *out_language_code); + R_SUCCEED(); +} + +Result IApplicationFunctions::SetTerminateResult(Result terminate_result) { + LOG_INFO(Service_AM, "(STUBBED) called, result={:#x} ({}-{})", terminate_result.GetInnerValue(), + static_cast<u32>(terminate_result.GetModule()) + 2000, + terminate_result.GetDescription()); + + std::scoped_lock lk{m_applet->lock}; + m_applet->terminate_result = terminate_result; + + R_SUCCEED(); +} + +Result IApplicationFunctions::GetDisplayVersion(Out<DisplayVersion> out_display_version) { + LOG_DEBUG(Service_AM, "called"); + + const auto res = [this] { + const FileSys::PatchManager pm{m_applet->program_id, system.GetFileSystemController(), + system.GetContentProvider()}; + auto metadata = pm.GetControlMetadata(); + if (metadata.first != nullptr) { + return metadata; + } + + const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(m_applet->program_id), + system.GetFileSystemController(), + system.GetContentProvider()}; + return pm_update.GetControlMetadata(); + }(); + + if (res.first != nullptr) { + const auto& version = res.first->GetVersionString(); + std::memcpy(out_display_version->string.data(), version.data(), + std::min(version.size(), out_display_version->string.size())); + } else { + static constexpr char default_version[]{"1.0.0"}; + std::memcpy(out_display_version->string.data(), default_version, sizeof(default_version)); + } + + out_display_version->string[out_display_version->string.size() - 1] = '\0'; + R_SUCCEED(); +} + +Result IApplicationFunctions::ExtendSaveData(Out<u64> out_required_size, FileSys::SaveDataType type, + Common::UUID user_id, u64 normal_size, + u64 journal_size) { + LOG_DEBUG(Service_AM, "called with type={} user_id={} normal={:#x} journal={:#x}", + static_cast<u8>(type), user_id.FormattedString(), normal_size, journal_size); + + system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize( + type, m_applet->program_id, user_id.AsU128(), {normal_size, journal_size}); + + // The following value is used to indicate the amount of space remaining on failure + // due to running out of space. Since we always succeed, this should be 0. + *out_required_size = 0; + + R_SUCCEED(); +} + +Result IApplicationFunctions::GetSaveDataSize(Out<u64> out_normal_size, Out<u64> out_journal_size, + FileSys::SaveDataType type, Common::UUID user_id) { + LOG_DEBUG(Service_AM, "called with type={} user_id={}", type, user_id.FormattedString()); + + const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize( + type, m_applet->program_id, user_id.AsU128()); + + *out_normal_size = size.normal; + *out_journal_size = size.journal; + R_SUCCEED(); +} + +Result IApplicationFunctions::CreateCacheStorage(Out<u32> out_target_media, + Out<u64> out_required_size, u16 index, + u64 normal_size, u64 journal_size) { + LOG_WARNING(Service_AM, "(STUBBED) called with index={} size={:#x} journal_size={:#x}", index, + normal_size, journal_size); + + *out_target_media = 1; // Nand + *out_required_size = 0; + + R_SUCCEED(); +} + +Result IApplicationFunctions::GetSaveDataSizeMax(Out<u64> out_max_normal_size, + Out<u64> out_max_journal_size) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + *out_max_normal_size = 0xFFFFFFF; + *out_max_journal_size = 0xFFFFFFF; + + R_SUCCEED(); +} + +Result IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(s64 unused) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::scoped_lock lk{m_applet->lock}; + m_applet->home_button_long_pressed_blocked = true; + m_applet->home_button_short_pressed_blocked = true; + + R_SUCCEED(); +} + +Result IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::scoped_lock lk{m_applet->lock}; + m_applet->home_button_long_pressed_blocked = false; + m_applet->home_button_short_pressed_blocked = false; + + R_SUCCEED(); +} + +Result IApplicationFunctions::BeginBlockingHomeButton(s64 timeout_ns) { + LOG_WARNING(Service_AM, "(STUBBED) called, timeout_ns={}", timeout_ns); + + std::scoped_lock lk{m_applet->lock}; + m_applet->home_button_long_pressed_blocked = true; + m_applet->home_button_short_pressed_blocked = true; + m_applet->home_button_double_click_enabled = true; + + R_SUCCEED(); +} + +Result IApplicationFunctions::EndBlockingHomeButton() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::scoped_lock lk{m_applet->lock}; + m_applet->home_button_long_pressed_blocked = false; + m_applet->home_button_short_pressed_blocked = false; + m_applet->home_button_double_click_enabled = false; + + R_SUCCEED(); +} + +Result IApplicationFunctions::NotifyRunning(Out<bool> out_became_running) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_became_running = true; + R_SUCCEED(); +} + +Result IApplicationFunctions::GetPseudoDeviceId(Out<Common::UUID> out_pseudo_device_id) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_pseudo_device_id = {}; + R_SUCCEED(); +} + +Result IApplicationFunctions::IsGamePlayRecordingSupported( + Out<bool> out_is_game_play_recording_supported) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_is_game_play_recording_supported = m_applet->game_play_recording_supported; + R_SUCCEED(); +} + +Result IApplicationFunctions::InitializeGamePlayRecording( + u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_SUCCEED(); +} + +Result IApplicationFunctions::SetGamePlayRecordingState( + GamePlayRecordingState game_play_recording_state) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::scoped_lock lk{m_applet->lock}; + m_applet->game_play_recording_state = game_play_recording_state; + + R_SUCCEED(); +} + +Result IApplicationFunctions::EnableApplicationCrashReport(bool enabled) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::scoped_lock lk{m_applet->lock}; + m_applet->application_crash_report_enabled = enabled; + + R_SUCCEED(); +} + +Result IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer( + s32 width, s32 height, u64 transfer_memory_size, + InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_SUCCEED(); +} + +Result IApplicationFunctions::SetApplicationCopyrightImage( + s32 x, s32 y, s32 width, s32 height, WindowOriginMode window_origin_mode, + InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> image_data) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_SUCCEED(); +} + +Result IApplicationFunctions::SetApplicationCopyrightVisibility(bool visible) { + LOG_WARNING(Service_AM, "(STUBBED) called, is_visible={}", visible); + R_SUCCEED(); +} + +Result IApplicationFunctions::QueryApplicationPlayStatistics( + Out<s32> out_entries, + OutArray<ApplicationPlayStatistics, BufferAttr_HipcMapAlias> out_play_statistics, + InArray<u64, BufferAttr_HipcMapAlias> application_ids) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_entries = 0; + R_SUCCEED(); +} + +Result IApplicationFunctions::QueryApplicationPlayStatisticsByUid( + Out<s32> out_entries, + OutArray<ApplicationPlayStatistics, BufferAttr_HipcMapAlias> out_play_statistics, + Common::UUID user_id, InArray<u64, BufferAttr_HipcMapAlias> application_ids) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_entries = 0; + R_SUCCEED(); +} + +Result IApplicationFunctions::ExecuteProgram(ProgramSpecifyKind kind, u64 value) { + LOG_WARNING(Service_AM, "(STUBBED) called, kind={}, value={}", kind, value); + ASSERT(kind == ProgramSpecifyKind::ExecuteProgram || + kind == ProgramSpecifyKind::RestartProgram); + + // Copy user channel ownership into the system so that it will be preserved + system.GetUserChannel() = m_applet->user_channel_launch_parameter; + system.ExecuteProgram(value); + R_SUCCEED(); +} + +Result IApplicationFunctions::ClearUserChannel() { + LOG_DEBUG(Service_AM, "called"); + m_applet->user_channel_launch_parameter.clear(); + R_SUCCEED(); +} + +Result IApplicationFunctions::UnpopToUserChannel(SharedPointer<IStorage> storage) { + LOG_DEBUG(Service_AM, "called"); + m_applet->user_channel_launch_parameter.push_back(storage->GetData()); + R_SUCCEED(); +} + +Result IApplicationFunctions::GetPreviousProgramIndex(Out<s32> out_previous_program_index) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_previous_program_index = m_applet->previous_program_index; + R_SUCCEED(); +} + +Result IApplicationFunctions::GetGpuErrorDetectedSystemEvent( + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_event = m_applet->gpu_error_detected_event.GetHandle(); + R_SUCCEED(); +} + +Result IApplicationFunctions::GetFriendInvitationStorageChannelEvent( + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_DEBUG(Service_AM, "called"); + *out_event = m_applet->friend_invitation_storage_channel_event.GetHandle(); + R_SUCCEED(); +} + +Result IApplicationFunctions::TryPopFromFriendInvitationStorageChannel( + Out<SharedPointer<IStorage>> out_storage) { + LOG_INFO(Service_AM, "(STUBBED) called"); + R_THROW(AM::ResultNoDataInChannel); +} + +Result IApplicationFunctions::GetNotificationStorageChannelEvent( + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_DEBUG(Service_AM, "called"); + *out_event = m_applet->notification_storage_channel_event.GetHandle(); + R_SUCCEED(); +} + +Result IApplicationFunctions::GetHealthWarningDisappearedSystemEvent( + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_DEBUG(Service_AM, "called"); + *out_event = m_applet->health_warning_disappeared_system_event.GetHandle(); + R_SUCCEED(); +} + +Result IApplicationFunctions::PrepareForJit() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::scoped_lock lk{m_applet->lock}; + m_applet->jit_service_launched = true; + + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/application_functions.h b/src/core/hle/service/am/service/application_functions.h new file mode 100644 index 000000000..3548202f8 --- /dev/null +++ b/src/core/hle/service/am/service/application_functions.h @@ -0,0 +1,83 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/uuid.h" +#include "core/hle/service/am/am_types.h" +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace FileSys { +enum class SaveDataType : u8; +} + +namespace Kernel { +class KReadableEvent; +} + +namespace Service::AM { + +struct Applet; +class IStorage; + +class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { +public: + explicit IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet); + ~IApplicationFunctions() override; + +private: + Result PopLaunchParameter(Out<SharedPointer<IStorage>> out_storage, + LaunchParameterKind launch_parameter_kind); + Result EnsureSaveData(Out<u64> out_size, Common::UUID user_id); + Result GetDesiredLanguage(Out<u64> out_language_code); + Result SetTerminateResult(Result terminate_result); + Result GetDisplayVersion(Out<DisplayVersion> out_display_version); + Result ExtendSaveData(Out<u64> out_required_size, FileSys::SaveDataType type, + Common::UUID user_id, u64 normal_size, u64 journal_size); + Result GetSaveDataSize(Out<u64> out_normal_size, Out<u64> out_journal_size, + FileSys::SaveDataType type, Common::UUID user_id); + Result CreateCacheStorage(Out<u32> out_target_media, Out<u64> out_required_size, u16 index, + u64 normal_size, u64 journal_size); + Result GetSaveDataSizeMax(Out<u64> out_max_normal_size, Out<u64> out_max_journal_size); + Result BeginBlockingHomeButtonShortAndLongPressed(s64 unused); + Result EndBlockingHomeButtonShortAndLongPressed(); + Result BeginBlockingHomeButton(s64 timeout_ns); + Result EndBlockingHomeButton(); + Result NotifyRunning(Out<bool> out_became_running); + Result GetPseudoDeviceId(Out<Common::UUID> out_pseudo_device_id); + Result IsGamePlayRecordingSupported(Out<bool> out_is_game_play_recording_supported); + Result InitializeGamePlayRecording( + u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle); + Result SetGamePlayRecordingState(GamePlayRecordingState game_play_recording_state); + Result EnableApplicationCrashReport(bool enabled); + Result InitializeApplicationCopyrightFrameBuffer( + s32 width, s32 height, u64 transfer_memory_size, + InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle); + Result SetApplicationCopyrightImage( + s32 x, s32 y, s32 width, s32 height, WindowOriginMode window_origin_mode, + InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> image_data); + Result SetApplicationCopyrightVisibility(bool visible); + Result QueryApplicationPlayStatistics( + Out<s32> out_entries, + OutArray<ApplicationPlayStatistics, BufferAttr_HipcMapAlias> out_play_statistics, + InArray<u64, BufferAttr_HipcMapAlias> application_ids); + Result QueryApplicationPlayStatisticsByUid( + Out<s32> out_entries, + OutArray<ApplicationPlayStatistics, BufferAttr_HipcMapAlias> out_play_statistics, + Common::UUID user_id, InArray<u64, BufferAttr_HipcMapAlias> application_ids); + Result ExecuteProgram(ProgramSpecifyKind kind, u64 value); + Result ClearUserChannel(); + Result UnpopToUserChannel(SharedPointer<IStorage> storage); + Result GetPreviousProgramIndex(Out<s32> out_previous_program_index); + Result GetGpuErrorDetectedSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); + Result GetFriendInvitationStorageChannelEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); + Result TryPopFromFriendInvitationStorageChannel(Out<SharedPointer<IStorage>> out_storage); + Result GetNotificationStorageChannelEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); + Result GetHealthWarningDisappearedSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); + Result PrepareForJit(); + + const std::shared_ptr<Applet> m_applet; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/application_proxy.cpp b/src/core/hle/service/am/service/application_proxy.cpp new file mode 100644 index 000000000..776f4552b --- /dev/null +++ b/src/core/hle/service/am/service/application_proxy.cpp @@ -0,0 +1,106 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/service/applet_common_functions.h" +#include "core/hle/service/am/service/application_functions.h" +#include "core/hle/service/am/service/application_proxy.h" +#include "core/hle/service/am/service/audio_controller.h" +#include "core/hle/service/am/service/common_state_getter.h" +#include "core/hle/service/am/service/debug_functions.h" +#include "core/hle/service/am/service/display_controller.h" +#include "core/hle/service/am/service/library_applet_creator.h" +#include "core/hle/service/am/service/process_winding_controller.h" +#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" + +namespace Service::AM { + +IApplicationProxy::IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet, + Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger) + : ServiceFramework{system_, "IApplicationProxy"}, + m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, D<&IApplicationProxy::GetCommonStateGetter>, "GetCommonStateGetter"}, + {1, D<&IApplicationProxy::GetSelfController>, "GetSelfController"}, + {2, D<&IApplicationProxy::GetWindowController>, "GetWindowController"}, + {3, D<&IApplicationProxy::GetAudioController>, "GetAudioController"}, + {4, D<&IApplicationProxy::GetDisplayController>, "GetDisplayController"}, + {10, D<&IApplicationProxy::GetProcessWindingController>, "GetProcessWindingController"}, + {11, D<&IApplicationProxy::GetLibraryAppletCreator>, "GetLibraryAppletCreator"}, + {20, D<&IApplicationProxy::GetApplicationFunctions>, "GetApplicationFunctions"}, + {1000, D<&IApplicationProxy::GetDebugFunctions>, "GetDebugFunctions"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IApplicationProxy::~IApplicationProxy() = default; + +Result IApplicationProxy::GetAudioController( + Out<SharedPointer<IAudioController>> out_audio_controller) { + LOG_DEBUG(Service_AM, "called"); + *out_audio_controller = std::make_shared<IAudioController>(system); + R_SUCCEED(); +} + +Result IApplicationProxy::GetDisplayController( + Out<SharedPointer<IDisplayController>> out_display_controller) { + LOG_DEBUG(Service_AM, "called"); + *out_display_controller = std::make_shared<IDisplayController>(system, m_applet); + R_SUCCEED(); +} + +Result IApplicationProxy::GetProcessWindingController( + Out<SharedPointer<IProcessWindingController>> out_process_winding_controller) { + LOG_DEBUG(Service_AM, "called"); + *out_process_winding_controller = std::make_shared<IProcessWindingController>(system, m_applet); + R_SUCCEED(); +} + +Result IApplicationProxy::GetDebugFunctions( + Out<SharedPointer<IDebugFunctions>> out_debug_functions) { + LOG_DEBUG(Service_AM, "called"); + *out_debug_functions = std::make_shared<IDebugFunctions>(system); + R_SUCCEED(); +} + +Result IApplicationProxy::GetWindowController( + Out<SharedPointer<IWindowController>> out_window_controller) { + LOG_DEBUG(Service_AM, "called"); + *out_window_controller = std::make_shared<IWindowController>(system, m_applet); + R_SUCCEED(); +} + +Result IApplicationProxy::GetSelfController( + Out<SharedPointer<ISelfController>> out_self_controller) { + LOG_DEBUG(Service_AM, "called"); + *out_self_controller = + std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger); + R_SUCCEED(); +} + +Result IApplicationProxy::GetCommonStateGetter( + Out<SharedPointer<ICommonStateGetter>> out_common_state_getter) { + LOG_DEBUG(Service_AM, "called"); + *out_common_state_getter = std::make_shared<ICommonStateGetter>(system, m_applet); + R_SUCCEED(); +} + +Result IApplicationProxy::GetLibraryAppletCreator( + Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) { + LOG_DEBUG(Service_AM, "called"); + *out_library_applet_creator = std::make_shared<ILibraryAppletCreator>(system, m_applet); + R_SUCCEED(); +} + +Result IApplicationProxy::GetApplicationFunctions( + Out<SharedPointer<IApplicationFunctions>> out_application_functions) { + LOG_DEBUG(Service_AM, "called"); + *out_application_functions = std::make_shared<IApplicationFunctions>(system, m_applet); + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/application_proxy.h b/src/core/hle/service/am/service/application_proxy.h new file mode 100644 index 000000000..1ebc593ba --- /dev/null +++ b/src/core/hle/service/am/service/application_proxy.h @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +struct Applet; +class IAudioController; +class IApplicationFunctions; +class ICommonStateGetter; +class IDebugFunctions; +class IDisplayController; +class ILibraryAppletCreator; +class IProcessWindingController; +class ISelfController; +class IWindowController; + +class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { +public: + explicit IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet, + Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger); + ~IApplicationProxy(); + +private: + Result GetAudioController(Out<SharedPointer<IAudioController>> out_audio_controller); + Result GetDisplayController(Out<SharedPointer<IDisplayController>> out_display_controller); + Result GetProcessWindingController( + Out<SharedPointer<IProcessWindingController>> out_process_winding_controller); + Result GetDebugFunctions(Out<SharedPointer<IDebugFunctions>> out_debug_functions); + Result GetWindowController(Out<SharedPointer<IWindowController>> out_window_controller); + Result GetSelfController(Out<SharedPointer<ISelfController>> out_self_controller); + Result GetCommonStateGetter(Out<SharedPointer<ICommonStateGetter>> out_common_state_getter); + Result GetLibraryAppletCreator( + Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator); + Result GetApplicationFunctions( + Out<SharedPointer<IApplicationFunctions>> out_application_functions); + +private: + Nvnflinger::Nvnflinger& m_nvnflinger; + Kernel::KProcess* const m_process; + const std::shared_ptr<Applet> m_applet; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/application_proxy_service.cpp b/src/core/hle/service/am/service/application_proxy_service.cpp new file mode 100644 index 000000000..36d4478df --- /dev/null +++ b/src/core/hle/service/am/service/application_proxy_service.cpp @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/applet_manager.h" +#include "core/hle/service/am/service/application_proxy.h" +#include "core/hle/service/am/service/application_proxy_service.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::AM { + +IApplicationProxyService::IApplicationProxyService(Core::System& system_, + Nvnflinger::Nvnflinger& nvnflinger) + : ServiceFramework{system_, "appletOE"}, m_nvnflinger{nvnflinger} { + static const FunctionInfo functions[] = { + {0, D<&IApplicationProxyService::OpenApplicationProxy>, "OpenApplicationProxy"}, + }; + RegisterHandlers(functions); +} + +IApplicationProxyService::~IApplicationProxyService() = default; + +Result IApplicationProxyService::OpenApplicationProxy( + Out<SharedPointer<IApplicationProxy>> out_application_proxy, ClientProcessId pid, + InCopyHandle<Kernel::KProcess> process_handle) { + LOG_DEBUG(Service_AM, "called"); + + if (const auto applet = this->GetAppletFromProcessId(pid)) { + *out_application_proxy = + std::make_shared<IApplicationProxy>(system, applet, process_handle.Get(), m_nvnflinger); + R_SUCCEED(); + } else { + UNIMPLEMENTED(); + R_THROW(ResultUnknown); + } +} + +std::shared_ptr<Applet> IApplicationProxyService::GetAppletFromProcessId(ProcessId process_id) { + return system.GetAppletManager().GetByAppletResourceUserId(process_id.pid); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/application_proxy_service.h b/src/core/hle/service/am/service/application_proxy_service.h new file mode 100644 index 000000000..1c1d32d0b --- /dev/null +++ b/src/core/hle/service/am/service/application_proxy_service.h @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Service { + +namespace Nvnflinger { +class Nvnflinger; +} + +namespace AM { + +struct Applet; +class IApplicationProxy; + +class IApplicationProxyService final : public ServiceFramework<IApplicationProxyService> { +public: + explicit IApplicationProxyService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger); + ~IApplicationProxyService() override; + +private: + Result OpenApplicationProxy(Out<SharedPointer<IApplicationProxy>> out_application_proxy, + ClientProcessId pid, InCopyHandle<Kernel::KProcess> process_handle); + +private: + std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid); + Nvnflinger::Nvnflinger& m_nvnflinger; +}; + +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am/service/audio_controller.cpp b/src/core/hle/service/am/service/audio_controller.cpp new file mode 100644 index 000000000..ad731c7bd --- /dev/null +++ b/src/core/hle/service/am/service/audio_controller.cpp @@ -0,0 +1,69 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/service/audio_controller.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::AM { + +IAudioController::IAudioController(Core::System& system_) + : ServiceFramework{system_, "IAudioController"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, D<&IAudioController::SetExpectedMasterVolume>, "SetExpectedMasterVolume"}, + {1, D<&IAudioController::GetMainAppletExpectedMasterVolume>, "GetMainAppletExpectedMasterVolume"}, + {2, D<&IAudioController::GetLibraryAppletExpectedMasterVolume>, "GetLibraryAppletExpectedMasterVolume"}, + {3, D<&IAudioController::ChangeMainAppletMasterVolume>, "ChangeMainAppletMasterVolume"}, + {4, D<&IAudioController::SetTransparentVolumeRate>, "SetTransparentVolumeRate"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IAudioController::~IAudioController() = default; + +Result IAudioController::SetExpectedMasterVolume(f32 main_applet_volume, + f32 library_applet_volume) { + LOG_DEBUG(Service_AM, "called. main_applet_volume={}, library_applet_volume={}", + main_applet_volume, library_applet_volume); + + // Ensure the volume values remain within the 0-100% range + m_main_applet_volume = std::clamp(main_applet_volume, MinAllowedVolume, MaxAllowedVolume); + m_library_applet_volume = std::clamp(library_applet_volume, MinAllowedVolume, MaxAllowedVolume); + + R_SUCCEED(); +} + +Result IAudioController::GetMainAppletExpectedMasterVolume(Out<f32> out_main_applet_volume) { + LOG_DEBUG(Service_AM, "called. main_applet_volume={}", m_main_applet_volume); + *out_main_applet_volume = m_main_applet_volume; + R_SUCCEED(); +} + +Result IAudioController::GetLibraryAppletExpectedMasterVolume(Out<f32> out_library_applet_volume) { + LOG_DEBUG(Service_AM, "called. library_applet_volume={}", m_library_applet_volume); + *out_library_applet_volume = m_library_applet_volume; + R_SUCCEED(); +} + +Result IAudioController::ChangeMainAppletMasterVolume(f32 volume, s64 fade_time_ns) { + LOG_DEBUG(Service_AM, "called. volume={}, fade_time_ns={}", volume, fade_time_ns); + + m_main_applet_volume = std::clamp(volume, MinAllowedVolume, MaxAllowedVolume); + m_fade_time_ns = std::chrono::nanoseconds{fade_time_ns}; + + R_SUCCEED(); +} + +Result IAudioController::SetTransparentVolumeRate(f32 transparent_volume_rate) { + LOG_DEBUG(Service_AM, "called. transparent_volume_rate={}", transparent_volume_rate); + + // Clamp volume range to 0-100%. + m_transparent_volume_rate = + std::clamp(transparent_volume_rate, MinAllowedVolume, MaxAllowedVolume); + + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/audio_controller.h b/src/core/hle/service/am/service/audio_controller.h new file mode 100644 index 000000000..4b0f3f9ae --- /dev/null +++ b/src/core/hle/service/am/service/audio_controller.h @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IAudioController final : public ServiceFramework<IAudioController> { +public: + explicit IAudioController(Core::System& system_); + ~IAudioController() override; + +private: + Result SetExpectedMasterVolume(f32 main_applet_volume, f32 library_applet_volume); + Result GetMainAppletExpectedMasterVolume(Out<f32> out_main_applet_volume); + Result GetLibraryAppletExpectedMasterVolume(Out<f32> out_library_applet_volume); + Result ChangeMainAppletMasterVolume(f32 volume, s64 fade_time_ns); + Result SetTransparentVolumeRate(f32 transparent_volume_rate); + + static constexpr float MinAllowedVolume = 0.0f; + static constexpr float MaxAllowedVolume = 1.0f; + + float m_main_applet_volume{0.25f}; + float m_library_applet_volume{MaxAllowedVolume}; + float m_transparent_volume_rate{MinAllowedVolume}; + + // Volume transition fade time in nanoseconds. + // e.g. If the main applet volume was 0% and was changed to 50% + // with a fade of 50ns, then over the course of 50ns, + // the volume will gradually fade up to 50% + std::chrono::nanoseconds m_fade_time_ns{0}; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/common_state_getter.cpp b/src/core/hle/service/am/service/common_state_getter.cpp new file mode 100644 index 000000000..12d7e8cb1 --- /dev/null +++ b/src/core/hle/service/am/service/common_state_getter.cpp @@ -0,0 +1,277 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/settings.h" +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/applet.h" +#include "core/hle/service/am/service/common_state_getter.h" +#include "core/hle/service/am/service/lock_accessor.h" +#include "core/hle/service/apm/apm_interface.h" +#include "core/hle/service/cmif_serialization.h" +#include "core/hle/service/pm/pm.h" +#include "core/hle/service/sm/sm.h" +#include "core/hle/service/vi/vi.h" + +namespace Service::AM { + +ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet) + : ServiceFramework{system_, "ICommonStateGetter"}, m_applet{std::move(applet)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, D<&ICommonStateGetter::GetEventHandle>, "GetEventHandle"}, + {1, D<&ICommonStateGetter::ReceiveMessage>, "ReceiveMessage"}, + {2, nullptr, "GetThisAppletKind"}, + {3, nullptr, "AllowToEnterSleep"}, + {4, nullptr, "DisallowToEnterSleep"}, + {5, D<&ICommonStateGetter::GetOperationMode>, "GetOperationMode"}, + {6, D<&ICommonStateGetter::GetPerformanceMode>, "GetPerformanceMode"}, + {7, nullptr, "GetCradleStatus"}, + {8, D<&ICommonStateGetter::GetBootMode>, "GetBootMode"}, + {9, D<&ICommonStateGetter::GetCurrentFocusState>, "GetCurrentFocusState"}, + {10, D<&ICommonStateGetter::RequestToAcquireSleepLock>, "RequestToAcquireSleepLock"}, + {11, nullptr, "ReleaseSleepLock"}, + {12, nullptr, "ReleaseSleepLockTransiently"}, + {13, D<&ICommonStateGetter::GetAcquiredSleepLockEvent>, "GetAcquiredSleepLockEvent"}, + {14, nullptr, "GetWakeupCount"}, + {20, nullptr, "PushToGeneralChannel"}, + {30, nullptr, "GetHomeButtonReaderLockAccessor"}, + {31, D<&ICommonStateGetter::GetReaderLockAccessorEx>, "GetReaderLockAccessorEx"}, + {32, D<&ICommonStateGetter::GetWriterLockAccessorEx>, "GetWriterLockAccessorEx"}, + {40, nullptr, "GetCradleFwVersion"}, + {50, D<&ICommonStateGetter::IsVrModeEnabled>, "IsVrModeEnabled"}, + {51, D<&ICommonStateGetter::SetVrModeEnabled>, "SetVrModeEnabled"}, + {52, D<&ICommonStateGetter::SetLcdBacklighOffEnabled>, "SetLcdBacklighOffEnabled"}, + {53, D<&ICommonStateGetter::BeginVrModeEx>, "BeginVrModeEx"}, + {54, D<&ICommonStateGetter::EndVrModeEx>, "EndVrModeEx"}, + {55, D<&ICommonStateGetter::IsInControllerFirmwareUpdateSection>, "IsInControllerFirmwareUpdateSection"}, + {59, nullptr, "SetVrPositionForDebug"}, + {60, D<&ICommonStateGetter::GetDefaultDisplayResolution>, "GetDefaultDisplayResolution"}, + {61, D<&ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent>, "GetDefaultDisplayResolutionChangeEvent"}, + {62, nullptr, "GetHdcpAuthenticationState"}, + {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"}, + {64, nullptr, "SetTvPowerStateMatchingMode"}, + {65, nullptr, "GetApplicationIdByContentActionName"}, + {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"}, + {67, nullptr, "CancelCpuBoostMode"}, + {68, D<&ICommonStateGetter::GetBuiltInDisplayType>, "GetBuiltInDisplayType"}, + {80, D<&ICommonStateGetter::PerformSystemButtonPressingIfInFocus>, "PerformSystemButtonPressingIfInFocus"}, + {90, nullptr, "SetPerformanceConfigurationChangedNotification"}, + {91, nullptr, "GetCurrentPerformanceConfiguration"}, + {100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"}, + {110, nullptr, "OpenMyGpuErrorHandler"}, + {120, D<&ICommonStateGetter::GetAppletLaunchedHistory>, "GetAppletLaunchedHistory"}, + {200, D<&ICommonStateGetter::GetOperationModeSystemInfo>, "GetOperationModeSystemInfo"}, + {300, D<&ICommonStateGetter::GetSettingsPlatformRegion>, "GetSettingsPlatformRegion"}, + {400, nullptr, "ActivateMigrationService"}, + {401, nullptr, "DeactivateMigrationService"}, + {500, nullptr, "DisableSleepTillShutdown"}, + {501, nullptr, "SuppressDisablingSleepTemporarily"}, + {502, nullptr, "IsSleepEnabled"}, + {503, nullptr, "IsDisablingSleepSuppressed"}, + {900, D<&ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled>, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +ICommonStateGetter::~ICommonStateGetter() = default; + +Result ICommonStateGetter::GetEventHandle(OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_DEBUG(Service_AM, "called"); + *out_event = &m_applet->message_queue.GetMessageReceiveEvent(); + R_SUCCEED(); +} + +Result ICommonStateGetter::ReceiveMessage(Out<AppletMessage> out_applet_message) { + LOG_DEBUG(Service_AM, "called"); + + *out_applet_message = m_applet->message_queue.PopMessage(); + if (*out_applet_message == AppletMessage::None) { + LOG_ERROR(Service_AM, "Tried to pop message but none was available!"); + R_THROW(AM::ResultNoMessages); + } + + R_SUCCEED(); +} + +Result ICommonStateGetter::GetCurrentFocusState(Out<FocusState> out_focus_state) { + LOG_DEBUG(Service_AM, "called"); + + std::scoped_lock lk{m_applet->lock}; + *out_focus_state = m_applet->focus_state; + + R_SUCCEED(); +} + +Result ICommonStateGetter::RequestToAcquireSleepLock() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + // Sleep lock is acquired immediately. + m_applet->sleep_lock_event.Signal(); + R_SUCCEED(); +} + +Result ICommonStateGetter::GetAcquiredSleepLockEvent( + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_WARNING(Service_AM, "called"); + *out_event = m_applet->sleep_lock_event.GetHandle(); + R_SUCCEED(); +} + +Result ICommonStateGetter::GetReaderLockAccessorEx( + Out<SharedPointer<ILockAccessor>> out_lock_accessor, u32 button_type) { + LOG_INFO(Service_AM, "called, button_type={}", button_type); + *out_lock_accessor = std::make_shared<ILockAccessor>(system); + R_SUCCEED(); +} + +Result ICommonStateGetter::GetWriterLockAccessorEx( + Out<SharedPointer<ILockAccessor>> out_lock_accessor, u32 button_type) { + LOG_INFO(Service_AM, "called, button_type={}", button_type); + *out_lock_accessor = std::make_shared<ILockAccessor>(system); + R_SUCCEED(); +} + +Result ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent( + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_DEBUG(Service_AM, "called"); + *out_event = &m_applet->message_queue.GetOperationModeChangedEvent(); + R_SUCCEED(); +} + +Result ICommonStateGetter::GetOperationMode(Out<OperationMode> out_operation_mode) { + const bool use_docked_mode{Settings::IsDockedMode()}; + LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode); + *out_operation_mode = use_docked_mode ? OperationMode::Docked : OperationMode::Handheld; + R_SUCCEED(); +} + +Result ICommonStateGetter::GetPerformanceMode(Out<APM::PerformanceMode> out_performance_mode) { + LOG_DEBUG(Service_AM, "called"); + *out_performance_mode = system.GetAPMController().GetCurrentPerformanceMode(); + R_SUCCEED(); +} + +Result ICommonStateGetter::GetBootMode(Out<PM::SystemBootMode> out_boot_mode) { + LOG_DEBUG(Service_AM, "called"); + *out_boot_mode = Service::PM::SystemBootMode::Normal; + R_SUCCEED(); +} + +Result ICommonStateGetter::IsVrModeEnabled(Out<bool> out_is_vr_mode_enabled) { + LOG_DEBUG(Service_AM, "called"); + + std::scoped_lock lk{m_applet->lock}; + *out_is_vr_mode_enabled = m_applet->vr_mode_enabled; + R_SUCCEED(); +} + +Result ICommonStateGetter::SetVrModeEnabled(bool is_vr_mode_enabled) { + std::scoped_lock lk{m_applet->lock}; + m_applet->vr_mode_enabled = is_vr_mode_enabled; + LOG_WARNING(Service_AM, "VR Mode is {}", m_applet->vr_mode_enabled ? "on" : "off"); + R_SUCCEED(); +} + +Result ICommonStateGetter::SetLcdBacklighOffEnabled(bool is_lcd_backlight_off_enabled) { + LOG_WARNING(Service_AM, "(STUBBED) called. is_lcd_backlight_off_enabled={}", + is_lcd_backlight_off_enabled); + R_SUCCEED(); +} + +Result ICommonStateGetter::BeginVrModeEx() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + std::scoped_lock lk{m_applet->lock}; + m_applet->vr_mode_enabled = true; + R_SUCCEED(); +} + +Result ICommonStateGetter::EndVrModeEx() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + std::scoped_lock lk{m_applet->lock}; + m_applet->vr_mode_enabled = false; + R_SUCCEED(); +} + +Result ICommonStateGetter::IsInControllerFirmwareUpdateSection( + Out<bool> out_is_in_controller_firmware_update_section) { + LOG_INFO(Service_AM, "called"); + *out_is_in_controller_firmware_update_section = false; + R_SUCCEED(); +} + +Result ICommonStateGetter::GetDefaultDisplayResolution(Out<s32> out_width, Out<s32> out_height) { + LOG_DEBUG(Service_AM, "called"); + + if (Settings::IsDockedMode()) { + *out_width = static_cast<u32>(Service::VI::DisplayResolution::DockedWidth); + *out_height = static_cast<u32>(Service::VI::DisplayResolution::DockedHeight); + } else { + *out_width = static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth); + *out_height = static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight); + } + + R_SUCCEED(); +} + +void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called, forwarding to APM:SYS"); + + const auto& sm = system.ServiceManager(); + const auto apm_sys = sm.GetService<APM::APM_Sys>("apm:sys"); + ASSERT(apm_sys != nullptr); + + apm_sys->SetCpuBoostMode(ctx); +} + +Result ICommonStateGetter::GetBuiltInDisplayType(Out<s32> out_display_type) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_display_type = 0; + R_SUCCEED(); +} + +Result ICommonStateGetter::PerformSystemButtonPressingIfInFocus(SystemButtonType type) { + LOG_WARNING(Service_AM, "(STUBBED) called, type={}", type); + R_SUCCEED(); +} + +Result ICommonStateGetter::GetOperationModeSystemInfo(Out<u32> out_operation_mode_system_info) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_operation_mode_system_info = 0; + R_SUCCEED(); +} + +Result ICommonStateGetter::GetAppletLaunchedHistory( + Out<s32> out_count, OutArray<AppletId, BufferAttr_HipcMapAlias> out_applet_ids) { + LOG_INFO(Service_AM, "called"); + + std::shared_ptr<Applet> current_applet = m_applet; + + for (*out_count = 0; + *out_count < static_cast<s32>(out_applet_ids.size()) && current_applet != nullptr; + /* ... */) { + out_applet_ids[(*out_count)++] = current_applet->applet_id; + current_applet = current_applet->caller_applet.lock(); + } + + R_SUCCEED(); +} + +Result ICommonStateGetter::GetSettingsPlatformRegion( + Out<SysPlatformRegion> out_settings_platform_region) { + LOG_INFO(Service_AM, "called"); + *out_settings_platform_region = SysPlatformRegion::Global; + R_SUCCEED(); +} + +Result ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::scoped_lock lk{m_applet->lock}; + m_applet->request_exit_to_library_applet_at_execute_next_program_enabled = true; + + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/common_state_getter.h b/src/core/hle/service/am/service/common_state_getter.h new file mode 100644 index 000000000..5a8dca3d6 --- /dev/null +++ b/src/core/hle/service/am/service/common_state_getter.h @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/am/am_types.h" +#include "core/hle/service/apm/apm_controller.h" +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/pm/pm.h" +#include "core/hle/service/service.h" + +namespace Kernel { +class KReadableEvent; +} + +namespace Service::AM { + +struct Applet; +class ILockAccessor; + +class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { +public: + explicit ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet_); + ~ICommonStateGetter() override; + +private: + Result GetEventHandle(OutCopyHandle<Kernel::KReadableEvent> out_event); + Result ReceiveMessage(Out<AppletMessage> out_applet_message); + Result GetCurrentFocusState(Out<FocusState> out_focus_state); + Result RequestToAcquireSleepLock(); + Result GetAcquiredSleepLockEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); + Result GetReaderLockAccessorEx(Out<SharedPointer<ILockAccessor>> out_lock_accessor, + u32 button_type); + Result GetWriterLockAccessorEx(Out<SharedPointer<ILockAccessor>> out_lock_accessor, + u32 button_type); + Result GetDefaultDisplayResolutionChangeEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); + Result GetOperationMode(Out<OperationMode> out_operation_mode); + Result GetPerformanceMode(Out<APM::PerformanceMode> out_performance_mode); + Result GetBootMode(Out<PM::SystemBootMode> out_boot_mode); + Result IsVrModeEnabled(Out<bool> out_is_vr_mode_enabled); + Result SetVrModeEnabled(bool is_vr_mode_enabled); + Result SetLcdBacklighOffEnabled(bool is_lcd_backlight_off_enabled); + Result BeginVrModeEx(); + Result EndVrModeEx(); + Result IsInControllerFirmwareUpdateSection( + Out<bool> out_is_in_controller_firmware_update_section); + Result GetDefaultDisplayResolution(Out<s32> out_width, Out<s32> out_height); + Result GetBuiltInDisplayType(Out<s32> out_display_type); + Result PerformSystemButtonPressingIfInFocus(SystemButtonType type); + Result GetOperationModeSystemInfo(Out<u32> out_operation_mode_system_info); + Result GetAppletLaunchedHistory(Out<s32> out_count, + OutArray<AppletId, BufferAttr_HipcMapAlias> out_applet_ids); + Result GetSettingsPlatformRegion(Out<SysPlatformRegion> out_settings_platform_region); + Result SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(); + + void SetCpuBoostMode(HLERequestContext& ctx); + + const std::shared_ptr<Applet> m_applet; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/cradle_firmware_updater.cpp b/src/core/hle/service/am/service/cradle_firmware_updater.cpp new file mode 100644 index 000000000..0a8af0858 --- /dev/null +++ b/src/core/hle/service/am/service/cradle_firmware_updater.cpp @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/service/cradle_firmware_updater.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::AM { + +ICradleFirmwareUpdater::ICradleFirmwareUpdater(Core::System& system_) + : ServiceFramework{system_, "ICradleFirmwareUpdater"}, + m_context{system, "ICradleFirmwareUpdater"}, m_cradle_device_info_event{m_context} { + // clang-format off + static const FunctionInfo functions[] = { + {0, D<&ICradleFirmwareUpdater::StartUpdate>, "StartUpdate"}, + {1, D<&ICradleFirmwareUpdater::FinishUpdate>, "FinishUpdate"}, + {2, D<&ICradleFirmwareUpdater::GetCradleDeviceInfo>, "GetCradleDeviceInfo"}, + {3, D<&ICradleFirmwareUpdater::GetCradleDeviceInfoChangeEvent>, "GetCradleDeviceInfoChangeEvent"}, + {4, nullptr, "GetUpdateProgressInfo"}, + {5, nullptr, "GetLastInternalResult"}, + + }; + // clang-format on + + RegisterHandlers(functions); +} + +ICradleFirmwareUpdater::~ICradleFirmwareUpdater() = default; + +Result ICradleFirmwareUpdater::StartUpdate() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_SUCCEED(); +} + +Result ICradleFirmwareUpdater::FinishUpdate() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_SUCCEED(); +} + +Result ICradleFirmwareUpdater::GetCradleDeviceInfo(Out<CradleDeviceInfo> out_cradle_device_info) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_cradle_device_info = {}; + R_SUCCEED(); +} + +Result ICradleFirmwareUpdater::GetCradleDeviceInfoChangeEvent( + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_event = m_cradle_device_info_event.GetHandle(); + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/cradle_firmware_updater.h b/src/core/hle/service/am/service/cradle_firmware_updater.h new file mode 100644 index 000000000..3e803f0ae --- /dev/null +++ b/src/core/hle/service/am/service/cradle_firmware_updater.h @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/os/event.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +struct CradleDeviceInfo { + bool unknown0; + bool unknown1; + bool unknown2; + u64 unknown3; +}; +static_assert(sizeof(CradleDeviceInfo) == 0x10, "CradleDeviceInfo has incorrect size"); + +class ICradleFirmwareUpdater final : public ServiceFramework<ICradleFirmwareUpdater> { +public: + explicit ICradleFirmwareUpdater(Core::System& system_); + ~ICradleFirmwareUpdater() override; + +private: + Result StartUpdate(); + Result FinishUpdate(); + Result GetCradleDeviceInfo(Out<CradleDeviceInfo> out_cradle_device_info); + Result GetCradleDeviceInfoChangeEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); + +private: + KernelHelpers::ServiceContext m_context; + Event m_cradle_device_info_event; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/debug_functions.cpp b/src/core/hle/service/am/service/debug_functions.cpp new file mode 100644 index 000000000..fcac4776d --- /dev/null +++ b/src/core/hle/service/am/service/debug_functions.cpp @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/service/debug_functions.h" + +namespace Service::AM { + +IDebugFunctions::IDebugFunctions(Core::System& system_) + : ServiceFramework{system_, "IDebugFunctions"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "NotifyMessageToHomeMenuForDebug"}, + {1, nullptr, "OpenMainApplication"}, + {10, nullptr, "PerformSystemButtonPressing"}, + {20, nullptr, "InvalidateTransitionLayer"}, + {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"}, + {31, nullptr, "RequestLaunchApplicationByApplicationLaunchInfoForDebug"}, + {40, nullptr, "GetAppletResourceUsageInfo"}, + {50, nullptr, "AddSystemProgramIdAndAppletIdForDebug"}, + {51, nullptr, "AddOperationConfirmedLibraryAppletIdForDebug"}, + {100, nullptr, "SetCpuBoostModeForApplet"}, + {101, nullptr, "CancelCpuBoostModeForApplet"}, + {110, nullptr, "PushToAppletBoundChannelForDebug"}, + {111, nullptr, "TryPopFromAppletBoundChannelForDebug"}, + {120, nullptr, "AlarmSettingNotificationEnableAppEventReserve"}, + {121, nullptr, "AlarmSettingNotificationDisableAppEventReserve"}, + {122, nullptr, "AlarmSettingNotificationPushAppEventNotify"}, + {130, nullptr, "FriendInvitationSetApplicationParameter"}, + {131, nullptr, "FriendInvitationClearApplicationParameter"}, + {132, nullptr, "FriendInvitationPushApplicationParameter"}, + {140, nullptr, "RestrictPowerOperationForSecureLaunchModeForDebug"}, + {200, nullptr, "CreateFloatingLibraryAppletAccepterForDebug"}, + {300, nullptr, "TerminateAllRunningApplicationsForDebug"}, + {900, nullptr, "GetGrcProcessLaunchedSystemEvent"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IDebugFunctions::~IDebugFunctions() = default; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/debug_functions.h b/src/core/hle/service/am/service/debug_functions.h new file mode 100644 index 000000000..d55968743 --- /dev/null +++ b/src/core/hle/service/am/service/debug_functions.h @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IDebugFunctions final : public ServiceFramework<IDebugFunctions> { +public: + explicit IDebugFunctions(Core::System& system_); + ~IDebugFunctions() override; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/display_controller.cpp b/src/core/hle/service/am/service/display_controller.cpp new file mode 100644 index 000000000..249c73dfb --- /dev/null +++ b/src/core/hle/service/am/service/display_controller.cpp @@ -0,0 +1,105 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/result.h" +#include "core/hle/service/am/applet.h" +#include "core/hle/service/am/service/display_controller.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::AM { + +IDisplayController::IDisplayController(Core::System& system_, std::shared_ptr<Applet> applet_) + : ServiceFramework{system_, "IDisplayController"}, applet(std::move(applet_)) { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetLastForegroundCaptureImage"}, + {1, nullptr, "UpdateLastForegroundCaptureImage"}, + {2, nullptr, "GetLastApplicationCaptureImage"}, + {3, nullptr, "GetCallerAppletCaptureImage"}, + {4, nullptr, "UpdateCallerAppletCaptureImage"}, + {5, nullptr, "GetLastForegroundCaptureImageEx"}, + {6, nullptr, "GetLastApplicationCaptureImageEx"}, + {7, D<&IDisplayController::GetCallerAppletCaptureImageEx>, "GetCallerAppletCaptureImageEx"}, + {8, D<&IDisplayController::TakeScreenShotOfOwnLayer>, "TakeScreenShotOfOwnLayer"}, + {9, nullptr, "CopyBetweenCaptureBuffers"}, + {10, nullptr, "AcquireLastApplicationCaptureBuffer"}, + {11, nullptr, "ReleaseLastApplicationCaptureBuffer"}, + {12, nullptr, "AcquireLastForegroundCaptureBuffer"}, + {13, nullptr, "ReleaseLastForegroundCaptureBuffer"}, + {14, nullptr, "AcquireCallerAppletCaptureBuffer"}, + {15, nullptr, "ReleaseCallerAppletCaptureBuffer"}, + {16, nullptr, "AcquireLastApplicationCaptureBufferEx"}, + {17, nullptr, "AcquireLastForegroundCaptureBufferEx"}, + {18, nullptr, "AcquireCallerAppletCaptureBufferEx"}, + {20, D<&IDisplayController::ClearCaptureBuffer>, "ClearCaptureBuffer"}, + {21, nullptr, "ClearAppletTransitionBuffer"}, + {22, D<&IDisplayController::AcquireLastApplicationCaptureSharedBuffer>, "AcquireLastApplicationCaptureSharedBuffer"}, + {23, D<&IDisplayController::ReleaseLastApplicationCaptureSharedBuffer>, "ReleaseLastApplicationCaptureSharedBuffer"}, + {24, D<&IDisplayController::AcquireLastForegroundCaptureSharedBuffer>, "AcquireLastForegroundCaptureSharedBuffer"}, + {25, D<&IDisplayController::ReleaseLastForegroundCaptureSharedBuffer>, "ReleaseLastForegroundCaptureSharedBuffer"}, + {26, D<&IDisplayController::AcquireCallerAppletCaptureSharedBuffer>, "AcquireCallerAppletCaptureSharedBuffer"}, + {27, D<&IDisplayController::ReleaseCallerAppletCaptureSharedBuffer>, "ReleaseCallerAppletCaptureSharedBuffer"}, + {28, nullptr, "TakeScreenShotOfOwnLayerEx"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IDisplayController::~IDisplayController() = default; + +Result IDisplayController::GetCallerAppletCaptureImageEx( + Out<bool> out_was_written, OutBuffer<BufferAttr_HipcMapAlias> out_image_data) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_was_written = true; + R_SUCCEED(); +} + +Result IDisplayController::TakeScreenShotOfOwnLayer(bool unknown0, s32 fbshare_layer_index) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_SUCCEED(); +} + +Result IDisplayController::ClearCaptureBuffer(bool unknown0, s32 fbshare_layer_index, u32 color) { + LOG_WARNING(Service_AM, "(STUBBED) called, unknown0={} fbshare_layer_index={} color={:#x}", + unknown0, fbshare_layer_index, color); + R_SUCCEED(); +} + +Result IDisplayController::AcquireLastForegroundCaptureSharedBuffer( + Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written, + out_fbshare_layer_index)); +} + +Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_SUCCEED(); +} + +Result IDisplayController::AcquireCallerAppletCaptureSharedBuffer( + Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written, + out_fbshare_layer_index)); +} + +Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_SUCCEED(); +} + +Result IDisplayController::AcquireLastApplicationCaptureSharedBuffer( + Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written, + out_fbshare_layer_index)); +} + +Result IDisplayController::ReleaseLastApplicationCaptureSharedBuffer() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/display_controller.h b/src/core/hle/service/am/service/display_controller.h new file mode 100644 index 000000000..406fae21a --- /dev/null +++ b/src/core/hle/service/am/service/display_controller.h @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +struct Applet; + +class IDisplayController final : public ServiceFramework<IDisplayController> { +public: + explicit IDisplayController(Core::System& system_, std::shared_ptr<Applet> applet_); + ~IDisplayController() override; + +private: + Result GetCallerAppletCaptureImageEx(Out<bool> out_was_written, + OutBuffer<BufferAttr_HipcMapAlias> out_image_data); + Result TakeScreenShotOfOwnLayer(bool unknown0, s32 fbshare_layer_index); + Result ClearCaptureBuffer(bool unknown0, s32 fbshare_layer_index, u32 color); + Result AcquireLastForegroundCaptureSharedBuffer(Out<bool> out_was_written, + Out<s32> out_fbshare_layer_index); + Result ReleaseLastForegroundCaptureSharedBuffer(); + Result AcquireCallerAppletCaptureSharedBuffer(Out<bool> out_was_written, + Out<s32> out_fbshare_layer_index); + Result ReleaseCallerAppletCaptureSharedBuffer(); + Result AcquireLastApplicationCaptureSharedBuffer(Out<bool> out_was_written, + Out<s32> out_fbshare_layer_index); + Result ReleaseLastApplicationCaptureSharedBuffer(); + + const std::shared_ptr<Applet> applet; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/global_state_controller.cpp b/src/core/hle/service/am/service/global_state_controller.cpp new file mode 100644 index 000000000..dba5d3613 --- /dev/null +++ b/src/core/hle/service/am/service/global_state_controller.cpp @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/service/cradle_firmware_updater.h" +#include "core/hle/service/am/service/global_state_controller.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::AM { + +IGlobalStateController::IGlobalStateController(Core::System& system_) + : ServiceFramework{system_, "IGlobalStateController"}, + m_context{system_, "IGlobalStateController"}, m_hdcp_authentication_failed_event{m_context} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "RequestToEnterSleep"}, + {1, nullptr, "EnterSleep"}, + {2, nullptr, "StartSleepSequence"}, + {3, nullptr, "StartShutdownSequence"}, + {4, nullptr, "StartRebootSequence"}, + {9, nullptr, "IsAutoPowerDownRequested"}, + {10, D<&IGlobalStateController::LoadAndApplyIdlePolicySettings>, "LoadAndApplyIdlePolicySettings"}, + {11, nullptr, "NotifyCecSettingsChanged"}, + {12, nullptr, "SetDefaultHomeButtonLongPressTime"}, + {13, nullptr, "UpdateDefaultDisplayResolution"}, + {14, D<&IGlobalStateController::ShouldSleepOnBoot>, "ShouldSleepOnBoot"}, + {15, D<&IGlobalStateController::GetHdcpAuthenticationFailedEvent>, "GetHdcpAuthenticationFailedEvent"}, + {30, D<&IGlobalStateController::OpenCradleFirmwareUpdater>, "OpenCradleFirmwareUpdater"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IGlobalStateController::~IGlobalStateController() = default; + +Result IGlobalStateController::LoadAndApplyIdlePolicySettings() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_SUCCEED(); +} + +Result IGlobalStateController::ShouldSleepOnBoot(Out<bool> out_should_sleep_on_boot) { + LOG_INFO(Service_AM, "called"); + *out_should_sleep_on_boot = false; + R_SUCCEED(); +} + +Result IGlobalStateController::GetHdcpAuthenticationFailedEvent( + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_INFO(Service_AM, "called"); + *out_event = m_hdcp_authentication_failed_event.GetHandle(); + R_SUCCEED(); +} + +Result IGlobalStateController::OpenCradleFirmwareUpdater( + Out<SharedPointer<ICradleFirmwareUpdater>> out_cradle_firmware_updater) { + LOG_INFO(Service_AM, "called"); + *out_cradle_firmware_updater = std::make_shared<ICradleFirmwareUpdater>(system); + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/global_state_controller.h b/src/core/hle/service/am/service/global_state_controller.h new file mode 100644 index 000000000..67c753513 --- /dev/null +++ b/src/core/hle/service/am/service/global_state_controller.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/os/event.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class ICradleFirmwareUpdater; + +class IGlobalStateController final : public ServiceFramework<IGlobalStateController> { +public: + explicit IGlobalStateController(Core::System& system_); + ~IGlobalStateController() override; + +private: + Result LoadAndApplyIdlePolicySettings(); + Result ShouldSleepOnBoot(Out<bool> out_should_sleep_on_boot); + Result GetHdcpAuthenticationFailedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); + Result OpenCradleFirmwareUpdater( + Out<SharedPointer<ICradleFirmwareUpdater>> out_cradle_firmware_updater); + + KernelHelpers::ServiceContext m_context; + Event m_hdcp_authentication_failed_event; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/home_menu_functions.cpp b/src/core/hle/service/am/service/home_menu_functions.cpp new file mode 100644 index 000000000..0c4d24b58 --- /dev/null +++ b/src/core/hle/service/am/service/home_menu_functions.cpp @@ -0,0 +1,74 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/result.h" +#include "core/hle/service/am/applet_manager.h" +#include "core/hle/service/am/service/home_menu_functions.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::AM { + +IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Applet> applet) + : ServiceFramework{system_, "IHomeMenuFunctions"}, m_applet{std::move(applet)}, + m_context{system, "IHomeMenuFunctions"}, m_pop_from_general_channel_event{m_context} { + // clang-format off + static const FunctionInfo functions[] = { + {10, D<&IHomeMenuFunctions::RequestToGetForeground>, "RequestToGetForeground"}, + {11, D<&IHomeMenuFunctions::LockForeground>, "LockForeground"}, + {12, D<&IHomeMenuFunctions::UnlockForeground>, "UnlockForeground"}, + {20, nullptr, "PopFromGeneralChannel"}, + {21, D<&IHomeMenuFunctions::GetPopFromGeneralChannelEvent>, "GetPopFromGeneralChannelEvent"}, + {30, nullptr, "GetHomeButtonWriterLockAccessor"}, + {31, nullptr, "GetWriterLockAccessorEx"}, + {40, nullptr, "IsSleepEnabled"}, + {41, D<&IHomeMenuFunctions::IsRebootEnabled>, "IsRebootEnabled"}, + {50, nullptr, "LaunchSystemApplet"}, + {51, nullptr, "LaunchStarter"}, + {100, nullptr, "PopRequestLaunchApplicationForDebug"}, + {110, D<&IHomeMenuFunctions::IsForceTerminateApplicationDisabledForDebug>, "IsForceTerminateApplicationDisabledForDebug"}, + {200, nullptr, "LaunchDevMenu"}, + {1000, nullptr, "SetLastApplicationExitReason"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IHomeMenuFunctions::~IHomeMenuFunctions() = default; + +Result IHomeMenuFunctions::RequestToGetForeground() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_SUCCEED(); +} + +Result IHomeMenuFunctions::LockForeground() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_SUCCEED(); +} + +Result IHomeMenuFunctions::UnlockForeground() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_SUCCEED(); +} + +Result IHomeMenuFunctions::GetPopFromGeneralChannelEvent( + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_INFO(Service_AM, "called"); + *out_event = m_pop_from_general_channel_event.GetHandle(); + R_SUCCEED(); +} + +Result IHomeMenuFunctions::IsRebootEnabled(Out<bool> out_is_reboot_enbaled) { + LOG_INFO(Service_AM, "called"); + *out_is_reboot_enbaled = true; + R_SUCCEED(); +} + +Result IHomeMenuFunctions::IsForceTerminateApplicationDisabledForDebug( + Out<bool> out_is_force_terminate_application_disabled_for_debug) { + LOG_INFO(Service_AM, "called"); + *out_is_force_terminate_application_disabled_for_debug = false; + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/home_menu_functions.h b/src/core/hle/service/am/service/home_menu_functions.h new file mode 100644 index 000000000..caf6fbaab --- /dev/null +++ b/src/core/hle/service/am/service/home_menu_functions.h @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/os/event.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +struct Applet; + +class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { +public: + explicit IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Applet> applet); + ~IHomeMenuFunctions() override; + +private: + Result RequestToGetForeground(); + Result LockForeground(); + Result UnlockForeground(); + Result GetPopFromGeneralChannelEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); + Result IsRebootEnabled(Out<bool> out_is_reboot_enbaled); + Result IsForceTerminateApplicationDisabledForDebug( + Out<bool> out_is_force_terminate_application_disabled_for_debug); + + const std::shared_ptr<Applet> m_applet; + KernelHelpers::ServiceContext m_context; + Event m_pop_from_general_channel_event; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/library_applet_accessor.cpp b/src/core/hle/service/am/service/library_applet_accessor.cpp new file mode 100644 index 000000000..0c2426d4b --- /dev/null +++ b/src/core/hle/service/am/service/library_applet_accessor.cpp @@ -0,0 +1,157 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applet_data_broker.h" +#include "core/hle/service/am/applet_manager.h" +#include "core/hle/service/am/frontend/applets.h" +#include "core/hle/service/am/service/library_applet_accessor.h" +#include "core/hle/service/am/service/storage.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::AM { + +ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_, + std::shared_ptr<AppletDataBroker> broker, + std::shared_ptr<Applet> applet) + : ServiceFramework{system_, "ILibraryAppletAccessor"}, m_broker{std::move(broker)}, + m_applet{std::move(applet)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, D<&ILibraryAppletAccessor::GetAppletStateChangedEvent>, "GetAppletStateChangedEvent"}, + {1, D<&ILibraryAppletAccessor::IsCompleted>, "IsCompleted"}, + {10, D<&ILibraryAppletAccessor::Start>, "Start"}, + {20, D<&ILibraryAppletAccessor::RequestExit>, "RequestExit"}, + {25, D<&ILibraryAppletAccessor::Terminate>, "Terminate"}, + {30, D<&ILibraryAppletAccessor::GetResult>, "GetResult"}, + {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, + {60, D<&ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero>, "PresetLibraryAppletGpuTimeSliceZero"}, + {100, D<&ILibraryAppletAccessor::PushInData>, "PushInData"}, + {101, D<&ILibraryAppletAccessor::PopOutData>, "PopOutData"}, + {102, nullptr, "PushExtraStorage"}, + {103, D<&ILibraryAppletAccessor::PushInteractiveInData>, "PushInteractiveInData"}, + {104, D<&ILibraryAppletAccessor::PopInteractiveOutData>, "PopInteractiveOutData"}, + {105, D<&ILibraryAppletAccessor::GetPopOutDataEvent>, "GetPopOutDataEvent"}, + {106, D<&ILibraryAppletAccessor::GetPopInteractiveOutDataEvent>, "GetPopInteractiveOutDataEvent"}, + {110, nullptr, "NeedsToExitProcess"}, + {120, nullptr, "GetLibraryAppletInfo"}, + {150, nullptr, "RequestForAppletToGetForeground"}, + {160, D<&ILibraryAppletAccessor::GetIndirectLayerConsumerHandle>, "GetIndirectLayerConsumerHandle"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +ILibraryAppletAccessor::~ILibraryAppletAccessor() = default; + +Result ILibraryAppletAccessor::GetAppletStateChangedEvent( + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_DEBUG(Service_AM, "called"); + *out_event = m_broker->GetStateChangedEvent().GetHandle(); + R_SUCCEED(); +} + +Result ILibraryAppletAccessor::IsCompleted(Out<bool> out_is_completed) { + LOG_DEBUG(Service_AM, "called"); + *out_is_completed = m_broker->IsCompleted(); + R_SUCCEED(); +} + +Result ILibraryAppletAccessor::GetResult(Out<Result> out_result) { + LOG_DEBUG(Service_AM, "called"); + *out_result = m_applet->terminate_result; + R_SUCCEED(); +} + +Result ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero() { + LOG_INFO(Service_AM, "(STUBBED) called"); + R_SUCCEED(); +} + +Result ILibraryAppletAccessor::Start() { + LOG_DEBUG(Service_AM, "called"); + m_applet->process->Run(); + FrontendExecute(); + R_SUCCEED(); +} + +Result ILibraryAppletAccessor::RequestExit() { + LOG_DEBUG(Service_AM, "called"); + m_applet->message_queue.RequestExit(); + FrontendRequestExit(); + R_SUCCEED(); +} + +Result ILibraryAppletAccessor::Terminate() { + LOG_DEBUG(Service_AM, "called"); + m_applet->process->Terminate(); + FrontendRequestExit(); + R_SUCCEED(); +} + +Result ILibraryAppletAccessor::PushInData(SharedPointer<IStorage> storage) { + LOG_DEBUG(Service_AM, "called"); + m_broker->GetInData().Push(storage); + R_SUCCEED(); +} + +Result ILibraryAppletAccessor::PopOutData(Out<SharedPointer<IStorage>> out_storage) { + LOG_DEBUG(Service_AM, "called"); + R_RETURN(m_broker->GetOutData().Pop(out_storage.Get())); +} + +Result ILibraryAppletAccessor::PushInteractiveInData(SharedPointer<IStorage> storage) { + LOG_DEBUG(Service_AM, "called"); + m_broker->GetInteractiveInData().Push(storage); + FrontendExecuteInteractive(); + R_SUCCEED(); +} + +Result ILibraryAppletAccessor::PopInteractiveOutData(Out<SharedPointer<IStorage>> out_storage) { + LOG_DEBUG(Service_AM, "called"); + R_RETURN(m_broker->GetInteractiveOutData().Pop(out_storage.Get())); +} + +Result ILibraryAppletAccessor::GetPopOutDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_DEBUG(Service_AM, "called"); + *out_event = m_broker->GetOutData().GetEvent(); + R_SUCCEED(); +} + +Result ILibraryAppletAccessor::GetPopInteractiveOutDataEvent( + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_DEBUG(Service_AM, "called"); + *out_event = m_broker->GetInteractiveOutData().GetEvent(); + R_SUCCEED(); +} + +Result ILibraryAppletAccessor::GetIndirectLayerConsumerHandle(Out<u64> out_handle) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + // We require a non-zero handle to be valid. Using 0xdeadbeef allows us to trace if this is + // actually used anywhere + *out_handle = 0xdeadbeef; + R_SUCCEED(); +} + +void ILibraryAppletAccessor::FrontendExecute() { + if (m_applet->frontend) { + m_applet->frontend->Initialize(); + m_applet->frontend->Execute(); + } +} + +void ILibraryAppletAccessor::FrontendExecuteInteractive() { + if (m_applet->frontend) { + m_applet->frontend->ExecuteInteractive(); + m_applet->frontend->Execute(); + } +} + +void ILibraryAppletAccessor::FrontendRequestExit() { + if (m_applet->frontend) { + m_applet->frontend->RequestExit(); + } +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/library_applet_accessor.h b/src/core/hle/service/am/service/library_applet_accessor.h new file mode 100644 index 000000000..97d3b6c8a --- /dev/null +++ b/src/core/hle/service/am/service/library_applet_accessor.h @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class AppletDataBroker; +struct Applet; +class IStorage; + +class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { +public: + explicit ILibraryAppletAccessor(Core::System& system_, std::shared_ptr<AppletDataBroker> broker, + std::shared_ptr<Applet> applet); + ~ILibraryAppletAccessor(); + +private: + Result GetAppletStateChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); + Result IsCompleted(Out<bool> out_is_completed); + Result GetResult(Out<Result> out_result); + Result PresetLibraryAppletGpuTimeSliceZero(); + Result Start(); + Result RequestExit(); + Result Terminate(); + Result PushInData(SharedPointer<IStorage> storage); + Result PopOutData(Out<SharedPointer<IStorage>> out_storage); + Result PushInteractiveInData(SharedPointer<IStorage> storage); + Result PopInteractiveOutData(Out<SharedPointer<IStorage>> out_storage); + Result GetPopOutDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); + Result GetPopInteractiveOutDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); + Result GetIndirectLayerConsumerHandle(Out<u64> out_handle); + + void FrontendExecute(); + void FrontendExecuteInteractive(); + void FrontendRequestExit(); + + const std::shared_ptr<AppletDataBroker> m_broker; + const std::shared_ptr<Applet> m_applet; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/library_applet_creator.cpp b/src/core/hle/service/am/service/library_applet_creator.cpp new file mode 100644 index 000000000..166637d60 --- /dev/null +++ b/src/core/hle/service/am/service/library_applet_creator.cpp @@ -0,0 +1,268 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/settings.h" +#include "core/hle/kernel/k_transfer_memory.h" +#include "core/hle/service/am/applet_data_broker.h" +#include "core/hle/service/am/applet_manager.h" +#include "core/hle/service/am/frontend/applets.h" +#include "core/hle/service/am/library_applet_storage.h" +#include "core/hle/service/am/service/library_applet_accessor.h" +#include "core/hle/service/am/service/library_applet_creator.h" +#include "core/hle/service/am/service/storage.h" +#include "core/hle/service/cmif_serialization.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::AM { + +namespace { + +bool ShouldCreateGuestApplet(AppletId applet_id) { +#define X(Name, name) \ + if (applet_id == AppletId::Name && \ + Settings::values.name##_applet_mode.GetValue() != Settings::AppletMode::LLE) { \ + return false; \ + } + + X(Cabinet, cabinet) + X(Controller, controller) + X(DataErase, data_erase) + X(Error, error) + X(NetConnect, net_connect) + X(ProfileSelect, player_select) + X(SoftwareKeyboard, swkbd) + X(MiiEdit, mii_edit) + X(Web, web) + X(Shop, shop) + X(PhotoViewer, photo_viewer) + X(OfflineWeb, offline_web) + X(LoginShare, login_share) + X(WebAuth, wifi_web_auth) + X(MyPage, my_page) + +#undef X + + return true; +} + +AppletProgramId AppletIdToProgramId(AppletId applet_id) { + switch (applet_id) { + case AppletId::OverlayDisplay: + return AppletProgramId::OverlayDisplay; + case AppletId::QLaunch: + return AppletProgramId::QLaunch; + case AppletId::Starter: + return AppletProgramId::Starter; + case AppletId::Auth: + return AppletProgramId::Auth; + case AppletId::Cabinet: + return AppletProgramId::Cabinet; + case AppletId::Controller: + return AppletProgramId::Controller; + case AppletId::DataErase: + return AppletProgramId::DataErase; + case AppletId::Error: + return AppletProgramId::Error; + case AppletId::NetConnect: + return AppletProgramId::NetConnect; + case AppletId::ProfileSelect: + return AppletProgramId::ProfileSelect; + case AppletId::SoftwareKeyboard: + return AppletProgramId::SoftwareKeyboard; + case AppletId::MiiEdit: + return AppletProgramId::MiiEdit; + case AppletId::Web: + return AppletProgramId::Web; + case AppletId::Shop: + return AppletProgramId::Shop; + case AppletId::PhotoViewer: + return AppletProgramId::PhotoViewer; + case AppletId::Settings: + return AppletProgramId::Settings; + case AppletId::OfflineWeb: + return AppletProgramId::OfflineWeb; + case AppletId::LoginShare: + return AppletProgramId::LoginShare; + case AppletId::WebAuth: + return AppletProgramId::WebAuth; + case AppletId::MyPage: + return AppletProgramId::MyPage; + default: + return static_cast<AppletProgramId>(0); + } +} + +std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system, + std::shared_ptr<Applet> caller_applet, + AppletId applet_id, + LibraryAppletMode mode) { + const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id)); + if (program_id == 0) { + // Unknown applet + return {}; + } + + // TODO: enable other versions of applets + enum : u8 { + Firmware1400 = 14, + Firmware1500 = 15, + Firmware1600 = 16, + Firmware1700 = 17, + }; + + auto process = std::make_unique<Process>(system); + if (!process->Initialize(program_id, Firmware1400, Firmware1700)) { + // Couldn't initialize the guest process + return {}; + } + + const auto applet = std::make_shared<Applet>(system, std::move(process)); + applet->program_id = program_id; + applet->applet_id = applet_id; + applet->type = AppletType::LibraryApplet; + applet->library_applet_mode = mode; + + // Set focus state + switch (mode) { + case LibraryAppletMode::AllForeground: + case LibraryAppletMode::NoUi: + case LibraryAppletMode::PartialForeground: + case LibraryAppletMode::PartialForegroundIndirectDisplay: + applet->hid_registration.EnableAppletToGetInput(true); + applet->focus_state = FocusState::InFocus; + applet->message_queue.PushMessage(AppletMessage::ChangeIntoForeground); + break; + case LibraryAppletMode::AllForegroundInitiallyHidden: + applet->hid_registration.EnableAppletToGetInput(false); + applet->focus_state = FocusState::NotInFocus; + applet->system_buffer_manager.SetWindowVisibility(false); + applet->message_queue.PushMessage(AppletMessage::ChangeIntoBackground); + break; + } + + auto broker = std::make_shared<AppletDataBroker>(system); + applet->caller_applet = caller_applet; + applet->caller_applet_broker = broker; + + system.GetAppletManager().InsertApplet(applet); + + return std::make_shared<ILibraryAppletAccessor>(system, broker, applet); +} + +std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& system, + std::shared_ptr<Applet> caller_applet, + AppletId applet_id, + LibraryAppletMode mode) { + const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id)); + + auto process = std::make_unique<Process>(system); + auto applet = std::make_shared<Applet>(system, std::move(process)); + applet->program_id = program_id; + applet->applet_id = applet_id; + applet->type = AppletType::LibraryApplet; + applet->library_applet_mode = mode; + + auto storage = std::make_shared<AppletDataBroker>(system); + applet->caller_applet = caller_applet; + applet->caller_applet_broker = storage; + applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode); + + return std::make_shared<ILibraryAppletAccessor>(system, storage, applet); +} + +} // namespace + +ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet) + : ServiceFramework{system_, "ILibraryAppletCreator"}, m_applet{std::move(applet)} { + static const FunctionInfo functions[] = { + {0, D<&ILibraryAppletCreator::CreateLibraryApplet>, "CreateLibraryApplet"}, + {1, nullptr, "TerminateAllLibraryApplets"}, + {2, nullptr, "AreAnyLibraryAppletsLeft"}, + {10, D<&ILibraryAppletCreator::CreateStorage>, "CreateStorage"}, + {11, D<&ILibraryAppletCreator::CreateTransferMemoryStorage>, "CreateTransferMemoryStorage"}, + {12, D<&ILibraryAppletCreator::CreateHandleStorage>, "CreateHandleStorage"}, + }; + RegisterHandlers(functions); +} + +ILibraryAppletCreator::~ILibraryAppletCreator() = default; + +Result ILibraryAppletCreator::CreateLibraryApplet( + Out<SharedPointer<ILibraryAppletAccessor>> out_library_applet_accessor, AppletId applet_id, + LibraryAppletMode library_applet_mode) { + LOG_DEBUG(Service_AM, "called with applet_id={} applet_mode={}", applet_id, + library_applet_mode); + + std::shared_ptr<ILibraryAppletAccessor> library_applet; + if (ShouldCreateGuestApplet(applet_id)) { + library_applet = CreateGuestApplet(system, m_applet, applet_id, library_applet_mode); + } + if (!library_applet) { + library_applet = CreateFrontendApplet(system, m_applet, applet_id, library_applet_mode); + } + if (!library_applet) { + LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); + R_THROW(ResultUnknown); + } + + // Applet is created, can now be launched. + m_applet->library_applet_launchable_event.Signal(); + *out_library_applet_accessor = library_applet; + R_SUCCEED(); +} + +Result ILibraryAppletCreator::CreateStorage(Out<SharedPointer<IStorage>> out_storage, s64 size) { + LOG_DEBUG(Service_AM, "called, size={}", size); + + if (size <= 0) { + LOG_ERROR(Service_AM, "size is less than or equal to 0"); + R_THROW(ResultUnknown); + } + + *out_storage = std::make_shared<IStorage>(system, AM::CreateStorage(std::vector<u8>(size))); + R_SUCCEED(); +} + +Result ILibraryAppletCreator::CreateTransferMemoryStorage( + Out<SharedPointer<IStorage>> out_storage, bool is_writable, s64 size, + InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle) { + LOG_DEBUG(Service_AM, "called, is_writable={} size={}", is_writable, size); + + if (size <= 0) { + LOG_ERROR(Service_AM, "size is less than or equal to 0"); + R_THROW(ResultUnknown); + } + + if (!transfer_memory_handle) { + LOG_ERROR(Service_AM, "transfer_memory_handle is null"); + R_THROW(ResultUnknown); + } + + *out_storage = std::make_shared<IStorage>( + system, AM::CreateTransferMemoryStorage(transfer_memory_handle->GetOwner()->GetMemory(), + transfer_memory_handle.Get(), is_writable, size)); + R_SUCCEED(); +} + +Result ILibraryAppletCreator::CreateHandleStorage( + Out<SharedPointer<IStorage>> out_storage, s64 size, + InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle) { + LOG_DEBUG(Service_AM, "called, size={}", size); + + if (size <= 0) { + LOG_ERROR(Service_AM, "size is less than or equal to 0"); + R_THROW(ResultUnknown); + } + + if (!transfer_memory_handle) { + LOG_ERROR(Service_AM, "transfer_memory_handle is null"); + R_THROW(ResultUnknown); + } + + *out_storage = std::make_shared<IStorage>( + system, AM::CreateHandleStorage(transfer_memory_handle->GetOwner()->GetMemory(), + transfer_memory_handle.Get(), size)); + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/library_applet_creator.h b/src/core/hle/service/am/service/library_applet_creator.h new file mode 100644 index 000000000..fe6d40eb3 --- /dev/null +++ b/src/core/hle/service/am/service/library_applet_creator.h @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/am/am_types.h" +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +struct Applet; +class ILibraryAppletAccessor; +class IStorage; + +class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { +public: + explicit ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet); + ~ILibraryAppletCreator() override; + +private: + Result CreateLibraryApplet( + Out<SharedPointer<ILibraryAppletAccessor>> out_library_applet_accessor, AppletId applet_id, + LibraryAppletMode library_applet_mode); + Result CreateStorage(Out<SharedPointer<IStorage>> out_storage, s64 size); + Result CreateTransferMemoryStorage( + Out<SharedPointer<IStorage>> out_storage, bool is_writable, s64 size, + InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle); + Result CreateHandleStorage(Out<SharedPointer<IStorage>> out_storage, s64 size, + InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle); + + const std::shared_ptr<Applet> m_applet; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/library_applet_proxy.cpp b/src/core/hle/service/am/service/library_applet_proxy.cpp new file mode 100644 index 000000000..bcb44a71c --- /dev/null +++ b/src/core/hle/service/am/service/library_applet_proxy.cpp @@ -0,0 +1,134 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/service/applet_common_functions.h" +#include "core/hle/service/am/service/audio_controller.h" +#include "core/hle/service/am/service/common_state_getter.h" +#include "core/hle/service/am/service/debug_functions.h" +#include "core/hle/service/am/service/display_controller.h" +#include "core/hle/service/am/service/global_state_controller.h" +#include "core/hle/service/am/service/home_menu_functions.h" +#include "core/hle/service/am/service/library_applet_creator.h" +#include "core/hle/service/am/service/library_applet_proxy.h" +#include "core/hle/service/am/service/library_applet_self_accessor.h" +#include "core/hle/service/am/service/process_winding_controller.h" +#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" + +namespace Service::AM { + +ILibraryAppletProxy::ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet, + Kernel::KProcess* process, + Nvnflinger::Nvnflinger& nvnflinger) + : ServiceFramework{system_, "ILibraryAppletProxy"}, + m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, D<&ILibraryAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"}, + {1, D<&ILibraryAppletProxy::GetSelfController>, "GetSelfController"}, + {2, D<&ILibraryAppletProxy::GetWindowController>, "GetWindowController"}, + {3, D<&ILibraryAppletProxy::GetAudioController>, "GetAudioController"}, + {4, D<&ILibraryAppletProxy::GetDisplayController>, "GetDisplayController"}, + {10, D<&ILibraryAppletProxy::GetProcessWindingController>, "GetProcessWindingController"}, + {11, D<&ILibraryAppletProxy::GetLibraryAppletCreator>, "GetLibraryAppletCreator"}, + {20, D<&ILibraryAppletProxy::OpenLibraryAppletSelfAccessor>, "OpenLibraryAppletSelfAccessor"}, + {21, D<&ILibraryAppletProxy::GetAppletCommonFunctions>, "GetAppletCommonFunctions"}, + {22, D<&ILibraryAppletProxy::GetHomeMenuFunctions>, "GetHomeMenuFunctions"}, + {23, D<&ILibraryAppletProxy::GetGlobalStateController>, "GetGlobalStateController"}, + {1000, D<&ILibraryAppletProxy::GetDebugFunctions>, "GetDebugFunctions"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +ILibraryAppletProxy::~ILibraryAppletProxy() = default; + +Result ILibraryAppletProxy::GetAudioController( + Out<SharedPointer<IAudioController>> out_audio_controller) { + LOG_DEBUG(Service_AM, "called"); + *out_audio_controller = std::make_shared<IAudioController>(system); + R_SUCCEED(); +} + +Result ILibraryAppletProxy::GetDisplayController( + Out<SharedPointer<IDisplayController>> out_display_controller) { + LOG_DEBUG(Service_AM, "called"); + *out_display_controller = std::make_shared<IDisplayController>(system, m_applet); + R_SUCCEED(); +} + +Result ILibraryAppletProxy::GetProcessWindingController( + Out<SharedPointer<IProcessWindingController>> out_process_winding_controller) { + LOG_DEBUG(Service_AM, "called"); + *out_process_winding_controller = std::make_shared<IProcessWindingController>(system, m_applet); + R_SUCCEED(); +} + +Result ILibraryAppletProxy::GetDebugFunctions( + Out<SharedPointer<IDebugFunctions>> out_debug_functions) { + LOG_DEBUG(Service_AM, "called"); + *out_debug_functions = std::make_shared<IDebugFunctions>(system); + R_SUCCEED(); +} + +Result ILibraryAppletProxy::GetWindowController( + Out<SharedPointer<IWindowController>> out_window_controller) { + LOG_DEBUG(Service_AM, "called"); + *out_window_controller = std::make_shared<IWindowController>(system, m_applet); + R_SUCCEED(); +} + +Result ILibraryAppletProxy::GetSelfController( + Out<SharedPointer<ISelfController>> out_self_controller) { + LOG_DEBUG(Service_AM, "called"); + *out_self_controller = + std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger); + R_SUCCEED(); +} + +Result ILibraryAppletProxy::GetCommonStateGetter( + Out<SharedPointer<ICommonStateGetter>> out_common_state_getter) { + LOG_DEBUG(Service_AM, "called"); + *out_common_state_getter = std::make_shared<ICommonStateGetter>(system, m_applet); + R_SUCCEED(); +} + +Result ILibraryAppletProxy::GetLibraryAppletCreator( + Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) { + LOG_DEBUG(Service_AM, "called"); + *out_library_applet_creator = std::make_shared<ILibraryAppletCreator>(system, m_applet); + R_SUCCEED(); +} + +Result ILibraryAppletProxy::OpenLibraryAppletSelfAccessor( + Out<SharedPointer<ILibraryAppletSelfAccessor>> out_library_applet_self_accessor) { + LOG_DEBUG(Service_AM, "called"); + *out_library_applet_self_accessor = + std::make_shared<ILibraryAppletSelfAccessor>(system, m_applet); + R_SUCCEED(); +} + +Result ILibraryAppletProxy::GetAppletCommonFunctions( + Out<SharedPointer<IAppletCommonFunctions>> out_applet_common_functions) { + LOG_DEBUG(Service_AM, "called"); + *out_applet_common_functions = std::make_shared<IAppletCommonFunctions>(system, m_applet); + R_SUCCEED(); +} + +Result ILibraryAppletProxy::GetHomeMenuFunctions( + Out<SharedPointer<IHomeMenuFunctions>> out_home_menu_functions) { + LOG_DEBUG(Service_AM, "called"); + *out_home_menu_functions = std::make_shared<IHomeMenuFunctions>(system, m_applet); + R_SUCCEED(); +} + +Result ILibraryAppletProxy::GetGlobalStateController( + Out<SharedPointer<IGlobalStateController>> out_global_state_controller) { + LOG_DEBUG(Service_AM, "called"); + *out_global_state_controller = std::make_shared<IGlobalStateController>(system); + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/library_applet_proxy.h b/src/core/hle/service/am/service/library_applet_proxy.h new file mode 100644 index 000000000..23e64e295 --- /dev/null +++ b/src/core/hle/service/am/service/library_applet_proxy.h @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +struct Applet; +class IAppletCommonFunctions; +class IAudioController; +class ICommonStateGetter; +class IDebugFunctions; +class IDisplayController; +class IHomeMenuFunctions; +class IGlobalStateController; +class ILibraryAppletCreator; +class ILibraryAppletSelfAccessor; +class IProcessWindingController; +class ISelfController; +class IWindowController; + +class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { +public: + explicit ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet, + Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger); + ~ILibraryAppletProxy(); + +private: + Result GetAudioController(Out<SharedPointer<IAudioController>> out_audio_controller); + Result GetDisplayController(Out<SharedPointer<IDisplayController>> out_display_controller); + Result GetProcessWindingController( + Out<SharedPointer<IProcessWindingController>> out_process_winding_controller); + Result GetDebugFunctions(Out<SharedPointer<IDebugFunctions>> out_debug_functions); + Result GetWindowController(Out<SharedPointer<IWindowController>> out_window_controller); + Result GetSelfController(Out<SharedPointer<ISelfController>> out_self_controller); + Result GetCommonStateGetter(Out<SharedPointer<ICommonStateGetter>> out_common_state_getter); + Result GetLibraryAppletCreator( + Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator); + Result OpenLibraryAppletSelfAccessor( + Out<SharedPointer<ILibraryAppletSelfAccessor>> out_library_applet_self_accessor); + Result GetAppletCommonFunctions( + Out<SharedPointer<IAppletCommonFunctions>> out_applet_common_functions); + Result GetHomeMenuFunctions(Out<SharedPointer<IHomeMenuFunctions>> out_home_menu_functions); + Result GetGlobalStateController( + Out<SharedPointer<IGlobalStateController>> out_global_state_controller); + + Nvnflinger::Nvnflinger& m_nvnflinger; + Kernel::KProcess* const m_process; + const std::shared_ptr<Applet> m_applet; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/library_applet_self_accessor.cpp b/src/core/hle/service/am/service/library_applet_self_accessor.cpp new file mode 100644 index 000000000..7a3a86e88 --- /dev/null +++ b/src/core/hle/service/am/service/library_applet_self_accessor.cpp @@ -0,0 +1,322 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core_timing.h" +#include "core/file_sys/control_metadata.h" +#include "core/file_sys/patch_manager.h" +#include "core/file_sys/registered_cache.h" +#include "core/hle/service/acc/profile_manager.h" +#include "core/hle/service/am/applet_data_broker.h" +#include "core/hle/service/am/applet_manager.h" +#include "core/hle/service/am/frontend/applets.h" +#include "core/hle/service/am/service/library_applet_self_accessor.h" +#include "core/hle/service/am/service/storage.h" +#include "core/hle/service/cmif_serialization.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/glue/glue_manager.h" +#include "core/hle/service/ns/ns.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::AM { + +namespace { + +AppletIdentityInfo GetCallerIdentity(Applet& applet) { + if (const auto caller_applet = applet.caller_applet.lock(); caller_applet) { + // TODO: is this actually the application ID? + return { + .applet_id = caller_applet->applet_id, + .application_id = caller_applet->program_id, + }; + } else { + return { + .applet_id = AppletId::QLaunch, + .application_id = 0x0100000000001000ull, + }; + } +} + +} // namespace + +ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_, + std::shared_ptr<Applet> applet) + : ServiceFramework{system_, "ILibraryAppletSelfAccessor"}, m_applet{std::move(applet)}, + m_broker{m_applet->caller_applet_broker} { + // clang-format off + static const FunctionInfo functions[] = { + {0, D<&ILibraryAppletSelfAccessor::PopInData>, "PopInData"}, + {1, D<&ILibraryAppletSelfAccessor::PushOutData>, "PushOutData"}, + {2, D<&ILibraryAppletSelfAccessor::PopInteractiveInData>, "PopInteractiveInData"}, + {3, D<&ILibraryAppletSelfAccessor::PushInteractiveOutData>, "PushInteractiveOutData"}, + {5, D<&ILibraryAppletSelfAccessor::GetPopInDataEvent>, "GetPopInDataEvent"}, + {6, D<&ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent>, "GetPopInteractiveInDataEvent"}, + {10, D<&ILibraryAppletSelfAccessor::ExitProcessAndReturn>, "ExitProcessAndReturn"}, + {11, D<&ILibraryAppletSelfAccessor::GetLibraryAppletInfo>, "GetLibraryAppletInfo"}, + {12, D<&ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo>, "GetMainAppletIdentityInfo"}, + {13, D<&ILibraryAppletSelfAccessor::CanUseApplicationCore>, "CanUseApplicationCore"}, + {14, D<&ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo>, "GetCallerAppletIdentityInfo"}, + {15, D<&ILibraryAppletSelfAccessor::GetMainAppletApplicationControlProperty>, "GetMainAppletApplicationControlProperty"}, + {16, D<&ILibraryAppletSelfAccessor::GetMainAppletStorageId>, "GetMainAppletStorageId"}, + {17, D<&ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfoStack>, "GetCallerAppletIdentityInfoStack"}, + {18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"}, + {19, D<&ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout>, "GetDesirableKeyboardLayout"}, + {20, nullptr, "PopExtraStorage"}, + {25, nullptr, "GetPopExtraStorageEvent"}, + {30, nullptr, "UnpopInData"}, + {31, nullptr, "UnpopExtraStorage"}, + {40, nullptr, "GetIndirectLayerProducerHandle"}, + {50, D<&ILibraryAppletSelfAccessor::ReportVisibleError>, "ReportVisibleError"}, + {51, D<&ILibraryAppletSelfAccessor::ReportVisibleErrorWithErrorContext>, "ReportVisibleErrorWithErrorContext"}, + {60, D<&ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage>, "GetMainAppletApplicationDesiredLanguage"}, + {70, D<&ILibraryAppletSelfAccessor::GetCurrentApplicationId>, "GetCurrentApplicationId"}, + {80, nullptr, "RequestExitToSelf"}, + {90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"}, + {100, nullptr, "CreateGameMovieTrimmer"}, + {101, nullptr, "ReserveResourceForMovieOperation"}, + {102, nullptr, "UnreserveResourceForMovieOperation"}, + {110, D<&ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers>, "GetMainAppletAvailableUsers"}, + {120, nullptr, "GetLaunchStorageInfoForDebug"}, + {130, nullptr, "GetGpuErrorDetectedSystemEvent"}, + {140, nullptr, "SetApplicationMemoryReservation"}, + {150, D<&ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually>, "ShouldSetGpuTimeSliceManually"}, + {160, D<&ILibraryAppletSelfAccessor::Cmd160>, "Cmd160"}, + }; + // clang-format on + RegisterHandlers(functions); +} + +ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default; + +Result ILibraryAppletSelfAccessor::PopInData(Out<SharedPointer<IStorage>> out_storage) { + LOG_INFO(Service_AM, "called"); + R_RETURN(m_broker->GetInData().Pop(out_storage)); +} + +Result ILibraryAppletSelfAccessor::PushOutData(SharedPointer<IStorage> storage) { + LOG_INFO(Service_AM, "called"); + m_broker->GetOutData().Push(storage); + R_SUCCEED(); +} + +Result ILibraryAppletSelfAccessor::PopInteractiveInData(Out<SharedPointer<IStorage>> out_storage) { + LOG_INFO(Service_AM, "called"); + R_RETURN(m_broker->GetInteractiveInData().Pop(out_storage)); +} + +Result ILibraryAppletSelfAccessor::PushInteractiveOutData(SharedPointer<IStorage> storage) { + LOG_INFO(Service_AM, "called"); + m_broker->GetInteractiveOutData().Push(storage); + R_SUCCEED(); +} + +Result ILibraryAppletSelfAccessor::GetPopInDataEvent( + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_INFO(Service_AM, "called"); + *out_event = m_broker->GetInData().GetEvent(); + R_SUCCEED(); +} + +Result ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent( + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_INFO(Service_AM, "called"); + *out_event = m_broker->GetInteractiveInData().GetEvent(); + R_SUCCEED(); +} + +Result ILibraryAppletSelfAccessor::GetLibraryAppletInfo( + Out<LibraryAppletInfo> out_library_applet_info) { + LOG_INFO(Service_AM, "called"); + *out_library_applet_info = { + .applet_id = m_applet->applet_id, + .library_applet_mode = m_applet->library_applet_mode, + }; + R_SUCCEED(); +} + +Result ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo( + Out<AppletIdentityInfo> out_identity_info) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_identity_info = { + .applet_id = AppletId::QLaunch, + .application_id = 0x0100000000001000ull, + }; + R_SUCCEED(); +} + +Result ILibraryAppletSelfAccessor::CanUseApplicationCore(Out<bool> out_can_use_application_core) { + // TODO: This appears to read the NPDM from state and check the core mask of the applet. + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_can_use_application_core = false; + R_SUCCEED(); +} + +Result ILibraryAppletSelfAccessor::GetMainAppletApplicationControlProperty( + OutLargeData<std::array<u8, 0x4000>, BufferAttr_HipcMapAlias> out_nacp) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + // TODO: this should be the main applet, not the caller applet + const auto application = GetCallerIdentity(*m_applet); + std::vector<u8> nacp; + const auto result = + system.GetARPManager().GetControlProperty(&nacp, application.application_id); + + if (R_SUCCEEDED(result)) { + std::memcpy(out_nacp->data(), nacp.data(), std::min(nacp.size(), out_nacp->size())); + } + + R_RETURN(result); +} + +Result ILibraryAppletSelfAccessor::GetMainAppletStorageId(Out<FileSys::StorageId> out_storage_id) { + LOG_INFO(Service_AM, "(STUBBED) called"); + *out_storage_id = FileSys::StorageId::NandUser; + R_SUCCEED(); +} + +Result ILibraryAppletSelfAccessor::ExitProcessAndReturn() { + LOG_INFO(Service_AM, "called"); + system.GetAppletManager().TerminateAndRemoveApplet(m_applet->aruid); + m_broker->SignalCompletion(); + R_SUCCEED(); +} + +Result ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo( + Out<AppletIdentityInfo> out_identity_info) { + LOG_INFO(Service_AM, "called"); + *out_identity_info = GetCallerIdentity(*m_applet); + R_SUCCEED(); +} + +Result ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfoStack( + Out<s32> out_count, OutArray<AppletIdentityInfo, BufferAttr_HipcMapAlias> out_identity_info) { + LOG_INFO(Service_AM, "called"); + + std::shared_ptr<Applet> applet = m_applet; + *out_count = 0; + + do { + if (*out_count >= static_cast<s32>(out_identity_info.size())) { + break; + } + out_identity_info[(*out_count)++] = GetCallerIdentity(*applet); + } while ((applet = applet->caller_applet.lock())); + + R_SUCCEED(); +} + +Result ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(Out<u32> out_desirable_layout) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_desirable_layout = 0; + R_SUCCEED(); +} + +Result ILibraryAppletSelfAccessor::ReportVisibleError(ErrorCode error_code) { + LOG_WARNING(Service_AM, "(STUBBED) called, error {}-{}", error_code.category, + error_code.number); + R_SUCCEED(); +} + +Result ILibraryAppletSelfAccessor::ReportVisibleErrorWithErrorContext( + ErrorCode error_code, InLargeData<ErrorContext, BufferAttr_HipcMapAlias> error_context) { + LOG_WARNING(Service_AM, "(STUBBED) called, error {}-{}", error_code.category, + error_code.number); + R_SUCCEED(); +} + +Result ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage( + Out<u64> out_desired_language) { + // FIXME: this is copied from IApplicationFunctions::GetDesiredLanguage + // FIXME: all of this stuff belongs to ns + auto identity = GetCallerIdentity(*m_applet); + + // TODO(bunnei): This should be configurable + LOG_DEBUG(Service_AM, "called"); + + // Get supported languages from NACP, if possible + // Default to 0 (all languages supported) + u32 supported_languages = 0; + + const auto res = [this, identity] { + const FileSys::PatchManager pm{identity.application_id, system.GetFileSystemController(), + system.GetContentProvider()}; + auto metadata = pm.GetControlMetadata(); + if (metadata.first != nullptr) { + return metadata; + } + + const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(identity.application_id), + system.GetFileSystemController(), + system.GetContentProvider()}; + return pm_update.GetControlMetadata(); + }(); + + if (res.first != nullptr) { + supported_languages = res.first->GetSupportedLanguages(); + } + + // Call IApplicationManagerInterface implementation. + auto& service_manager = system.ServiceManager(); + auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2"); + auto app_man = ns_am2->GetApplicationManagerInterface(); + + // Get desired application language + u8 desired_language{}; + R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages)); + + // Convert to settings language code. + u64 language_code{}; + R_TRY(app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language)); + + LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code); + + *out_desired_language = language_code; + R_SUCCEED(); +} + +Result ILibraryAppletSelfAccessor::GetCurrentApplicationId(Out<u64> out_application_id) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + // TODO: this should be the main applet, not the caller applet + const auto main_applet = GetCallerIdentity(*m_applet); + *out_application_id = main_applet.application_id; + + R_SUCCEED(); +} + +Result ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers( + Out<bool> out_no_users_available, Out<s32> out_users_count, + OutArray<Common::UUID, BufferAttr_HipcMapAlias> out_users) { + const Service::Account::ProfileManager manager{}; + + *out_no_users_available = true; + *out_users_count = -1; + + LOG_INFO(Service_AM, "called"); + + if (manager.GetUserCount() > 0) { + *out_no_users_available = false; + *out_users_count = static_cast<s32>(manager.GetUserCount()); + + const auto users = manager.GetAllUsers(); + for (size_t i = 0; i < users.size() && i < out_users.size(); i++) { + out_users[i] = users[i]; + } + } + + R_SUCCEED(); +} + +Result ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually( + Out<bool> out_should_set_gpu_time_slice_manually) { + LOG_INFO(Service_AM, "(STUBBED) called"); + *out_should_set_gpu_time_slice_manually = false; + R_SUCCEED(); +} + +Result ILibraryAppletSelfAccessor::Cmd160(Out<u64> out_unknown0) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + *out_unknown0 = 0; + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/library_applet_self_accessor.h b/src/core/hle/service/am/service/library_applet_self_accessor.h new file mode 100644 index 000000000..a9743569f --- /dev/null +++ b/src/core/hle/service/am/service/library_applet_self_accessor.h @@ -0,0 +1,83 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/uuid.h" +#include "core/hle/service/am/am_types.h" +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace FileSys { +enum class StorageId : u8; +} + +namespace Kernel { +class KReadableEvent; +} + +namespace Service::AM { + +class AppletDataBroker; +struct Applet; +class IStorage; + +struct LibraryAppletInfo { + AppletId applet_id; + LibraryAppletMode library_applet_mode; +}; +static_assert(sizeof(LibraryAppletInfo) == 0x8, "LibraryAppletInfo has incorrect size."); + +struct ErrorCode { + u32 category; + u32 number; +}; +static_assert(sizeof(ErrorCode) == 0x8, "ErrorCode has incorrect size."); + +struct ErrorContext { + u8 type; + INSERT_PADDING_BYTES_NOINIT(0x7); + std::array<u8, 0x1f4> data; + Result result; +}; +static_assert(sizeof(ErrorContext) == 0x200, "ErrorContext has incorrect size."); + +class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> { +public: + explicit ILibraryAppletSelfAccessor(Core::System& system_, std::shared_ptr<Applet> applet); + ~ILibraryAppletSelfAccessor() override; + +private: + Result PopInData(Out<SharedPointer<IStorage>> out_storage); + Result PushOutData(SharedPointer<IStorage> storage); + Result PopInteractiveInData(Out<SharedPointer<IStorage>> out_storage); + Result PushInteractiveOutData(SharedPointer<IStorage> storage); + Result GetPopInDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); + Result GetPopInteractiveInDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); + Result GetLibraryAppletInfo(Out<LibraryAppletInfo> out_library_applet_info); + Result GetMainAppletIdentityInfo(Out<AppletIdentityInfo> out_identity_info); + Result CanUseApplicationCore(Out<bool> out_can_use_application_core); + Result GetMainAppletApplicationControlProperty( + OutLargeData<std::array<u8, 0x4000>, BufferAttr_HipcMapAlias> out_nacp); + Result GetMainAppletStorageId(Out<FileSys::StorageId> out_storage_id); + Result ExitProcessAndReturn(); + Result GetCallerAppletIdentityInfo(Out<AppletIdentityInfo> out_identity_info); + Result GetCallerAppletIdentityInfoStack( + Out<s32> out_count, + OutArray<AppletIdentityInfo, BufferAttr_HipcMapAlias> out_identity_info); + Result GetDesirableKeyboardLayout(Out<u32> out_desirable_layout); + Result ReportVisibleError(ErrorCode error_code); + Result ReportVisibleErrorWithErrorContext( + ErrorCode error_code, InLargeData<ErrorContext, BufferAttr_HipcMapAlias> error_context); + Result GetMainAppletApplicationDesiredLanguage(Out<u64> out_desired_language); + Result GetCurrentApplicationId(Out<u64> out_application_id); + Result GetMainAppletAvailableUsers(Out<bool> out_no_users_available, Out<s32> out_users_count, + OutArray<Common::UUID, BufferAttr_HipcMapAlias> out_users); + Result ShouldSetGpuTimeSliceManually(Out<bool> out_should_set_gpu_time_slice_manually); + Result Cmd160(Out<u64> out_unknown0); + + const std::shared_ptr<Applet> m_applet; + const std::shared_ptr<AppletDataBroker> m_broker; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/lock_accessor.cpp b/src/core/hle/service/am/service/lock_accessor.cpp new file mode 100644 index 000000000..8e556fdd6 --- /dev/null +++ b/src/core/hle/service/am/service/lock_accessor.cpp @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/service/lock_accessor.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::AM { + +ILockAccessor::ILockAccessor(Core::System& system_) + : ServiceFramework{system_, "ILockAccessor"}, m_context{system_, "ILockAccessor"}, + m_event{m_context} { + // clang-format off + static const FunctionInfo functions[] = { + {1, D<&ILockAccessor::TryLock>, "TryLock"}, + {2, D<&ILockAccessor::Unlock>, "Unlock"}, + {3, D<&ILockAccessor::GetEvent>, "GetEvent"}, + {4, D<&ILockAccessor::IsLocked>, "IsLocked"}, + }; + // clang-format on + + RegisterHandlers(functions); + + m_event.Signal(); +} + +ILockAccessor::~ILockAccessor() = default; + +Result ILockAccessor::TryLock(Out<bool> out_is_locked, + OutCopyHandle<Kernel::KReadableEvent> out_handle, + bool return_handle) { + LOG_INFO(Service_AM, "called, return_handle={}", return_handle); + + { + std::scoped_lock lk{m_mutex}; + if (m_is_locked) { + *out_is_locked = false; + } else { + m_is_locked = true; + *out_is_locked = true; + } + } + + if (return_handle) { + *out_handle = m_event.GetHandle(); + } + + R_SUCCEED(); +} + +Result ILockAccessor::Unlock() { + LOG_INFO(Service_AM, "called"); + + { + std::scoped_lock lk{m_mutex}; + m_is_locked = false; + } + + m_event.Signal(); + R_SUCCEED(); +} + +Result ILockAccessor::GetEvent(OutCopyHandle<Kernel::KReadableEvent> out_handle) { + LOG_INFO(Service_AM, "called"); + *out_handle = m_event.GetHandle(); + R_SUCCEED(); +} + +Result ILockAccessor::IsLocked(Out<bool> out_is_locked) { + LOG_INFO(Service_AM, "called"); + std::scoped_lock lk{m_mutex}; + *out_is_locked = m_is_locked; + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/lock_accessor.h b/src/core/hle/service/am/service/lock_accessor.h new file mode 100644 index 000000000..9bfb5c050 --- /dev/null +++ b/src/core/hle/service/am/service/lock_accessor.h @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/os/event.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class ILockAccessor final : public ServiceFramework<ILockAccessor> { +public: + explicit ILockAccessor(Core::System& system_); + ~ILockAccessor() override; + +private: + Result TryLock(Out<bool> out_is_locked, OutCopyHandle<Kernel::KReadableEvent> out_handle, + bool return_handle); + Result Unlock(); + Result GetEvent(OutCopyHandle<Kernel::KReadableEvent> out_handle); + Result IsLocked(Out<bool> out_is_locked); + +private: + KernelHelpers::ServiceContext m_context; + Event m_event; + std::mutex m_mutex{}; + bool m_is_locked{}; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/process_winding_controller.cpp b/src/core/hle/service/am/service/process_winding_controller.cpp new file mode 100644 index 000000000..10df830d7 --- /dev/null +++ b/src/core/hle/service/am/service/process_winding_controller.cpp @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/frontend/applets.h" +#include "core/hle/service/am/service/library_applet_accessor.h" +#include "core/hle/service/am/service/process_winding_controller.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::AM { + +IProcessWindingController::IProcessWindingController(Core::System& system_, + std::shared_ptr<Applet> applet) + : ServiceFramework{system_, "IProcessWindingController"}, m_applet{std::move(applet)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, D<&IProcessWindingController::GetLaunchReason>, "GetLaunchReason"}, + {11, D<&IProcessWindingController::OpenCallingLibraryApplet>, "OpenCallingLibraryApplet"}, + {21, nullptr, "PushContext"}, + {22, nullptr, "PopContext"}, + {23, nullptr, "CancelWindingReservation"}, + {30, nullptr, "WindAndDoReserved"}, + {40, nullptr, "ReserveToStartAndWaitAndUnwindThis"}, + {41, nullptr, "ReserveToStartAndWait"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IProcessWindingController::~IProcessWindingController() = default; + +Result IProcessWindingController::GetLaunchReason( + Out<AppletProcessLaunchReason> out_launch_reason) { + LOG_INFO(Service_AM, "called"); + *out_launch_reason = m_applet->launch_reason; + R_SUCCEED(); +} + +Result IProcessWindingController::OpenCallingLibraryApplet( + Out<SharedPointer<ILibraryAppletAccessor>> out_calling_library_applet) { + LOG_INFO(Service_AM, "called"); + + const auto caller_applet = m_applet->caller_applet.lock(); + if (caller_applet == nullptr) { + LOG_ERROR(Service_AM, "No caller applet available"); + R_THROW(ResultUnknown); + } + + *out_calling_library_applet = std::make_shared<ILibraryAppletAccessor>( + system, m_applet->caller_applet_broker, caller_applet); + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/process_winding_controller.h b/src/core/hle/service/am/service/process_winding_controller.h new file mode 100644 index 000000000..4408af1f1 --- /dev/null +++ b/src/core/hle/service/am/service/process_winding_controller.h @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/am/am_types.h" +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +struct Applet; +class ILibraryAppletAccessor; + +class IProcessWindingController final : public ServiceFramework<IProcessWindingController> { +public: + explicit IProcessWindingController(Core::System& system_, std::shared_ptr<Applet> applet_); + ~IProcessWindingController() override; + +private: + Result GetLaunchReason(Out<AppletProcessLaunchReason> out_launch_reason); + Result OpenCallingLibraryApplet( + Out<SharedPointer<ILibraryAppletAccessor>> out_calling_library_applet); + + const std::shared_ptr<Applet> m_applet; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/self_controller.cpp b/src/core/hle/service/am/service/self_controller.cpp new file mode 100644 index 000000000..5c4c13de1 --- /dev/null +++ b/src/core/hle/service/am/service/self_controller.cpp @@ -0,0 +1,393 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "core/hle/result.h" +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/frontend/applets.h" +#include "core/hle/service/am/service/self_controller.h" +#include "core/hle/service/caps/caps_su.h" +#include "core/hle/service/cmif_serialization.h" +#include "core/hle/service/nvnflinger/nvnflinger.h" +#include "core/hle/service/sm/sm.h" +#include "core/hle/service/vi/vi_results.h" + +namespace Service::AM { + +ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet> applet, + Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger) + : ServiceFramework{system_, "ISelfController"}, + m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, D<&ISelfController::Exit>, "Exit"}, + {1, D<&ISelfController::LockExit>, "LockExit"}, + {2, D<&ISelfController::UnlockExit>, "UnlockExit"}, + {3, D<&ISelfController::EnterFatalSection>, "EnterFatalSection"}, + {4, D<&ISelfController::LeaveFatalSection>, "LeaveFatalSection"}, + {9, D<&ISelfController::GetLibraryAppletLaunchableEvent>, "GetLibraryAppletLaunchableEvent"}, + {10, D<&ISelfController::SetScreenShotPermission>, "SetScreenShotPermission"}, + {11, D<&ISelfController::SetOperationModeChangedNotification>, "SetOperationModeChangedNotification"}, + {12, D<&ISelfController::SetPerformanceModeChangedNotification>, "SetPerformanceModeChangedNotification"}, + {13, D<&ISelfController::SetFocusHandlingMode>, "SetFocusHandlingMode"}, + {14, D<&ISelfController::SetRestartMessageEnabled>, "SetRestartMessageEnabled"}, + {15, D<&ISelfController::SetScreenShotAppletIdentityInfo>, "SetScreenShotAppletIdentityInfo"}, + {16, D<&ISelfController::SetOutOfFocusSuspendingEnabled>, "SetOutOfFocusSuspendingEnabled"}, + {17, nullptr, "SetControllerFirmwareUpdateSection"}, + {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"}, + {19, D<&ISelfController::SetAlbumImageOrientation>, "SetAlbumImageOrientation"}, + {20, nullptr, "SetDesirableKeyboardLayout"}, + {21, nullptr, "GetScreenShotProgramId"}, + {40, D<&ISelfController::CreateManagedDisplayLayer>, "CreateManagedDisplayLayer"}, + {41, D<&ISelfController::IsSystemBufferSharingEnabled>, "IsSystemBufferSharingEnabled"}, + {42, D<&ISelfController::GetSystemSharedLayerHandle>, "GetSystemSharedLayerHandle"}, + {43, D<&ISelfController::GetSystemSharedBufferHandle>, "GetSystemSharedBufferHandle"}, + {44, D<&ISelfController::CreateManagedDisplaySeparableLayer>, "CreateManagedDisplaySeparableLayer"}, + {45, nullptr, "SetManagedDisplayLayerSeparationMode"}, + {46, nullptr, "SetRecordingLayerCompositionEnabled"}, + {50, D<&ISelfController::SetHandlesRequestToDisplay>, "SetHandlesRequestToDisplay"}, + {51, D<&ISelfController::ApproveToDisplay>, "ApproveToDisplay"}, + {60, D<&ISelfController::OverrideAutoSleepTimeAndDimmingTime>, "OverrideAutoSleepTimeAndDimmingTime"}, + {61, D<&ISelfController::SetMediaPlaybackState>, "SetMediaPlaybackState"}, + {62, D<&ISelfController::SetIdleTimeDetectionExtension>, "SetIdleTimeDetectionExtension"}, + {63, D<&ISelfController::GetIdleTimeDetectionExtension>, "GetIdleTimeDetectionExtension"}, + {64, nullptr, "SetInputDetectionSourceSet"}, + {65, D<&ISelfController::ReportUserIsActive>, "ReportUserIsActive"}, + {66, nullptr, "GetCurrentIlluminance"}, + {67, nullptr, "IsIlluminanceAvailable"}, + {68, D<&ISelfController::SetAutoSleepDisabled>, "SetAutoSleepDisabled"}, + {69, D<&ISelfController::IsAutoSleepDisabled>, "IsAutoSleepDisabled"}, + {70, nullptr, "ReportMultimediaError"}, + {71, nullptr, "GetCurrentIlluminanceEx"}, + {72, D<&ISelfController::SetInputDetectionPolicy>, "SetInputDetectionPolicy"}, + {80, nullptr, "SetWirelessPriorityMode"}, + {90, D<&ISelfController::GetAccumulatedSuspendedTickValue>, "GetAccumulatedSuspendedTickValue"}, + {91, D<&ISelfController::GetAccumulatedSuspendedTickChangedEvent>, "GetAccumulatedSuspendedTickChangedEvent"}, + {100, D<&ISelfController::SetAlbumImageTakenNotificationEnabled>, "SetAlbumImageTakenNotificationEnabled"}, + {110, nullptr, "SetApplicationAlbumUserData"}, + {120, D<&ISelfController::SaveCurrentScreenshot>, "SaveCurrentScreenshot"}, + {130, D<&ISelfController::SetRecordVolumeMuted>, "SetRecordVolumeMuted"}, + {1000, nullptr, "GetDebugStorageChannel"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +ISelfController::~ISelfController() = default; + +Result ISelfController::Exit() { + LOG_DEBUG(Service_AM, "called"); + + // TODO + system.Exit(); + + R_SUCCEED(); +} + +Result ISelfController::LockExit() { + LOG_DEBUG(Service_AM, "called"); + + system.SetExitLocked(true); + + R_SUCCEED(); +} + +Result ISelfController::UnlockExit() { + LOG_DEBUG(Service_AM, "called"); + + system.SetExitLocked(false); + + if (system.GetExitRequested()) { + system.Exit(); + } + + R_SUCCEED(); +} + +Result ISelfController::EnterFatalSection() { + std::scoped_lock lk{m_applet->lock}; + + m_applet->fatal_section_count++; + LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", m_applet->fatal_section_count); + + R_SUCCEED(); +} + +Result ISelfController::LeaveFatalSection() { + LOG_DEBUG(Service_AM, "called"); + + // Entry and exit of fatal sections must be balanced. + std::scoped_lock lk{m_applet->lock}; + R_UNLESS(m_applet->fatal_section_count > 0, AM::ResultFatalSectionCountImbalance); + m_applet->fatal_section_count--; + + R_SUCCEED(); +} + +Result ISelfController::GetLibraryAppletLaunchableEvent( + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + m_applet->library_applet_launchable_event.Signal(); + *out_event = m_applet->library_applet_launchable_event.GetHandle(); + + R_SUCCEED(); +} + +Result ISelfController::SetScreenShotPermission(ScreenshotPermission screen_shot_permission) { + LOG_DEBUG(Service_AM, "called, permission={}", screen_shot_permission); + + std::scoped_lock lk{m_applet->lock}; + m_applet->screenshot_permission = screen_shot_permission; + + R_SUCCEED(); +} + +Result ISelfController::SetOperationModeChangedNotification(bool enabled) { + LOG_INFO(Service_AM, "called, enabled={}", enabled); + + std::scoped_lock lk{m_applet->lock}; + m_applet->operation_mode_changed_notification_enabled = enabled; + + R_SUCCEED(); +} + +Result ISelfController::SetPerformanceModeChangedNotification(bool enabled) { + LOG_INFO(Service_AM, "called, enabled={}", enabled); + + std::scoped_lock lk{m_applet->lock}; + m_applet->performance_mode_changed_notification_enabled = enabled; + + R_SUCCEED(); +} + +Result ISelfController::SetFocusHandlingMode(bool notify, bool background, bool suspend) { + LOG_WARNING(Service_AM, "(STUBBED) called, notify={} background={} suspend={}", notify, + background, suspend); + + std::scoped_lock lk{m_applet->lock}; + m_applet->focus_handling_mode = {notify, background, suspend}; + + R_SUCCEED(); +} + +Result ISelfController::SetRestartMessageEnabled(bool enabled) { + LOG_INFO(Service_AM, "called, enabled={}", enabled); + + std::scoped_lock lk{m_applet->lock}; + m_applet->restart_message_enabled = enabled; + + R_SUCCEED(); +} + +Result ISelfController::SetScreenShotAppletIdentityInfo( + AppletIdentityInfo screen_shot_applet_identity_info) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::scoped_lock lk{m_applet->lock}; + m_applet->screen_shot_identity = screen_shot_applet_identity_info; + + R_SUCCEED(); +} + +Result ISelfController::SetOutOfFocusSuspendingEnabled(bool enabled) { + LOG_INFO(Service_AM, "called, enabled={}", enabled); + + std::scoped_lock lk{m_applet->lock}; + m_applet->out_of_focus_suspension_enabled = enabled; + + R_SUCCEED(); +} + +Result ISelfController::SetAlbumImageOrientation( + Capture::AlbumImageOrientation album_image_orientation) { + LOG_WARNING(Service_AM, "(STUBBED) called, orientation={}", album_image_orientation); + + std::scoped_lock lk{m_applet->lock}; + m_applet->album_image_orientation = album_image_orientation; + + R_SUCCEED(); +} + +Result ISelfController::IsSystemBufferSharingEnabled() { + LOG_INFO(Service_AM, "called"); + R_SUCCEED_IF(m_applet->system_buffer_manager.Initialize( + &m_nvnflinger, m_process, m_applet->applet_id, m_applet->library_applet_mode)); + R_THROW(VI::ResultOperationFailed); +} + +Result ISelfController::GetSystemSharedBufferHandle(Out<u64> out_buffer_id) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + R_TRY(this->IsSystemBufferSharingEnabled()); + + u64 layer_id; + m_applet->system_buffer_manager.GetSystemSharedLayerHandle(out_buffer_id, &layer_id); + R_SUCCEED(); +} + +Result ISelfController::GetSystemSharedLayerHandle(Out<u64> out_buffer_id, Out<u64> out_layer_id) { + LOG_INFO(Service_AM, "(STUBBED) called"); + + R_TRY(this->IsSystemBufferSharingEnabled()); + + m_applet->system_buffer_manager.GetSystemSharedLayerHandle(out_buffer_id, out_layer_id); + R_SUCCEED(); +} + +Result ISelfController::CreateManagedDisplayLayer(Out<u64> out_layer_id) { + LOG_INFO(Service_AM, "called"); + + m_applet->managed_layer_holder.Initialize(&m_nvnflinger); + m_applet->managed_layer_holder.CreateManagedDisplayLayer(out_layer_id); + + R_SUCCEED(); +} + +Result ISelfController::CreateManagedDisplaySeparableLayer(Out<u64> out_layer_id, + Out<u64> out_recording_layer_id) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + m_applet->managed_layer_holder.Initialize(&m_nvnflinger); + m_applet->managed_layer_holder.CreateManagedDisplaySeparableLayer(out_layer_id, + out_recording_layer_id); + + R_SUCCEED(); +} + +Result ISelfController::SetHandlesRequestToDisplay(bool enable) { + LOG_WARNING(Service_AM, "(STUBBED) called, enable={}", enable); + R_SUCCEED(); +} + +Result ISelfController::ApproveToDisplay() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_SUCCEED(); +} + +Result ISelfController::SetMediaPlaybackState(bool state) { + LOG_WARNING(Service_AM, "(STUBBED) called, state={}", state); + R_SUCCEED(); +} + +Result ISelfController::OverrideAutoSleepTimeAndDimmingTime(s32 a, s32 b, s32 c, s32 d) { + LOG_WARNING(Service_AM, "(STUBBED) called, a={}, b={}, c={}, d={}", a, b, c, d); + R_SUCCEED(); +} + +Result ISelfController::SetIdleTimeDetectionExtension( + IdleTimeDetectionExtension idle_time_detection_extension) { + LOG_DEBUG(Service_AM, "(STUBBED) called extension={}", idle_time_detection_extension); + + std::scoped_lock lk{m_applet->lock}; + m_applet->idle_time_detection_extension = idle_time_detection_extension; + + R_SUCCEED(); +} + +Result ISelfController::GetIdleTimeDetectionExtension( + Out<IdleTimeDetectionExtension> out_idle_time_detection_extension) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::scoped_lock lk{m_applet->lock}; + *out_idle_time_detection_extension = m_applet->idle_time_detection_extension; + + R_SUCCEED(); +} + +Result ISelfController::ReportUserIsActive() { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_SUCCEED(); +} + +Result ISelfController::SetAutoSleepDisabled(bool is_auto_sleep_disabled) { + LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", is_auto_sleep_disabled); + + // On the system itself, if the previous state of is_auto_sleep_disabled + // differed from the current value passed in, it'd signify the internal + // window manager to update (and also increment some statistics like update counts) + // + // It'd also indicate this change to an idle handling context. + // + // However, given we're emulating this behavior, most of this can be ignored + // and it's sufficient to simply set the member variable for querying via + // IsAutoSleepDisabled(). + + std::scoped_lock lk{m_applet->lock}; + m_applet->auto_sleep_disabled = is_auto_sleep_disabled; + + R_SUCCEED(); +} + +Result ISelfController::IsAutoSleepDisabled(Out<bool> out_is_auto_sleep_disabled) { + LOG_DEBUG(Service_AM, "called."); + + std::scoped_lock lk{m_applet->lock}; + *out_is_auto_sleep_disabled = m_applet->auto_sleep_disabled; + + R_SUCCEED(); +} + +Result ISelfController::SetInputDetectionPolicy(InputDetectionPolicy input_detection_policy) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + R_SUCCEED(); +} + +Result ISelfController::GetAccumulatedSuspendedTickValue( + Out<u64> out_accumulated_suspended_tick_value) { + LOG_DEBUG(Service_AM, "called."); + + // This command returns the total number of system ticks since ISelfController creation + // where the game was suspended. Since Yuzu doesn't implement game suspension, this command + // can just always return 0 ticks. + std::scoped_lock lk{m_applet->lock}; + *out_accumulated_suspended_tick_value = m_applet->suspended_ticks; + + R_SUCCEED(); +} + +Result ISelfController::GetAccumulatedSuspendedTickChangedEvent( + OutCopyHandle<Kernel::KReadableEvent> out_event) { + LOG_DEBUG(Service_AM, "called."); + + *out_event = m_applet->accumulated_suspended_tick_changed_event.GetHandle(); + R_SUCCEED(); +} + +Result ISelfController::SetAlbumImageTakenNotificationEnabled(bool enabled) { + LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled); + + // This service call sets an internal flag whether a notification is shown when an image is + // captured. Currently we do not support capturing images via the capture button, so this can be + // stubbed for now. + std::scoped_lock lk{m_applet->lock}; + m_applet->album_image_taken_notification_enabled = enabled; + + R_SUCCEED(); +} + +Result ISelfController::SaveCurrentScreenshot(Capture::AlbumReportOption album_report_option) { + LOG_INFO(Service_AM, "called, report_option={}", album_report_option); + + const auto screenshot_service = + system.ServiceManager().GetService<Service::Capture::IScreenShotApplicationService>( + "caps:su"); + + if (screenshot_service) { + screenshot_service->CaptureAndSaveScreenshot(album_report_option); + } + + R_SUCCEED(); +} + +Result ISelfController::SetRecordVolumeMuted(bool muted) { + LOG_WARNING(Service_AM, "(STUBBED) called. muted={}", muted); + + std::scoped_lock lk{m_applet->lock}; + m_applet->record_volume_muted = muted; + + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/self_controller.h b/src/core/hle/service/am/service/self_controller.h new file mode 100644 index 000000000..01fa381a3 --- /dev/null +++ b/src/core/hle/service/am/service/self_controller.h @@ -0,0 +1,72 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/am/am_types.h" +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Kernel { +class KReadableEvent; +} + +namespace Service::Capture { +enum class AlbumImageOrientation; +enum class AlbumReportOption; +} // namespace Service::Capture + +namespace Service::AM { + +struct Applet; + +class ISelfController final : public ServiceFramework<ISelfController> { +public: + explicit ISelfController(Core::System& system_, std::shared_ptr<Applet> applet, + Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger); + ~ISelfController() override; + +private: + Result Exit(); + Result LockExit(); + Result UnlockExit(); + Result EnterFatalSection(); + Result LeaveFatalSection(); + Result GetLibraryAppletLaunchableEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); + Result SetScreenShotPermission(ScreenshotPermission screen_shot_permission); + Result SetOperationModeChangedNotification(bool enabled); + Result SetPerformanceModeChangedNotification(bool enabled); + Result SetFocusHandlingMode(bool notify, bool background, bool suspend); + Result SetRestartMessageEnabled(bool enabled); + Result SetScreenShotAppletIdentityInfo(AppletIdentityInfo screen_shot_applet_identity_info); + Result SetOutOfFocusSuspendingEnabled(bool enabled); + Result SetAlbumImageOrientation(Capture::AlbumImageOrientation album_image_orientation); + Result IsSystemBufferSharingEnabled(); + Result GetSystemSharedBufferHandle(Out<u64> out_buffer_id); + Result GetSystemSharedLayerHandle(Out<u64> out_buffer_id, Out<u64> out_layer_id); + Result CreateManagedDisplayLayer(Out<u64> out_layer_id); + Result CreateManagedDisplaySeparableLayer(Out<u64> out_layer_id, + Out<u64> out_recording_layer_id); + Result SetHandlesRequestToDisplay(bool enable); + Result ApproveToDisplay(); + Result SetMediaPlaybackState(bool state); + Result OverrideAutoSleepTimeAndDimmingTime(s32 a, s32 b, s32 c, s32 d); + Result SetIdleTimeDetectionExtension(IdleTimeDetectionExtension idle_time_detection_extension); + Result GetIdleTimeDetectionExtension( + Out<IdleTimeDetectionExtension> out_idle_time_detection_extension); + Result ReportUserIsActive(); + Result SetAutoSleepDisabled(bool is_auto_sleep_disabled); + Result IsAutoSleepDisabled(Out<bool> out_is_auto_sleep_disabled); + Result SetInputDetectionPolicy(InputDetectionPolicy input_detection_policy); + Result GetAccumulatedSuspendedTickValue(Out<u64> out_accumulated_suspended_tick_value); + Result GetAccumulatedSuspendedTickChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); + Result SetAlbumImageTakenNotificationEnabled(bool enabled); + Result SaveCurrentScreenshot(Capture::AlbumReportOption album_report_option); + Result SetRecordVolumeMuted(bool muted); + + Nvnflinger::Nvnflinger& m_nvnflinger; + Kernel::KProcess* const m_process; + const std::shared_ptr<Applet> m_applet; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/storage.cpp b/src/core/hle/service/am/service/storage.cpp new file mode 100644 index 000000000..25ee0afbd --- /dev/null +++ b/src/core/hle/service/am/service/storage.cpp @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/library_applet_storage.h" +#include "core/hle/service/am/service/storage.h" +#include "core/hle/service/am/service/storage_accessor.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::AM { + +IStorage::IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl) + : ServiceFramework{system_, "IStorage"}, m_impl{std::move(impl)} { + static const FunctionInfo functions[] = { + {0, D<&IStorage::Open>, "Open"}, + {1, D<&IStorage::OpenTransferStorage>, "OpenTransferStorage"}, + }; + + RegisterHandlers(functions); +} + +IStorage::IStorage(Core::System& system_, std::vector<u8>&& data) + : IStorage(system_, CreateStorage(std::move(data))) {} + +IStorage::~IStorage() = default; + +Result IStorage::Open(Out<SharedPointer<IStorageAccessor>> out_storage_accessor) { + LOG_DEBUG(Service_AM, "called"); + + R_UNLESS(m_impl->GetHandle() == nullptr, AM::ResultInvalidStorageType); + + *out_storage_accessor = std::make_shared<IStorageAccessor>(system, m_impl); + R_SUCCEED(); +} + +Result IStorage::OpenTransferStorage( + Out<SharedPointer<ITransferStorageAccessor>> out_transfer_storage_accessor) { + R_UNLESS(m_impl->GetHandle() != nullptr, AM::ResultInvalidStorageType); + + *out_transfer_storage_accessor = std::make_shared<ITransferStorageAccessor>(system, m_impl); + R_SUCCEED(); +} + +std::vector<u8> IStorage::GetData() const { + return m_impl->GetData(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/storage.h b/src/core/hle/service/am/service/storage.h new file mode 100644 index 000000000..cde2ed0ea --- /dev/null +++ b/src/core/hle/service/am/service/storage.h @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class LibraryAppletStorage; +class IStorageAccessor; +class ITransferStorageAccessor; + +class IStorage final : public ServiceFramework<IStorage> { +public: + explicit IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl); + explicit IStorage(Core::System& system_, std::vector<u8>&& buffer); + ~IStorage() override; + + std::shared_ptr<LibraryAppletStorage> GetImpl() const { + return m_impl; + } + + std::vector<u8> GetData() const; + +private: + Result Open(Out<SharedPointer<IStorageAccessor>> out_storage_accessor); + Result OpenTransferStorage( + Out<SharedPointer<ITransferStorageAccessor>> out_transfer_storage_accessor); + + const std::shared_ptr<LibraryAppletStorage> m_impl; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/storage_accessor.cpp b/src/core/hle/service/am/service/storage_accessor.cpp new file mode 100644 index 000000000..84577fee4 --- /dev/null +++ b/src/core/hle/service/am/service/storage_accessor.cpp @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/k_transfer_memory.h" +#include "core/hle/service/am/library_applet_storage.h" +#include "core/hle/service/am/service/storage_accessor.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::AM { + +IStorageAccessor::IStorageAccessor(Core::System& system_, + std::shared_ptr<LibraryAppletStorage> impl) + : ServiceFramework{system_, "IStorageAccessor"}, m_impl{std::move(impl)} { + static const FunctionInfo functions[] = { + {0, D<&IStorageAccessor::GetSize>, "GetSize"}, + {10, D<&IStorageAccessor::Write>, "Write"}, + {11, D<&IStorageAccessor::Read>, "Read"}, + }; + + RegisterHandlers(functions); +} + +IStorageAccessor::~IStorageAccessor() = default; + +Result IStorageAccessor::GetSize(Out<s64> out_size) { + LOG_DEBUG(Service_AM, "called"); + *out_size = m_impl->GetSize(); + R_SUCCEED(); +} + +Result IStorageAccessor::Write(InBuffer<BufferAttr_HipcAutoSelect> buffer, s64 offset) { + LOG_DEBUG(Service_AM, "called, offset={} size={}", offset, buffer.size()); + R_RETURN(m_impl->Write(offset, buffer.data(), buffer.size())); +} + +Result IStorageAccessor::Read(OutBuffer<BufferAttr_HipcAutoSelect> out_buffer, s64 offset) { + LOG_DEBUG(Service_AM, "called, offset={} size={}", offset, out_buffer.size()); + R_RETURN(m_impl->Read(offset, out_buffer.data(), out_buffer.size())); +} + +ITransferStorageAccessor::ITransferStorageAccessor(Core::System& system_, + std::shared_ptr<LibraryAppletStorage> impl) + : ServiceFramework{system_, "ITransferStorageAccessor"}, m_impl{std::move(impl)} { + static const FunctionInfo functions[] = { + {0, D<&ITransferStorageAccessor::GetSize>, "GetSize"}, + {1, D<&ITransferStorageAccessor::GetHandle>, "GetHandle"}, + }; + + RegisterHandlers(functions); +} + +ITransferStorageAccessor::~ITransferStorageAccessor() = default; + +Result ITransferStorageAccessor::GetSize(Out<s64> out_size) { + LOG_DEBUG(Service_AM, "called"); + *out_size = m_impl->GetSize(); + R_SUCCEED(); +} + +Result ITransferStorageAccessor::GetHandle(Out<s64> out_size, + OutCopyHandle<Kernel::KTransferMemory> out_handle) { + LOG_INFO(Service_AM, "called"); + *out_size = m_impl->GetSize(); + *out_handle = m_impl->GetHandle(); + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/storage_accessor.h b/src/core/hle/service/am/service/storage_accessor.h new file mode 100644 index 000000000..1a01730e0 --- /dev/null +++ b/src/core/hle/service/am/service/storage_accessor.h @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/am/library_applet_storage.h" +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { +public: + explicit IStorageAccessor(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl); + ~IStorageAccessor() override; + +private: + Result GetSize(Out<s64> out_size); + Result Write(InBuffer<BufferAttr_HipcAutoSelect> buffer, s64 offset); + Result Read(OutBuffer<BufferAttr_HipcAutoSelect> out_buffer, s64 offset); + + const std::shared_ptr<LibraryAppletStorage> m_impl; +}; + +class ITransferStorageAccessor final : public ServiceFramework<ITransferStorageAccessor> { +public: + explicit ITransferStorageAccessor(Core::System& system_, + std::shared_ptr<LibraryAppletStorage> impl); + ~ITransferStorageAccessor() override; + +private: + Result GetSize(Out<s64> out_size); + Result GetHandle(Out<s64> out_size, OutCopyHandle<Kernel::KTransferMemory> out_handle); + + const std::shared_ptr<LibraryAppletStorage> m_impl; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/system_applet_proxy.cpp b/src/core/hle/service/am/service/system_applet_proxy.cpp new file mode 100644 index 000000000..5ec509d2e --- /dev/null +++ b/src/core/hle/service/am/service/system_applet_proxy.cpp @@ -0,0 +1,133 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/service/applet_common_functions.h" +#include "core/hle/service/am/service/application_creator.h" +#include "core/hle/service/am/service/audio_controller.h" +#include "core/hle/service/am/service/common_state_getter.h" +#include "core/hle/service/am/service/debug_functions.h" +#include "core/hle/service/am/service/display_controller.h" +#include "core/hle/service/am/service/global_state_controller.h" +#include "core/hle/service/am/service/home_menu_functions.h" +#include "core/hle/service/am/service/library_applet_creator.h" +#include "core/hle/service/am/service/process_winding_controller.h" +#include "core/hle/service/am/service/self_controller.h" +#include "core/hle/service/am/service/system_applet_proxy.h" +#include "core/hle/service/am/service/window_controller.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::AM { + +ISystemAppletProxy::ISystemAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet, + Kernel::KProcess* process, + Nvnflinger::Nvnflinger& nvnflinger) + : ServiceFramework{system_, "ISystemAppletProxy"}, + m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, D<&ISystemAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"}, + {1, D<&ISystemAppletProxy::GetSelfController>, "GetSelfController"}, + {2, D<&ISystemAppletProxy::GetWindowController>, "GetWindowController"}, + {3, D<&ISystemAppletProxy::GetAudioController>, "GetAudioController"}, + {4, D<&ISystemAppletProxy::GetDisplayController>, "GetDisplayController"}, + {10, D<&ISystemAppletProxy::GetProcessWindingController>, "GetProcessWindingController"}, + {11, D<&ISystemAppletProxy::GetLibraryAppletCreator>, "GetLibraryAppletCreator"}, + {20, D<&ISystemAppletProxy::GetHomeMenuFunctions>, "GetHomeMenuFunctions"}, + {21, D<&ISystemAppletProxy::GetGlobalStateController>, "GetGlobalStateController"}, + {22, D<&ISystemAppletProxy::GetApplicationCreator>, "GetApplicationCreator"}, + {23, D<&ISystemAppletProxy::GetAppletCommonFunctions>, "GetAppletCommonFunctions"}, + {1000, D<&ISystemAppletProxy::GetDebugFunctions>, "GetDebugFunctions"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +ISystemAppletProxy::~ISystemAppletProxy() = default; + +Result ISystemAppletProxy::GetAudioController( + Out<SharedPointer<IAudioController>> out_audio_controller) { + LOG_DEBUG(Service_AM, "called"); + *out_audio_controller = std::make_shared<IAudioController>(system); + R_SUCCEED(); +} + +Result ISystemAppletProxy::GetDisplayController( + Out<SharedPointer<IDisplayController>> out_display_controller) { + LOG_DEBUG(Service_AM, "called"); + *out_display_controller = std::make_shared<IDisplayController>(system, m_applet); + R_SUCCEED(); +} + +Result ISystemAppletProxy::GetProcessWindingController( + Out<SharedPointer<IProcessWindingController>> out_process_winding_controller) { + LOG_DEBUG(Service_AM, "called"); + *out_process_winding_controller = std::make_shared<IProcessWindingController>(system, m_applet); + R_SUCCEED(); +} + +Result ISystemAppletProxy::GetDebugFunctions( + Out<SharedPointer<IDebugFunctions>> out_debug_functions) { + LOG_DEBUG(Service_AM, "called"); + *out_debug_functions = std::make_shared<IDebugFunctions>(system); + R_SUCCEED(); +} + +Result ISystemAppletProxy::GetWindowController( + Out<SharedPointer<IWindowController>> out_window_controller) { + LOG_DEBUG(Service_AM, "called"); + *out_window_controller = std::make_shared<IWindowController>(system, m_applet); + R_SUCCEED(); +} + +Result ISystemAppletProxy::GetSelfController( + Out<SharedPointer<ISelfController>> out_self_controller) { + LOG_DEBUG(Service_AM, "called"); + *out_self_controller = + std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger); + R_SUCCEED(); +} + +Result ISystemAppletProxy::GetCommonStateGetter( + Out<SharedPointer<ICommonStateGetter>> out_common_state_getter) { + LOG_DEBUG(Service_AM, "called"); + *out_common_state_getter = std::make_shared<ICommonStateGetter>(system, m_applet); + R_SUCCEED(); +} + +Result ISystemAppletProxy::GetLibraryAppletCreator( + Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) { + LOG_DEBUG(Service_AM, "called"); + *out_library_applet_creator = std::make_shared<ILibraryAppletCreator>(system, m_applet); + R_SUCCEED(); +} + +Result ISystemAppletProxy::GetApplicationCreator( + Out<SharedPointer<IApplicationCreator>> out_application_creator) { + LOG_DEBUG(Service_AM, "called"); + *out_application_creator = std::make_shared<IApplicationCreator>(system); + R_SUCCEED(); +} + +Result ISystemAppletProxy::GetAppletCommonFunctions( + Out<SharedPointer<IAppletCommonFunctions>> out_applet_common_functions) { + LOG_DEBUG(Service_AM, "called"); + *out_applet_common_functions = std::make_shared<IAppletCommonFunctions>(system, m_applet); + R_SUCCEED(); +} + +Result ISystemAppletProxy::GetHomeMenuFunctions( + Out<SharedPointer<IHomeMenuFunctions>> out_home_menu_functions) { + LOG_DEBUG(Service_AM, "called"); + *out_home_menu_functions = std::make_shared<IHomeMenuFunctions>(system, m_applet); + R_SUCCEED(); +} + +Result ISystemAppletProxy::GetGlobalStateController( + Out<SharedPointer<IGlobalStateController>> out_global_state_controller) { + LOG_DEBUG(Service_AM, "called"); + *out_global_state_controller = std::make_shared<IGlobalStateController>(system); + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/system_applet_proxy.h b/src/core/hle/service/am/service/system_applet_proxy.h new file mode 100644 index 000000000..3d5040315 --- /dev/null +++ b/src/core/hle/service/am/service/system_applet_proxy.h @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +struct Applet; +class IAppletCommonFunctions; +class IApplicationCreator; +class IAudioController; +class ICommonStateGetter; +class IDebugFunctions; +class IDisplayController; +class IHomeMenuFunctions; +class IGlobalStateController; +class ILibraryAppletCreator; +class IProcessWindingController; +class ISelfController; +class IWindowController; + +class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { +public: + explicit ISystemAppletProxy(Core::System& system, std::shared_ptr<Applet> applet, + Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger); + ~ISystemAppletProxy(); + +private: + Result GetAudioController(Out<SharedPointer<IAudioController>> out_audio_controller); + Result GetDisplayController(Out<SharedPointer<IDisplayController>> out_display_controller); + Result GetProcessWindingController( + Out<SharedPointer<IProcessWindingController>> out_process_winding_controller); + Result GetDebugFunctions(Out<SharedPointer<IDebugFunctions>> out_debug_functions); + Result GetWindowController(Out<SharedPointer<IWindowController>> out_window_controller); + Result GetSelfController(Out<SharedPointer<ISelfController>> out_self_controller); + Result GetCommonStateGetter(Out<SharedPointer<ICommonStateGetter>> out_common_state_getter); + Result GetLibraryAppletCreator( + Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator); + Result GetApplicationCreator(Out<SharedPointer<IApplicationCreator>> out_application_creator); + Result GetAppletCommonFunctions( + Out<SharedPointer<IAppletCommonFunctions>> out_applet_common_functions); + Result GetHomeMenuFunctions(Out<SharedPointer<IHomeMenuFunctions>> out_home_menu_functions); + Result GetGlobalStateController( + Out<SharedPointer<IGlobalStateController>> out_global_state_controller); + + Nvnflinger::Nvnflinger& m_nvnflinger; + Kernel::KProcess* const m_process; + const std::shared_ptr<Applet> m_applet; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/window_controller.cpp b/src/core/hle/service/am/service/window_controller.cpp new file mode 100644 index 000000000..b874ecb91 --- /dev/null +++ b/src/core/hle/service/am/service/window_controller.cpp @@ -0,0 +1,86 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applet.h" +#include "core/hle/service/am/applet_manager.h" +#include "core/hle/service/am/service/window_controller.h" +#include "core/hle/service/cmif_serialization.h" + +namespace Service::AM { + +IWindowController::IWindowController(Core::System& system_, std::shared_ptr<Applet> applet) + : ServiceFramework{system_, "IWindowController"}, m_applet{std::move(applet)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "CreateWindow"}, + {1, D<&IWindowController::GetAppletResourceUserId>, "GetAppletResourceUserId"}, + {2, D<&IWindowController::GetAppletResourceUserIdOfCallerApplet>, "GetAppletResourceUserIdOfCallerApplet"}, + {10, D<&IWindowController::AcquireForegroundRights>, "AcquireForegroundRights"}, + {11, D<&IWindowController::ReleaseForegroundRights>, "ReleaseForegroundRights"}, + {12, D<&IWindowController::RejectToChangeIntoBackground>, "RejectToChangeIntoBackground"}, + {20, D<&IWindowController::SetAppletWindowVisibility>, "SetAppletWindowVisibility"}, + {21, D<&IWindowController::SetAppletGpuTimeSlice>, "SetAppletGpuTimeSlice"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IWindowController::~IWindowController() = default; + +Result IWindowController::GetAppletResourceUserId(Out<AppletResourceUserId> out_aruid) { + LOG_INFO(Service_AM, "called"); + *out_aruid = m_applet->aruid; + R_SUCCEED(); +} + +Result IWindowController::GetAppletResourceUserIdOfCallerApplet( + Out<AppletResourceUserId> out_aruid) { + LOG_INFO(Service_AM, "called"); + + if (auto caller_applet = m_applet->caller_applet.lock(); caller_applet != nullptr) { + *out_aruid = caller_applet->aruid; + } else { + *out_aruid = AppletResourceUserId{}; + } + + R_SUCCEED(); +} + +Result IWindowController::AcquireForegroundRights() { + LOG_INFO(Service_AM, "called"); + R_SUCCEED(); +} + +Result IWindowController::ReleaseForegroundRights() { + LOG_INFO(Service_AM, "called"); + R_SUCCEED(); +} + +Result IWindowController::RejectToChangeIntoBackground() { + LOG_INFO(Service_AM, "called"); + R_SUCCEED(); +} + +Result IWindowController::SetAppletWindowVisibility(bool visible) { + m_applet->system_buffer_manager.SetWindowVisibility(visible); + m_applet->hid_registration.EnableAppletToGetInput(visible); + + if (visible) { + m_applet->message_queue.PushMessage(AppletMessage::ChangeIntoForeground); + m_applet->focus_state = FocusState::InFocus; + } else { + m_applet->focus_state = FocusState::NotInFocus; + } + + m_applet->message_queue.PushMessage(AppletMessage::FocusStateChanged); + + R_SUCCEED(); +} + +Result IWindowController::SetAppletGpuTimeSlice(s64 time_slice) { + LOG_WARNING(Service_AM, "(STUBBED) called, time_slice={}", time_slice); + R_SUCCEED(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/service/window_controller.h b/src/core/hle/service/am/service/window_controller.h new file mode 100644 index 000000000..bfbad9bcc --- /dev/null +++ b/src/core/hle/service/am/service/window_controller.h @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +struct Applet; + +class IWindowController final : public ServiceFramework<IWindowController> { +public: + explicit IWindowController(Core::System& system_, std::shared_ptr<Applet> applet); + ~IWindowController() override; + +private: + Result GetAppletResourceUserId(Out<AppletResourceUserId> out_aruid); + Result GetAppletResourceUserIdOfCallerApplet(Out<AppletResourceUserId> out_aruid); + Result AcquireForegroundRights(); + Result ReleaseForegroundRights(); + Result RejectToChangeIntoBackground(); + Result SetAppletWindowVisibility(bool visible); + Result SetAppletGpuTimeSlice(s64 time_slice); + + const std::shared_ptr<Applet> m_applet; +}; + +} // namespace Service::AM |