diff options
61 files changed, 4093 insertions, 3482 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ea6b2c285..3a2ba9ed4 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -392,6 +392,7 @@ add_library(core STATIC hle/service/acc/profile_manager.h hle/service/am/am.cpp hle/service/am/am.h + hle/service/am/am_results.h hle/service/am/applet_ae.cpp hle/service/am/applet_ae.h hle/service/am/applet_oe.cpp @@ -417,12 +418,56 @@ add_library(core STATIC hle/service/am/applets/applet_web_browser_types.h hle/service/am/applets/applets.cpp hle/service/am/applets/applets.h + hle/service/am/applet_common_functions.cpp + hle/service/am/applet_common_functions.h + hle/service/am/applet_message_queue.cpp + hle/service/am/applet_message_queue.h + hle/service/am/application_creator.cpp + hle/service/am/application_creator.h + hle/service/am/application_functions.cpp + hle/service/am/application_functions.h + hle/service/am/application_proxy.cpp + hle/service/am/application_proxy.h + hle/service/am/audio_controller.cpp + hle/service/am/audio_controller.h + hle/service/am/common_state_getter.cpp + hle/service/am/common_state_getter.h + hle/service/am/debug_functions.cpp + hle/service/am/debug_functions.h + hle/service/am/display_controller.cpp + hle/service/am/display_controller.h + hle/service/am/global_state_controller.cpp + hle/service/am/global_state_controller.h + hle/service/am/home_menu_functions.cpp + hle/service/am/home_menu_functions.h hle/service/am/idle.cpp hle/service/am/idle.h + hle/service/am/library_applet_accessor.cpp + hle/service/am/library_applet_accessor.h + hle/service/am/library_applet_creator.cpp + hle/service/am/library_applet_creator.h + hle/service/am/library_applet_proxy.cpp + hle/service/am/library_applet_proxy.h + hle/service/am/library_applet_self_accessor.cpp + hle/service/am/library_applet_self_accessor.h + hle/service/am/lock_accessor.cpp + hle/service/am/lock_accessor.h hle/service/am/omm.cpp hle/service/am/omm.h + hle/service/am/process_winding_controller.cpp + hle/service/am/process_winding_controller.h + hle/service/am/self_controller.cpp + hle/service/am/self_controller.h + hle/service/am/system_applet_proxy.cpp + hle/service/am/system_applet_proxy.h hle/service/am/spsm.cpp hle/service/am/spsm.h + hle/service/am/storage_accessor.cpp + hle/service/am/storage_accessor.h + hle/service/am/storage.cpp + hle/service/am/storage.h + hle/service/am/window_controller.cpp + hle/service/am/window_controller.h hle/service/aoc/aoc_u.cpp hle/service/aoc/aoc_u.h hle/service/apm/apm.cpp diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 38f67adcd..46bc4f703 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -1,2541 +1,17 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include <algorithm> -#include <array> -#include <cinttypes> -#include <cstring> -#include "common/settings.h" -#include "common/settings_enums.h" -#include "core/core.h" -#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/file_sys/savedata_factory.h" -#include "core/hle/kernel/k_event.h" -#include "core/hle/kernel/k_transfer_memory.h" -#include "core/hle/result.h" -#include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" +#include "core/hle/service/am/applet_message_queue.h" #include "core/hle/service/am/applet_oe.h" -#include "core/hle/service/am/applets/applet_cabinet.h" -#include "core/hle/service/am/applets/applet_controller.h" -#include "core/hle/service/am/applets/applet_mii_edit_types.h" -#include "core/hle/service/am/applets/applet_profile_select.h" -#include "core/hle/service/am/applets/applet_software_keyboard_types.h" -#include "core/hle/service/am/applets/applet_web_browser.h" -#include "core/hle/service/am/applets/applets.h" #include "core/hle/service/am/idle.h" #include "core/hle/service/am/omm.h" #include "core/hle/service/am/spsm.h" -#include "core/hle/service/apm/apm_controller.h" -#include "core/hle/service/apm/apm_interface.h" -#include "core/hle/service/bcat/backend/backend.h" -#include "core/hle/service/caps/caps_su.h" -#include "core/hle/service/caps/caps_types.h" -#include "core/hle/service/filesystem/filesystem.h" -#include "core/hle/service/filesystem/save_data_controller.h" -#include "core/hle/service/ipc_helpers.h" -#include "core/hle/service/ns/ns.h" -#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" -#include "core/hle/service/nvnflinger/nvnflinger.h" -#include "core/hle/service/pm/pm.h" #include "core/hle/service/server_manager.h" -#include "core/hle/service/sm/sm.h" -#include "core/hle/service/vi/vi.h" -#include "core/hle/service/vi/vi_results.h" -#include "core/memory.h" -#include "hid_core/hid_types.h" -#include "hid_core/resources/npad/npad.h" namespace Service::AM { -constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2}; -constexpr Result ResultNoMessages{ErrorModule::AM, 3}; -constexpr Result ResultInvalidOffset{ErrorModule::AM, 503}; - -enum class LaunchParameterKind : u32 { - UserChannel = 1, - AccountPreselectedUser = 2, -}; - -constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA; - -struct LaunchParameterAccountPreselectedUser { - u32_le magic; - u32_le is_account_selected; - Common::UUID current_user; - INSERT_PADDING_BYTES(0x70); -}; -static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); - -IWindowController::IWindowController(Core::System& system_) - : ServiceFramework{system_, "IWindowController"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "CreateWindow"}, - {1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"}, - {2, &IWindowController::GetAppletResourceUserIdOfCallerApplet, "GetAppletResourceUserIdOfCallerApplet"}, - {10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"}, - {11, nullptr, "ReleaseForegroundRights"}, - {12, nullptr, "RejectToChangeIntoBackground"}, - {20, nullptr, "SetAppletWindowVisibility"}, - {21, nullptr, "SetAppletGpuTimeSlice"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IWindowController::~IWindowController() = default; - -void IWindowController::GetAppletResourceUserId(HLERequestContext& ctx) { - const u64 process_id = system.ApplicationProcess()->GetProcessId(); - - LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push<u64>(process_id); -} - -void IWindowController::GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx) { - const u64 process_id = 0; - - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push<u64>(process_id); -} - -void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -IAudioController::IAudioController(Core::System& system_) - : ServiceFramework{system_, "IAudioController"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IAudioController::SetExpectedMasterVolume, "SetExpectedMasterVolume"}, - {1, &IAudioController::GetMainAppletExpectedMasterVolume, "GetMainAppletExpectedMasterVolume"}, - {2, &IAudioController::GetLibraryAppletExpectedMasterVolume, "GetLibraryAppletExpectedMasterVolume"}, - {3, &IAudioController::ChangeMainAppletMasterVolume, "ChangeMainAppletMasterVolume"}, - {4, &IAudioController::SetTransparentAudioRate, "SetTransparentVolumeRate"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IAudioController::~IAudioController() = default; - -void IAudioController::SetExpectedMasterVolume(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const float main_applet_volume_tmp = rp.Pop<float>(); - const float library_applet_volume_tmp = rp.Pop<float>(); - - LOG_DEBUG(Service_AM, "called. main_applet_volume={}, library_applet_volume={}", - main_applet_volume_tmp, library_applet_volume_tmp); - - // Ensure the volume values remain within the 0-100% range - main_applet_volume = std::clamp(main_applet_volume_tmp, min_allowed_volume, max_allowed_volume); - library_applet_volume = - std::clamp(library_applet_volume_tmp, min_allowed_volume, max_allowed_volume); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IAudioController::GetMainAppletExpectedMasterVolume(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called. main_applet_volume={}", main_applet_volume); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(main_applet_volume); -} - -void IAudioController::GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called. library_applet_volume={}", library_applet_volume); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(library_applet_volume); -} - -void IAudioController::ChangeMainAppletMasterVolume(HLERequestContext& ctx) { - struct Parameters { - float volume; - s64 fade_time_ns; - }; - static_assert(sizeof(Parameters) == 16); - - IPC::RequestParser rp{ctx}; - const auto parameters = rp.PopRaw<Parameters>(); - - LOG_DEBUG(Service_AM, "called. volume={}, fade_time_ns={}", parameters.volume, - parameters.fade_time_ns); - - main_applet_volume = std::clamp(parameters.volume, min_allowed_volume, max_allowed_volume); - fade_time_ns = std::chrono::nanoseconds{parameters.fade_time_ns}; - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IAudioController::SetTransparentAudioRate(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const float transparent_volume_rate_tmp = rp.Pop<float>(); - - LOG_DEBUG(Service_AM, "called. transparent_volume_rate={}", transparent_volume_rate_tmp); - - // Clamp volume range to 0-100%. - transparent_volume_rate = - std::clamp(transparent_volume_rate_tmp, min_allowed_volume, max_allowed_volume); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -IDisplayController::IDisplayController(Core::System& system_) - : ServiceFramework{system_, "IDisplayController"} { - // 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, &IDisplayController::GetCallerAppletCaptureImageEx, "GetCallerAppletCaptureImageEx"}, - {8, &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, nullptr, "ClearCaptureBuffer"}, - {21, nullptr, "ClearAppletTransitionBuffer"}, - {22, nullptr, "AcquireLastApplicationCaptureSharedBuffer"}, - {23, nullptr, "ReleaseLastApplicationCaptureSharedBuffer"}, - {24, &IDisplayController::AcquireLastForegroundCaptureSharedBuffer, "AcquireLastForegroundCaptureSharedBuffer"}, - {25, &IDisplayController::ReleaseLastForegroundCaptureSharedBuffer, "ReleaseLastForegroundCaptureSharedBuffer"}, - {26, &IDisplayController::AcquireCallerAppletCaptureSharedBuffer, "AcquireCallerAppletCaptureSharedBuffer"}, - {27, &IDisplayController::ReleaseCallerAppletCaptureSharedBuffer, "ReleaseCallerAppletCaptureSharedBuffer"}, - {28, nullptr, "TakeScreenShotOfOwnLayerEx"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IDisplayController::~IDisplayController() = default; - -void IDisplayController::GetCallerAppletCaptureImageEx(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(1u); - rb.Push(0); -} - -void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IDisplayController::AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(1U); - rb.Push(0); -} - -void IDisplayController::ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IDisplayController::AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(1U); - rb.Push(0); -} - -void IDisplayController::ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -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; - -ISelfController::ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_) - : ServiceFramework{system_, "ISelfController"}, nvnflinger{nvnflinger_}, - service_context{system, "ISelfController"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &ISelfController::Exit, "Exit"}, - {1, &ISelfController::LockExit, "LockExit"}, - {2, &ISelfController::UnlockExit, "UnlockExit"}, - {3, &ISelfController::EnterFatalSection, "EnterFatalSection"}, - {4, &ISelfController::LeaveFatalSection, "LeaveFatalSection"}, - {9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"}, - {10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"}, - {11, &ISelfController::SetOperationModeChangedNotification, "SetOperationModeChangedNotification"}, - {12, &ISelfController::SetPerformanceModeChangedNotification, "SetPerformanceModeChangedNotification"}, - {13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"}, - {14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"}, - {15, nullptr, "SetScreenShotAppletIdentityInfo"}, - {16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"}, - {17, nullptr, "SetControllerFirmwareUpdateSection"}, - {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"}, - {19, &ISelfController::SetAlbumImageOrientation, "SetAlbumImageOrientation"}, - {20, nullptr, "SetDesirableKeyboardLayout"}, - {21, nullptr, "GetScreenShotProgramId"}, - {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"}, - {41, &ISelfController::IsSystemBufferSharingEnabled, "IsSystemBufferSharingEnabled"}, - {42, &ISelfController::GetSystemSharedLayerHandle, "GetSystemSharedLayerHandle"}, - {43, &ISelfController::GetSystemSharedBufferHandle, "GetSystemSharedBufferHandle"}, - {44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"}, - {45, nullptr, "SetManagedDisplayLayerSeparationMode"}, - {46, nullptr, "SetRecordingLayerCompositionEnabled"}, - {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"}, - {51, &ISelfController::ApproveToDisplay, "ApproveToDisplay"}, - {60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"}, - {61, nullptr, "SetMediaPlaybackState"}, - {62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"}, - {63, &ISelfController::GetIdleTimeDetectionExtension, "GetIdleTimeDetectionExtension"}, - {64, nullptr, "SetInputDetectionSourceSet"}, - {65, &ISelfController::ReportUserIsActive, "ReportUserIsActive"}, - {66, nullptr, "GetCurrentIlluminance"}, - {67, nullptr, "IsIlluminanceAvailable"}, - {68, &ISelfController::SetAutoSleepDisabled, "SetAutoSleepDisabled"}, - {69, &ISelfController::IsAutoSleepDisabled, "IsAutoSleepDisabled"}, - {70, nullptr, "ReportMultimediaError"}, - {71, nullptr, "GetCurrentIlluminanceEx"}, - {72, nullptr, "SetInputDetectionPolicy"}, - {80, nullptr, "SetWirelessPriorityMode"}, - {90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"}, - {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"}, - {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"}, - {110, nullptr, "SetApplicationAlbumUserData"}, - {120, &ISelfController::SaveCurrentScreenshot, "SaveCurrentScreenshot"}, - {130, &ISelfController::SetRecordVolumeMuted, "SetRecordVolumeMuted"}, - {1000, nullptr, "GetDebugStorageChannel"}, - }; - // clang-format on - - RegisterHandlers(functions); - - launchable_event = service_context.CreateEvent("ISelfController:LaunchableEvent"); - - // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is - // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple - // ISelfControllers. The event is signaled on creation, and on transition from suspended -> not - // suspended if the event has previously been created by a call to - // GetAccumulatedSuspendedTickChangedEvent. - - accumulated_suspended_tick_changed_event = - service_context.CreateEvent("ISelfController:AccumulatedSuspendedTickChangedEvent"); - accumulated_suspended_tick_changed_event->Signal(); -} - -ISelfController::~ISelfController() { - service_context.CloseEvent(launchable_event); - service_context.CloseEvent(accumulated_suspended_tick_changed_event); -} - -void ISelfController::Exit(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - - system.Exit(); -} - -void ISelfController::LockExit(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - system.SetExitLocked(true); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::UnlockExit(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - system.SetExitLocked(false); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - - if (system.GetExitRequested()) { - system.Exit(); - } -} - -void ISelfController::EnterFatalSection(HLERequestContext& ctx) { - ++num_fatal_sections_entered; - LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", num_fatal_sections_entered); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::LeaveFatalSection(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called."); - - // Entry and exit of fatal sections must be balanced. - if (num_fatal_sections_entered == 0) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(Result{ErrorModule::AM, 512}); - return; - } - - --num_fatal_sections_entered; - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::GetLibraryAppletLaunchableEvent(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - launchable_event->Signal(); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(launchable_event->GetReadableEvent()); -} - -void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto permission = rp.PopEnum<ScreenshotPermission>(); - LOG_DEBUG(Service_AM, "called, permission={}", permission); - - screenshot_permission = permission; - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - bool flag = rp.Pop<bool>(); - LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SetPerformanceModeChangedNotification(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - bool flag = rp.Pop<bool>(); - LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SetFocusHandlingMode(HLERequestContext& ctx) { - // Takes 3 input u8s with each field located immediately after the previous - // u8, these are bool flags. No output. - IPC::RequestParser rp{ctx}; - - struct FocusHandlingModeParams { - u8 unknown0; - u8 unknown1; - u8 unknown2; - }; - const auto flags = rp.PopRaw<FocusHandlingModeParams>(); - - LOG_WARNING(Service_AM, "(STUBBED) called. unknown0={}, unknown1={}, unknown2={}", - flags.unknown0, flags.unknown1, flags.unknown2); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SetRestartMessageEnabled(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx) { - // Takes 3 input u8s with each field located immediately after the previous - // u8, these are bool flags. No output. - IPC::RequestParser rp{ctx}; - - bool enabled = rp.Pop<bool>(); - LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SetAlbumImageOrientation(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - // TODO(Subv): Find out how AM determines the display to use, for now just - // create the layer in the Default display. - const auto display_id = nvnflinger.OpenDisplay("Default"); - const auto layer_id = nvnflinger.CreateLayer(*display_id); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(*layer_id); -} - -void ISelfController::IsSystemBufferSharingEnabled(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(this->EnsureBufferSharingEnabled()); -} - -void ISelfController::GetSystemSharedLayerHandle(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(this->EnsureBufferSharingEnabled()); - rb.Push<s64>(system_shared_buffer_id); - rb.Push<s64>(system_shared_layer_id); -} - -void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(this->EnsureBufferSharingEnabled()); - rb.Push<s64>(system_shared_buffer_id); -} - -Result ISelfController::EnsureBufferSharingEnabled() { - if (buffer_sharing_enabled) { - return ResultSuccess; - } - - if (system.GetAppletManager().GetCurrentAppletId() <= Applets::AppletId::Application) { - return VI::ResultOperationFailed; - } - - const auto display_id = nvnflinger.OpenDisplay("Default"); - const auto result = nvnflinger.GetSystemBufferManager().Initialize( - &system_shared_buffer_id, &system_shared_layer_id, *display_id); - - if (result.IsSuccess()) { - buffer_sharing_enabled = true; - } - - return result; -} - -void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - // TODO(Subv): Find out how AM determines the display to use, for now just - // create the layer in the Default display. - // This calls nn::vi::CreateRecordingLayer() which creates another layer. - // Currently we do not support more than 1 layer per display, output 1 layer id for now. - // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse - // side effects. - // TODO: Support multiple layers - const auto display_id = nvnflinger.OpenDisplay("Default"); - const auto layer_id = nvnflinger.CreateLayer(*display_id); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(*layer_id); -} - -void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::ApproveToDisplay(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - idle_time_detection_extension = rp.Pop<u32>(); - LOG_DEBUG(Service_AM, "(STUBBED) called idle_time_detection_extension={}", - idle_time_detection_extension); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::GetIdleTimeDetectionExtension(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u32>(idle_time_detection_extension); -} - -void ISelfController::ReportUserIsActive(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - is_auto_sleep_disabled = rp.Pop<bool>(); - - // 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(). - - LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", is_auto_sleep_disabled); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::IsAutoSleepDisabled(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called."); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(is_auto_sleep_disabled); -} - -void ISelfController::GetAccumulatedSuspendedTickValue(HLERequestContext& ctx) { - 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. - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push<u64>(0); -} - -void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called."); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent()); -} - -void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - // 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. - const bool album_image_taken_notification_enabled = rp.Pop<bool>(); - - LOG_WARNING(Service_AM, "(STUBBED) called. album_image_taken_notification_enabled={}", - album_image_taken_notification_enabled); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto report_option = rp.PopEnum<Capture::AlbumReportOption>(); - - LOG_INFO(Service_AM, "called, report_option={}", report_option); - - const auto screenshot_service = - system.ServiceManager().GetService<Service::Capture::IScreenShotApplicationService>( - "caps:su"); - - if (screenshot_service) { - screenshot_service->CaptureAndSaveScreenshot(report_option); - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ISelfController::SetRecordVolumeMuted(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto is_record_volume_muted = rp.Pop<bool>(); - - LOG_WARNING(Service_AM, "(STUBBED) called. is_record_volume_muted={}", is_record_volume_muted); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -AppletMessageQueue::AppletMessageQueue(Core::System& system) - : service_context{system, "AppletMessageQueue"} { - on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived"); - on_operation_mode_changed = service_context.CreateEvent("AMMessageQueue:OperationModeChanged"); -} - -AppletMessageQueue::~AppletMessageQueue() { - service_context.CloseEvent(on_new_message); - service_context.CloseEvent(on_operation_mode_changed); -} - -Kernel::KReadableEvent& AppletMessageQueue::GetMessageReceiveEvent() { - return on_new_message->GetReadableEvent(); -} - -Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() { - return on_operation_mode_changed->GetReadableEvent(); -} - -void AppletMessageQueue::PushMessage(AppletMessage msg) { - messages.push(msg); - on_new_message->Signal(); -} - -AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { - if (messages.empty()) { - on_new_message->Clear(); - return AppletMessage::None; - } - auto msg = messages.front(); - messages.pop(); - if (messages.empty()) { - on_new_message->Clear(); - } - return msg; -} - -std::size_t AppletMessageQueue::GetMessageCount() const { - return messages.size(); -} - -void AppletMessageQueue::RequestExit() { - PushMessage(AppletMessage::Exit); -} - -void AppletMessageQueue::RequestResume() { - PushMessage(AppletMessage::Resume); -} - -void AppletMessageQueue::FocusStateChanged() { - PushMessage(AppletMessage::FocusStateChanged); -} - -void AppletMessageQueue::OperationModeChanged() { - PushMessage(AppletMessage::OperationModeChanged); - PushMessage(AppletMessage::PerformanceModeChanged); - on_operation_mode_changed->Signal(); -} - -ILockAccessor::ILockAccessor(Core::System& system_) - : ServiceFramework{system_, "ILockAccessor"}, service_context{system_, "ILockAccessor"} { - // clang-format off - static const FunctionInfo functions[] = { - {1, &ILockAccessor::TryLock, "TryLock"}, - {2, &ILockAccessor::Unlock, "Unlock"}, - {3, &ILockAccessor::GetEvent, "GetEvent"}, - {4,&ILockAccessor::IsLocked, "IsLocked"}, - }; - // clang-format on - - RegisterHandlers(functions); - - lock_event = service_context.CreateEvent("ILockAccessor::LockEvent"); -} - -ILockAccessor::~ILockAccessor() { - service_context.CloseEvent(lock_event); -}; - -void ILockAccessor::TryLock(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto return_handle = rp.Pop<bool>(); - - LOG_WARNING(Service_AM, "(STUBBED) called, return_handle={}", return_handle); - - // TODO: When return_handle is true this function should return the lock handle - - is_locked = true; - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u8>(is_locked); -} - -void ILockAccessor::Unlock(HLERequestContext& ctx) { - LOG_INFO(Service_AM, "called"); - - is_locked = false; - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ILockAccessor::GetEvent(HLERequestContext& ctx) { - LOG_INFO(Service_AM, "called"); - - lock_event->Signal(); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(lock_event->GetReadableEvent()); -} - -void ILockAccessor::IsLocked(HLERequestContext& ctx) { - LOG_INFO(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - rb.Push<u8>(is_locked); -} - -ICommonStateGetter::ICommonStateGetter(Core::System& system_, - std::shared_ptr<AppletMessageQueue> msg_queue_) - : ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)}, - service_context{system_, "ICommonStateGetter"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, - {1, &ICommonStateGetter::ReceiveMessage, "ReceiveMessage"}, - {2, nullptr, "GetThisAppletKind"}, - {3, nullptr, "AllowToEnterSleep"}, - {4, nullptr, "DisallowToEnterSleep"}, - {5, &ICommonStateGetter::GetOperationMode, "GetOperationMode"}, - {6, &ICommonStateGetter::GetPerformanceMode, "GetPerformanceMode"}, - {7, nullptr, "GetCradleStatus"}, - {8, &ICommonStateGetter::GetBootMode, "GetBootMode"}, - {9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"}, - {10, &ICommonStateGetter::RequestToAcquireSleepLock, "RequestToAcquireSleepLock"}, - {11, nullptr, "ReleaseSleepLock"}, - {12, nullptr, "ReleaseSleepLockTransiently"}, - {13, &ICommonStateGetter::GetAcquiredSleepLockEvent, "GetAcquiredSleepLockEvent"}, - {14, nullptr, "GetWakeupCount"}, - {20, nullptr, "PushToGeneralChannel"}, - {30, nullptr, "GetHomeButtonReaderLockAccessor"}, - {31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"}, - {32, nullptr, "GetWriterLockAccessorEx"}, - {40, nullptr, "GetCradleFwVersion"}, - {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"}, - {51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"}, - {52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"}, - {53, &ICommonStateGetter::BeginVrModeEx, "BeginVrModeEx"}, - {54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"}, - {55, nullptr, "IsInControllerFirmwareUpdateSection"}, - {59, nullptr, "SetVrPositionForDebug"}, - {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"}, - {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"}, - {62, nullptr, "GetHdcpAuthenticationState"}, - {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"}, - {64, nullptr, "SetTvPowerStateMatchingMode"}, - {65, nullptr, "GetApplicationIdByContentActionName"}, - {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"}, - {67, nullptr, "CancelCpuBoostMode"}, - {68, &ICommonStateGetter::GetBuiltInDisplayType, "GetBuiltInDisplayType"}, - {80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"}, - {90, nullptr, "SetPerformanceConfigurationChangedNotification"}, - {91, nullptr, "GetCurrentPerformanceConfiguration"}, - {100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"}, - {110, nullptr, "OpenMyGpuErrorHandler"}, - {120, nullptr, "GetAppletLaunchedHistory"}, - {200, nullptr, "GetOperationModeSystemInfo"}, - {300, &ICommonStateGetter::GetSettingsPlatformRegion, "GetSettingsPlatformRegion"}, - {400, nullptr, "ActivateMigrationService"}, - {401, nullptr, "DeactivateMigrationService"}, - {500, nullptr, "DisableSleepTillShutdown"}, - {501, nullptr, "SuppressDisablingSleepTemporarily"}, - {502, nullptr, "IsSleepEnabled"}, - {503, nullptr, "IsDisablingSleepSuppressed"}, - {900, &ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"}, - }; - // clang-format on - - RegisterHandlers(functions); - - sleep_lock_event = service_context.CreateEvent("ICommonStateGetter::SleepLockEvent"); - - // Configure applets to be in foreground state - msg_queue->PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); - msg_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); -} - -ICommonStateGetter::~ICommonStateGetter() { - service_context.CloseEvent(sleep_lock_event); -}; - -void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode -} - -void ICommonStateGetter::GetEventHandle(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(msg_queue->GetMessageReceiveEvent()); -} - -void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - const auto message = msg_queue->PopMessage(); - IPC::ResponseBuilder rb{ctx, 3}; - - if (message == AppletMessageQueue::AppletMessage::None) { - LOG_ERROR(Service_AM, "Message queue is empty"); - rb.Push(AM::ResultNoMessages); - rb.PushEnum<AppletMessageQueue::AppletMessage>(message); - return; - } - - rb.Push(ResultSuccess); - rb.PushEnum<AppletMessageQueue::AppletMessage>(message); -} - -void ICommonStateGetter::GetCurrentFocusState(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast<u8>(FocusState::InFocus)); -} - -void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - // Sleep lock is acquired immediately. - sleep_lock_event->Signal(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ICommonStateGetter::GetReaderLockAccessorEx(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto unknown = rp.Pop<u32>(); - - LOG_INFO(Service_AM, "called, unknown={}", unknown); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - - rb.Push(ResultSuccess); - rb.PushIpcInterface<ILockAccessor>(system); -} - -void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(sleep_lock_event->GetReadableEvent()); -} - -void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(vr_mode_state); -} - -void ICommonStateGetter::SetVrModeEnabled(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - vr_mode_state = rp.Pop<bool>(); - - LOG_WARNING(Service_AM, "VR Mode is {}", vr_mode_state ? "on" : "off"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ICommonStateGetter::SetLcdBacklighOffEnabled(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto is_lcd_backlight_off_enabled = rp.Pop<bool>(); - - LOG_WARNING(Service_AM, "(STUBBED) called. is_lcd_backlight_off_enabled={}", - is_lcd_backlight_off_enabled); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ICommonStateGetter::BeginVrModeEx(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ICommonStateGetter::EndVrModeEx(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent()); -} - -void ICommonStateGetter::GetDefaultDisplayResolution(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - - if (Settings::IsDockedMode()) { - rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); - rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); - } else { - rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); - rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight)); - } -} - -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); -} - -void ICommonStateGetter::GetBuiltInDisplayType(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(0); -} - -void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto system_button{rp.PopEnum<SystemButtonType>()}; - - LOG_WARNING(Service_AM, "(STUBBED) called, system_button={}", system_button); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ICommonStateGetter::GetSettingsPlatformRegion(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(SysPlatformRegion::Global); -} - -void ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled( - HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -IStorageImpl::~IStorageImpl() = default; - -class StorageDataImpl final : public IStorageImpl { -public: - explicit StorageDataImpl(std::vector<u8>&& buffer_) : buffer{std::move(buffer_)} {} - - std::vector<u8>& GetData() override { - return buffer; - } - - const std::vector<u8>& GetData() const override { - return buffer; - } - - std::size_t GetSize() const override { - return buffer.size(); - } - -private: - std::vector<u8> buffer; -}; - -IStorage::IStorage(Core::System& system_, std::vector<u8>&& buffer) - : ServiceFramework{system_, "IStorage"}, impl{std::make_shared<StorageDataImpl>( - std::move(buffer))} { - Register(); -} - -void IStorage::Register() { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IStorage::Open, "Open"}, - {1, nullptr, "OpenTransferStorage"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IStorage::~IStorage() = default; - -void IStorage::Open(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - - rb.Push(ResultSuccess); - rb.PushIpcInterface<IStorageAccessor>(system, *this); -} - -void ICommonStateGetter::GetOperationMode(HLERequestContext& ctx) { - const bool use_docked_mode{Settings::IsDockedMode()}; - LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld)); -} - -void ICommonStateGetter::GetPerformanceMode(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(system.GetAPMController().GetCurrentPerformanceMode()); -} - -class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { -public: - explicit ILibraryAppletAccessor(Core::System& system_, std::shared_ptr<Applets::Applet> applet_) - : ServiceFramework{system_, "ILibraryAppletAccessor"}, applet{std::move(applet_)} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, - {1, &ILibraryAppletAccessor::IsCompleted, "IsCompleted"}, - {10, &ILibraryAppletAccessor::Start, "Start"}, - {20, &ILibraryAppletAccessor::RequestExit, "RequestExit"}, - {25, nullptr, "Terminate"}, - {30, &ILibraryAppletAccessor::GetResult, "GetResult"}, - {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, - {60, &ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero, "PresetLibraryAppletGpuTimeSliceZero"}, - {100, &ILibraryAppletAccessor::PushInData, "PushInData"}, - {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"}, - {102, nullptr, "PushExtraStorage"}, - {103, &ILibraryAppletAccessor::PushInteractiveInData, "PushInteractiveInData"}, - {104, &ILibraryAppletAccessor::PopInteractiveOutData, "PopInteractiveOutData"}, - {105, &ILibraryAppletAccessor::GetPopOutDataEvent, "GetPopOutDataEvent"}, - {106, &ILibraryAppletAccessor::GetPopInteractiveOutDataEvent, "GetPopInteractiveOutDataEvent"}, - {110, nullptr, "NeedsToExitProcess"}, - {120, nullptr, "GetLibraryAppletInfo"}, - {150, nullptr, "RequestForAppletToGetForeground"}, - {160, &ILibraryAppletAccessor::GetIndirectLayerConsumerHandle, "GetIndirectLayerConsumerHandle"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - -private: - void GetAppletStateChangedEvent(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(applet->GetBroker().GetStateChangedEvent()); - } - - void IsCompleted(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u32>(applet->TransactionComplete()); - } - - void GetResult(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(applet->GetStatus()); - } - - void PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void Start(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - ASSERT(applet != nullptr); - - applet->Initialize(); - applet->Execute(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void RequestExit(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - ASSERT(applet != nullptr); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(applet->RequestExit()); - } - - void PushInData(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::RequestParser rp{ctx}; - applet->GetBroker().PushNormalDataFromGame(rp.PopIpcInterface<IStorage>().lock()); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void PopOutData(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - auto storage = applet->GetBroker().PopNormalDataToGame(); - if (storage == nullptr) { - LOG_DEBUG(Service_AM, - "storage is a nullptr. There is no data in the current normal channel"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultNoDataInChannel); - return; - } - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IStorage>(std::move(storage)); - } - - void PushInteractiveInData(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::RequestParser rp{ctx}; - applet->GetBroker().PushInteractiveDataFromGame(rp.PopIpcInterface<IStorage>().lock()); - - ASSERT(applet->IsInitialized()); - applet->ExecuteInteractive(); - applet->Execute(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void PopInteractiveOutData(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - auto storage = applet->GetBroker().PopInteractiveDataToGame(); - if (storage == nullptr) { - LOG_DEBUG(Service_AM, - "storage is a nullptr. There is no data in the current interactive channel"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultNoDataInChannel); - return; - } - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IStorage>(std::move(storage)); - } - - void GetPopOutDataEvent(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent()); - } - - void GetPopInteractiveOutDataEvent(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent()); - } - - void GetIndirectLayerConsumerHandle(HLERequestContext& ctx) { - 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 - constexpr u64 handle = 0xdeadbeef; - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(handle); - } - - std::shared_ptr<Applets::Applet> applet; -}; - -IStorageAccessor::IStorageAccessor(Core::System& system_, IStorage& backing_) - : ServiceFramework{system_, "IStorageAccessor"}, backing{backing_} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IStorageAccessor::GetSize, "GetSize"}, - {10, &IStorageAccessor::Write, "Write"}, - {11, &IStorageAccessor::Read, "Read"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IStorageAccessor::~IStorageAccessor() = default; - -void IStorageAccessor::GetSize(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 4}; - - rb.Push(ResultSuccess); - rb.Push(static_cast<u64>(backing.GetSize())); -} - -void IStorageAccessor::Write(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const u64 offset{rp.Pop<u64>()}; - const auto data{ctx.ReadBuffer()}; - const std::size_t size{std::min<u64>(data.size(), backing.GetSize() - offset)}; - - LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); - - if (offset > backing.GetSize()) { - LOG_ERROR(Service_AM, - "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", - backing.GetSize(), size, offset); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultInvalidOffset); - return; - } - - std::memcpy(backing.GetData().data() + offset, data.data(), size); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IStorageAccessor::Read(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const u64 offset{rp.Pop<u64>()}; - const std::size_t size{std::min<u64>(ctx.GetWriteBufferSize(), backing.GetSize() - offset)}; - - LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); - - if (offset > backing.GetSize()) { - LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", - backing.GetSize(), size, offset); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultInvalidOffset); - return; - } - - ctx.WriteBuffer(backing.GetData().data() + offset, size); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_) - : ServiceFramework{system_, "ILibraryAppletCreator"} { - static const FunctionInfo functions[] = { - {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"}, - {1, nullptr, "TerminateAllLibraryApplets"}, - {2, nullptr, "AreAnyLibraryAppletsLeft"}, - {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"}, - {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"}, - {12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"}, - }; - RegisterHandlers(functions); -} - -ILibraryAppletCreator::~ILibraryAppletCreator() = default; - -void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto applet_id = rp.PopRaw<Applets::AppletId>(); - const auto applet_mode = rp.PopRaw<Applets::LibraryAppletMode>(); - - LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, - applet_mode); - - const auto& applet_manager{system.GetAppletManager()}; - const auto applet = applet_manager.GetApplet(applet_id, applet_mode); - - if (applet == nullptr) { - LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; - } - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - - rb.Push(ResultSuccess); - rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet); -} - -void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const s64 size{rp.Pop<s64>()}; - - LOG_DEBUG(Service_AM, "called, size={}", size); - - if (size <= 0) { - LOG_ERROR(Service_AM, "size is less than or equal to 0"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; - } - - std::vector<u8> buffer(size); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IStorage>(system, std::move(buffer)); -} - -void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - struct Parameters { - u8 permissions; - s64 size; - }; - - const auto parameters{rp.PopRaw<Parameters>()}; - const auto handle{ctx.GetCopyHandle(0)}; - - LOG_DEBUG(Service_AM, "called, permissions={}, size={}, handle={:08X}", parameters.permissions, - parameters.size, handle); - - if (parameters.size <= 0) { - LOG_ERROR(Service_AM, "size is less than or equal to 0"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; - } - - auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle); - - if (transfer_mem.IsNull()) { - LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; - } - - std::vector<u8> memory(transfer_mem->GetSize()); - ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size()); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IStorage>(system, std::move(memory)); -} - -void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const s64 size{rp.Pop<s64>()}; - const auto handle{ctx.GetCopyHandle(0)}; - - LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle); - - if (size <= 0) { - LOG_ERROR(Service_AM, "size is less than or equal to 0"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; - } - - auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle); - - if (transfer_mem.IsNull()) { - LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; - } - - std::vector<u8> memory(transfer_mem->GetSize()); - ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size()); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IStorage>(system, std::move(memory)); -} - -ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_) - : ServiceFramework{system_, "ILibraryAppletSelfAccessor"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &ILibraryAppletSelfAccessor::PopInData, "PopInData"}, - {1, &ILibraryAppletSelfAccessor::PushOutData, "PushOutData"}, - {2, nullptr, "PopInteractiveInData"}, - {3, nullptr, "PushInteractiveOutData"}, - {5, nullptr, "GetPopInDataEvent"}, - {6, nullptr, "GetPopInteractiveInDataEvent"}, - {10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"}, - {11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"}, - {12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"}, - {13, nullptr, "CanUseApplicationCore"}, - {14, &ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo, "GetCallerAppletIdentityInfo"}, - {15, nullptr, "GetMainAppletApplicationControlProperty"}, - {16, nullptr, "GetMainAppletStorageId"}, - {17, nullptr, "GetCallerAppletIdentityInfoStack"}, - {18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"}, - {19, &ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout, "GetDesirableKeyboardLayout"}, - {20, nullptr, "PopExtraStorage"}, - {25, nullptr, "GetPopExtraStorageEvent"}, - {30, nullptr, "UnpopInData"}, - {31, nullptr, "UnpopExtraStorage"}, - {40, nullptr, "GetIndirectLayerProducerHandle"}, - {50, nullptr, "ReportVisibleError"}, - {51, nullptr, "ReportVisibleErrorWithErrorContext"}, - {60, nullptr, "GetMainAppletApplicationDesiredLanguage"}, - {70, nullptr, "GetCurrentApplicationId"}, - {80, nullptr, "RequestExitToSelf"}, - {90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"}, - {100, nullptr, "CreateGameMovieTrimmer"}, - {101, nullptr, "ReserveResourceForMovieOperation"}, - {102, nullptr, "UnreserveResourceForMovieOperation"}, - {110, &ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers, "GetMainAppletAvailableUsers"}, - {120, nullptr, "GetLaunchStorageInfoForDebug"}, - {130, nullptr, "GetGpuErrorDetectedSystemEvent"}, - {140, nullptr, "SetApplicationMemoryReservation"}, - {150, &ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually, "ShouldSetGpuTimeSliceManually"}, - }; - // clang-format on - RegisterHandlers(functions); - - switch (system.GetAppletManager().GetCurrentAppletId()) { - case Applets::AppletId::Cabinet: - PushInShowCabinetData(); - break; - case Applets::AppletId::MiiEdit: - PushInShowMiiEditData(); - break; - case Applets::AppletId::PhotoViewer: - PushInShowAlbum(); - break; - case Applets::AppletId::SoftwareKeyboard: - PushInShowSoftwareKeyboard(); - break; - case Applets::AppletId::Controller: - PushInShowController(); - break; - default: - break; - } -} - -ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default; -void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) { - LOG_INFO(Service_AM, "called"); - - if (queue_data.empty()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultNoDataInChannel); - return; - } - - auto data = queue_data.front(); - queue_data.pop_front(); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IStorage>(system, std::move(data)); -} - -void ILibraryAppletSelfAccessor::PushOutData(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - system.Exit(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) { - struct LibraryAppletInfo { - Applets::AppletId applet_id; - Applets::LibraryAppletMode library_applet_mode; - }; - - LOG_WARNING(Service_AM, "(STUBBED) called"); - - const LibraryAppletInfo applet_info{ - .applet_id = system.GetAppletManager().GetCurrentAppletId(), - .library_applet_mode = Applets::LibraryAppletMode::AllForeground, - }; - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.PushRaw(applet_info); -} - -void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) { - struct AppletIdentityInfo { - Applets::AppletId applet_id; - INSERT_PADDING_BYTES(0x4); - u64 application_id; - }; - static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); - - LOG_WARNING(Service_AM, "(STUBBED) called"); - - const AppletIdentityInfo applet_info{ - .applet_id = Applets::AppletId::QLaunch, - .application_id = 0x0100000000001000ull, - }; - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - rb.PushRaw(applet_info); -} - -void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) { - struct AppletIdentityInfo { - Applets::AppletId applet_id; - INSERT_PADDING_BYTES(0x4); - u64 application_id; - }; - static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); - LOG_WARNING(Service_AM, "(STUBBED) called"); - - const AppletIdentityInfo applet_info{ - .applet_id = Applets::AppletId::QLaunch, - .application_id = 0x0100000000001000ull, - }; - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - rb.PushRaw(applet_info); -} - -void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u32>(0); -} - -void ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(HLERequestContext& ctx) { - const Service::Account::ProfileManager manager{}; - bool is_empty{true}; - s32 user_count{-1}; - - LOG_INFO(Service_AM, "called"); - - if (manager.GetUserCount() > 0) { - is_empty = false; - user_count = static_cast<s32>(manager.GetUserCount()); - ctx.WriteBuffer(manager.GetAllUsers()); - } - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push<u8>(is_empty); - rb.Push(user_count); -} - -void ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - rb.Push<u8>(0); -} - -void ILibraryAppletSelfAccessor::PushInShowAlbum() { - const Applets::CommonArguments arguments{ - .arguments_version = Applets::CommonArgumentVersion::Version3, - .size = Applets::CommonArgumentSize::Version3, - .library_version = 1, - .theme_color = Applets::ThemeColor::BasicBlack, - .play_startup_sound = true, - .system_tick = system.CoreTiming().GetClockTicks(), - }; - - std::vector<u8> argument_data(sizeof(arguments)); - std::vector<u8> settings_data{2}; - std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); - queue_data.emplace_back(std::move(argument_data)); - queue_data.emplace_back(std::move(settings_data)); -} - -void ILibraryAppletSelfAccessor::PushInShowController() { - const Applets::CommonArguments common_args = { - .arguments_version = Applets::CommonArgumentVersion::Version3, - .size = Applets::CommonArgumentSize::Version3, - .library_version = static_cast<u32>(Applets::ControllerAppletVersion::Version8), - .theme_color = Applets::ThemeColor::BasicBlack, - .play_startup_sound = true, - .system_tick = system.CoreTiming().GetClockTicks(), - }; - - Applets::ControllerSupportArgNew user_args = { - .header = {.player_count_min = 1, - .player_count_max = 4, - .enable_take_over_connection = true, - .enable_left_justify = false, - .enable_permit_joy_dual = true, - .enable_single_mode = false, - .enable_identification_color = false}, - .identification_colors = {}, - .enable_explain_text = false, - .explain_text = {}, - }; - - Applets::ControllerSupportArgPrivate private_args = { - .arg_private_size = sizeof(Applets::ControllerSupportArgPrivate), - .arg_size = sizeof(Applets::ControllerSupportArgNew), - .is_home_menu = true, - .flag_1 = true, - .mode = Applets::ControllerSupportMode::ShowControllerSupport, - .caller = Applets::ControllerSupportCaller:: - Application, // switchbrew: Always zero except with - // ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem, - // which sets this to the input param - .style_set = Core::HID::NpadStyleSet::None, - .joy_hold_type = 0, - }; - std::vector<u8> common_args_data(sizeof(common_args)); - std::vector<u8> private_args_data(sizeof(private_args)); - std::vector<u8> user_args_data(sizeof(user_args)); - - std::memcpy(common_args_data.data(), &common_args, sizeof(common_args)); - std::memcpy(private_args_data.data(), &private_args, sizeof(private_args)); - std::memcpy(user_args_data.data(), &user_args, sizeof(user_args)); - - queue_data.emplace_back(std::move(common_args_data)); - queue_data.emplace_back(std::move(private_args_data)); - queue_data.emplace_back(std::move(user_args_data)); -} - -void ILibraryAppletSelfAccessor::PushInShowCabinetData() { - const Applets::CommonArguments arguments{ - .arguments_version = Applets::CommonArgumentVersion::Version3, - .size = Applets::CommonArgumentSize::Version3, - .library_version = static_cast<u32>(Applets::CabinetAppletVersion::Version1), - .theme_color = Applets::ThemeColor::BasicBlack, - .play_startup_sound = true, - .system_tick = system.CoreTiming().GetClockTicks(), - }; - - const Applets::StartParamForAmiiboSettings amiibo_settings{ - .param_1 = 0, - .applet_mode = system.GetAppletManager().GetCabinetMode(), - .flags = Applets::CabinetFlags::None, - .amiibo_settings_1 = 0, - .device_handle = 0, - .tag_info{}, - .register_info{}, - .amiibo_settings_3{}, - }; - - std::vector<u8> argument_data(sizeof(arguments)); - std::vector<u8> settings_data(sizeof(amiibo_settings)); - std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); - std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings)); - queue_data.emplace_back(std::move(argument_data)); - queue_data.emplace_back(std::move(settings_data)); -} - -void ILibraryAppletSelfAccessor::PushInShowMiiEditData() { - struct MiiEditV3 { - Applets::MiiEditAppletInputCommon common; - Applets::MiiEditAppletInputV3 input; - }; - static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size."); - - MiiEditV3 mii_arguments{ - .common = - { - .version = Applets::MiiEditAppletVersion::Version3, - .applet_mode = Applets::MiiEditAppletMode::ShowMiiEdit, - }, - .input{}, - }; - - std::vector<u8> argument_data(sizeof(mii_arguments)); - std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments)); - - queue_data.emplace_back(std::move(argument_data)); -} - -void ILibraryAppletSelfAccessor::PushInShowSoftwareKeyboard() { - const Applets::CommonArguments arguments{ - .arguments_version = Applets::CommonArgumentVersion::Version3, - .size = Applets::CommonArgumentSize::Version3, - .library_version = static_cast<u32>(Applets::SwkbdAppletVersion::Version524301), - .theme_color = Applets::ThemeColor::BasicBlack, - .play_startup_sound = true, - .system_tick = system.CoreTiming().GetClockTicks(), - }; - - std::vector<char16_t> initial_string(0); - - const Applets::SwkbdConfigCommon swkbd_config{ - .type = Applets::SwkbdType::Qwerty, - .ok_text{}, - .left_optional_symbol_key{}, - .right_optional_symbol_key{}, - .use_prediction = false, - .key_disable_flags{}, - .initial_cursor_position = Applets::SwkbdInitialCursorPosition::Start, - .header_text{}, - .sub_text{}, - .guide_text{}, - .max_text_length = 500, - .min_text_length = 0, - .password_mode = Applets::SwkbdPasswordMode::Disabled, - .text_draw_type = Applets::SwkbdTextDrawType::Box, - .enable_return_button = true, - .use_utf8 = false, - .use_blur_background = true, - .initial_string_offset{}, - .initial_string_length = static_cast<u32>(initial_string.size()), - .user_dictionary_offset{}, - .user_dictionary_entries{}, - .use_text_check = false, - }; - - Applets::SwkbdConfigNew swkbd_config_new{}; - - std::vector<u8> argument_data(sizeof(arguments)); - std::vector<u8> swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new)); - std::vector<u8> work_buffer(swkbd_config.initial_string_length * sizeof(char16_t)); - - std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); - std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config)); - std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new, - sizeof(Applets::SwkbdConfigNew)); - std::memcpy(work_buffer.data(), initial_string.data(), - swkbd_config.initial_string_length * sizeof(char16_t)); - - queue_data.emplace_back(std::move(argument_data)); - queue_data.emplace_back(std::move(swkbd_data)); - queue_data.emplace_back(std::move(work_buffer)); -} - -IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_) - : ServiceFramework{system_, "IAppletCommonFunctions"} { - // 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, nullptr, "GetHomeButtonDoubleClickEnabled"}, - {52, nullptr, "IsHomeButtonShortPressedBlocked"}, - {60, nullptr, "IsVrModeCurtainRequired"}, - {61, nullptr, "IsSleepRequiredByHighTemperature"}, - {62, nullptr, "IsSleepRequiredByLowBattery"}, - {70, &IAppletCommonFunctions::SetCpuBoostRequestPriority, "SetCpuBoostRequestPriority"}, - {80, nullptr, "SetHandlingCaptureButtonShortPressedMessageEnabledForApplet"}, - {81, nullptr, "SetHandlingCaptureButtonLongPressedMessageEnabledForApplet"}, - {90, nullptr, "OpenNamedChannelAsParent"}, - {91, nullptr, "OpenNamedChannelAsChild"}, - {100, nullptr, "SetApplicationCoreUsageMode"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IAppletCommonFunctions::~IAppletCommonFunctions() = default; - -void IAppletCommonFunctions::SetCpuBoostRequestPriority(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -IApplicationFunctions::IApplicationFunctions(Core::System& system_) - : ServiceFramework{system_, "IApplicationFunctions"}, service_context{system, - "IApplicationFunctions"} { - // clang-format off - static const FunctionInfo functions[] = { - {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, - {10, nullptr, "CreateApplicationAndPushAndRequestToStart"}, - {11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"}, - {12, nullptr, "CreateApplicationAndRequestToStart"}, - {13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, "CreateApplicationAndRequestToStartForQuest"}, - {14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"}, - {15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"}, - {20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"}, - {21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"}, - {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"}, - {23, &IApplicationFunctions::GetDisplayVersion, "GetDisplayVersion"}, - {24, nullptr, "GetLaunchStorageInfoForDebug"}, - {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"}, - {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"}, - {27, &IApplicationFunctions::CreateCacheStorage, "CreateCacheStorage"}, - {28, &IApplicationFunctions::GetSaveDataSizeMax, "GetSaveDataSizeMax"}, - {29, nullptr, "GetCacheStorageMax"}, - {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"}, - {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"}, - {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"}, - {33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"}, - {34, nullptr, "SelectApplicationLicense"}, - {35, nullptr, "GetDeviceSaveDataSizeMax"}, - {36, nullptr, "GetLimitedApplicationLicense"}, - {37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"}, - {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"}, - {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"}, - {60, nullptr, "SetMediaPlaybackStateForApplication"}, - {65, &IApplicationFunctions::IsGamePlayRecordingSupported, "IsGamePlayRecordingSupported"}, - {66, &IApplicationFunctions::InitializeGamePlayRecording, "InitializeGamePlayRecording"}, - {67, &IApplicationFunctions::SetGamePlayRecordingState, "SetGamePlayRecordingState"}, - {68, nullptr, "RequestFlushGamePlayingMovieForDebug"}, - {70, nullptr, "RequestToShutdown"}, - {71, nullptr, "RequestToReboot"}, - {72, nullptr, "RequestToSleep"}, - {80, nullptr, "ExitAndRequestToShowThanksMessage"}, - {90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"}, - {100, &IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer, "InitializeApplicationCopyrightFrameBuffer"}, - {101, &IApplicationFunctions::SetApplicationCopyrightImage, "SetApplicationCopyrightImage"}, - {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"}, - {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"}, - {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"}, - {120, &IApplicationFunctions::ExecuteProgram, "ExecuteProgram"}, - {121, &IApplicationFunctions::ClearUserChannel, "ClearUserChannel"}, - {122, &IApplicationFunctions::UnpopToUserChannel, "UnpopToUserChannel"}, - {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"}, - {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, - {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, - {131, nullptr, "SetDelayTimeToAbortOnGpuError"}, - {140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"}, - {141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"}, - {150, &IApplicationFunctions::GetNotificationStorageChannelEvent, "GetNotificationStorageChannelEvent"}, - {151, nullptr, "TryPopFromNotificationStorageChannel"}, - {160, &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, &IApplicationFunctions::PrepareForJit, "PrepareForJit"}, - }; - // clang-format on - - RegisterHandlers(functions); - - gpu_error_detected_event = - service_context.CreateEvent("IApplicationFunctions:GpuErrorDetectedSystemEvent"); - friend_invitation_storage_channel_event = - service_context.CreateEvent("IApplicationFunctions:FriendInvitationStorageChannelEvent"); - notification_storage_channel_event = - service_context.CreateEvent("IApplicationFunctions:NotificationStorageChannelEvent"); - health_warning_disappeared_system_event = - service_context.CreateEvent("IApplicationFunctions:HealthWarningDisappearedSystemEvent"); -} - -IApplicationFunctions::~IApplicationFunctions() { - service_context.CloseEvent(gpu_error_detected_event); - service_context.CloseEvent(friend_invitation_storage_channel_event); - service_context.CloseEvent(notification_storage_channel_event); - service_context.CloseEvent(health_warning_disappeared_system_event); -} - -void IApplicationFunctions::EnableApplicationCrashReport(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::SetApplicationCopyrightImage(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::SetApplicationCopyrightVisibility(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto is_visible = rp.Pop<bool>(); - - LOG_WARNING(Service_AM, "(STUBBED) called, is_visible={}", is_visible); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::BeginBlockingHomeButton(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::EndBlockingHomeButton(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto kind = rp.PopEnum<LaunchParameterKind>(); - - LOG_INFO(Service_AM, "called, kind={:08X}", kind); - - if (kind == LaunchParameterKind::UserChannel) { - auto channel = system.GetUserChannel(); - if (channel.empty()) { - LOG_ERROR(Service_AM, "Attempted to load launch parameter but none was found!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultNoDataInChannel); - return; - } - - auto data = channel.back(); - channel.pop_back(); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IStorage>(system, std::move(data)); - } else if (kind == LaunchParameterKind::AccountPreselectedUser && - !launch_popped_account_preselect) { - // TODO: Verify this is hw-accurate - LaunchParameterAccountPreselectedUser params{}; - - params.magic = LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC; - params.is_account_selected = 1; - - Account::ProfileManager profile_manager{}; - const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user)); - ASSERT(uuid.has_value() && uuid->IsValid()); - params.current_user = *uuid; - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - - std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); - std::memcpy(buffer.data(), ¶ms, buffer.size()); - - rb.PushIpcInterface<IStorage>(system, std::move(buffer)); - launch_popped_account_preselect = true; - } else { - LOG_ERROR(Service_AM, "Unknown launch parameter kind."); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultNoDataInChannel); - } -} - -void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - u128 user_id = rp.PopRaw<u128>(); - - LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]); - - FileSys::SaveDataAttribute attribute{}; - attribute.title_id = system.GetApplicationProcessProgramID(); - attribute.user_id = user_id; - attribute.type = FileSys::SaveDataType::SaveData; - - FileSys::VirtualDir save_data{}; - const auto res = system.GetFileSystemController().OpenSaveDataController()->CreateSaveData( - &save_data, FileSys::SaveDataSpaceId::NandUser, attribute); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(res); - rb.Push<u64>(0); -} - -void IApplicationFunctions::SetTerminateResult(HLERequestContext& ctx) { - // Takes an input u32 Result, no output. - // For example, in some cases official apps use this with error 0x2A2 then - // uses svcBreak. - - IPC::RequestParser rp{ctx}; - u32 result = rp.Pop<u32>(); - LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::GetDisplayVersion(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - std::array<u8, 0x10> version_string{}; - - const auto res = [this] { - const auto title_id = system.GetApplicationProcessProgramID(); - - const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), - system.GetContentProvider()}; - auto metadata = pm.GetControlMetadata(); - if (metadata.first != nullptr) { - return metadata; - } - - const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), - system.GetFileSystemController(), - system.GetContentProvider()}; - return pm_update.GetControlMetadata(); - }(); - - if (res.first != nullptr) { - const auto& version = res.first->GetVersionString(); - std::copy(version.begin(), version.end(), version_string.begin()); - } else { - static constexpr char default_version[]{"1.0.0"}; - std::memcpy(version_string.data(), default_version, sizeof(default_version)); - } - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - rb.PushRaw(version_string); -} - -void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) { - // 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 auto title_id = system.GetApplicationProcessProgramID(); - - const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), - system.GetContentProvider()}; - auto metadata = pm.GetControlMetadata(); - if (metadata.first != nullptr) { - return metadata; - } - - const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_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{}; - const auto res_lang = - app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages); - if (res_lang != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res_lang); - return; - } - - // Convert to settings language code. - u64 language_code{}; - const auto res_code = - app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language); - if (res_code != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res_code); - return; - } - - LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(language_code); -} - -void IApplicationFunctions::IsGamePlayRecordingSupported(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - constexpr bool gameplay_recording_supported = false; - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(gameplay_recording_supported); -} - -void IApplicationFunctions::InitializeGamePlayRecording(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::SetGamePlayRecordingState(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::NotifyRunning(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u8>(0); // Unknown, seems to be ignored by official processes -} - -void IApplicationFunctions::GetPseudoDeviceId(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - - // Returns a 128-bit UUID - rb.Push<u64>(0); - rb.Push<u64>(0); -} - -void IApplicationFunctions::ExtendSaveData(HLERequestContext& ctx) { - struct Parameters { - FileSys::SaveDataType type; - u128 user_id; - u64 new_normal_size; - u64 new_journal_size; - }; - static_assert(sizeof(Parameters) == 40); - - IPC::RequestParser rp{ctx}; - const auto [type, user_id, new_normal_size, new_journal_size] = rp.PopRaw<Parameters>(); - - LOG_DEBUG(Service_AM, - "called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, " - "new_journal={:016X}", - static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size); - - system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize( - type, system.GetApplicationProcessProgramID(), user_id, - {new_normal_size, new_journal_size}); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - - // The following value is used upon failure to help the system recover. - // Since we always succeed, this should be 0. - rb.Push<u64>(0); -} - -void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) { - struct Parameters { - FileSys::SaveDataType type; - u128 user_id; - }; - static_assert(sizeof(Parameters) == 24); - - IPC::RequestParser rp{ctx}; - const auto [type, user_id] = rp.PopRaw<Parameters>(); - - LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1], - user_id[0]); - - const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize( - type, system.GetApplicationProcessProgramID(), user_id); - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - rb.Push(size.normal); - rb.Push(size.journal); -} - -void IApplicationFunctions::CreateCacheStorage(HLERequestContext& ctx) { - struct InputParameters { - u16 index; - s64 size; - s64 journal_size; - }; - static_assert(sizeof(InputParameters) == 24); - - struct OutputParameters { - u32 storage_target; - u64 required_size; - }; - static_assert(sizeof(OutputParameters) == 16); - - IPC::RequestParser rp{ctx}; - const auto params = rp.PopRaw<InputParameters>(); - - LOG_WARNING(Service_AM, "(STUBBED) called with index={}, size={:#x}, journal_size={:#x}", - params.index, params.size, params.journal_size); - - const OutputParameters resp{ - .storage_target = 1, - .required_size = 0, - }; - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - rb.PushRaw(resp); -} - -void IApplicationFunctions::GetSaveDataSizeMax(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - constexpr u64 size_max_normal = 0xFFFFFFF; - constexpr u64 size_max_journal = 0xFFFFFFF; - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - rb.Push(size_max_normal); - rb.Push(size_max_journal); -} - -void IApplicationFunctions::QueryApplicationPlayStatistics(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u32>(0); -} - -void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u32>(0); -} - -void IApplicationFunctions::ExecuteProgram(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::RequestParser rp{ctx}; - [[maybe_unused]] const auto unk_1 = rp.Pop<u32>(); - [[maybe_unused]] const auto unk_2 = rp.Pop<u32>(); - const auto program_index = rp.Pop<u64>(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - - system.ExecuteProgram(program_index); -} - -void IApplicationFunctions::ClearUserChannel(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - system.GetUserChannel().clear(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::UnpopToUserChannel(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::RequestParser rp{ctx}; - const auto storage = rp.PopIpcInterface<IStorage>().lock(); - if (storage) { - system.GetUserChannel().push_back(storage->GetData()); - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IApplicationFunctions::GetPreviousProgramIndex(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<s32>(previous_program_index); -} - -void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(gpu_error_detected_event->GetReadableEvent()); -} - -void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(friend_invitation_storage_channel_event->GetReadableEvent()); -} - -void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(AM::ResultNoDataInChannel); -} - -void IApplicationFunctions::GetNotificationStorageChannelEvent(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(notification_storage_channel_event->GetReadableEvent()); -} - -void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent()); -} - -void IApplicationFunctions::PrepareForJit(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { auto message_queue = std::make_shared<AppletMessageQueue>(system); auto server_manager = std::make_unique<ServerManager>(system); @@ -2550,155 +26,4 @@ void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { ServerManager::RunServer(std::move(server_manager)); } -IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_) - : ServiceFramework{system_, "IHomeMenuFunctions"}, service_context{system, - "IHomeMenuFunctions"} { - // clang-format off - static const FunctionInfo functions[] = { - {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"}, - {11, nullptr, "LockForeground"}, - {12, nullptr, "UnlockForeground"}, - {20, nullptr, "PopFromGeneralChannel"}, - {21, &IHomeMenuFunctions::GetPopFromGeneralChannelEvent, "GetPopFromGeneralChannelEvent"}, - {30, nullptr, "GetHomeButtonWriterLockAccessor"}, - {31, nullptr, "GetWriterLockAccessorEx"}, - {40, nullptr, "IsSleepEnabled"}, - {41, nullptr, "IsRebootEnabled"}, - {50, nullptr, "LaunchSystemApplet"}, - {51, nullptr, "LaunchStarter"}, - {100, nullptr, "PopRequestLaunchApplicationForDebug"}, - {110, nullptr, "IsForceTerminateApplicationDisabledForDebug"}, - {200, nullptr, "LaunchDevMenu"}, - {1000, nullptr, "SetLastApplicationExitReason"}, - }; - // clang-format on - - RegisterHandlers(functions); - - pop_from_general_channel_event = - service_context.CreateEvent("IHomeMenuFunctions:PopFromGeneralChannelEvent"); -} - -IHomeMenuFunctions::~IHomeMenuFunctions() { - service_context.CloseEvent(pop_from_general_channel_event); -} - -void IHomeMenuFunctions::RequestToGetForeground(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(pop_from_general_channel_event->GetReadableEvent()); -} - -IGlobalStateController::IGlobalStateController(Core::System& system_) - : ServiceFramework{system_, "IGlobalStateController"} { - // 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, nullptr, "LoadAndApplyIdlePolicySettings"}, - {11, nullptr, "NotifyCecSettingsChanged"}, - {12, nullptr, "SetDefaultHomeButtonLongPressTime"}, - {13, nullptr, "UpdateDefaultDisplayResolution"}, - {14, nullptr, "ShouldSleepOnBoot"}, - {15, nullptr, "GetHdcpAuthenticationFailedEvent"}, - {30, nullptr, "OpenCradleFirmwareUpdater"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IGlobalStateController::~IGlobalStateController() = default; - -IApplicationCreator::IApplicationCreator(Core::System& system_) - : ServiceFramework{system_, "IApplicationCreator"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "CreateApplication"}, - {1, nullptr, "PopLaunchRequestedApplication"}, - {10, nullptr, "CreateSystemApplication"}, - {100, nullptr, "PopFloatingApplicationForDevelopment"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -IApplicationCreator::~IApplicationCreator() = default; - -IProcessWindingController::IProcessWindingController(Core::System& system_) - : ServiceFramework{system_, "IProcessWindingController"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IProcessWindingController::GetLaunchReason, "GetLaunchReason"}, - {11, &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; - -void IProcessWindingController::GetLaunchReason(HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - - struct AppletProcessLaunchReason { - u8 flag; - INSERT_PADDING_BYTES(3); - }; - static_assert(sizeof(AppletProcessLaunchReason) == 0x4, - "AppletProcessLaunchReason is an invalid size"); - - AppletProcessLaunchReason reason{ - .flag = 0, - }; - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushRaw(reason); -} - -void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) { - const auto applet_id = system.GetAppletManager().GetCurrentAppletId(); - const auto applet_mode = Applets::LibraryAppletMode::AllForeground; - - LOG_WARNING(Service_AM, "(STUBBED) called with applet_id={:08X}, applet_mode={:08X}", applet_id, - applet_mode); - - const auto& applet_manager{system.GetAppletManager()}; - const auto applet = applet_manager.GetApplet(applet_id, applet_mode); - - if (applet == nullptr) { - LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; - } - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet); -} - } // namespace Service::AM diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 905a71b9f..4a2d797bd 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -1,20 +1,11 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once -#include <chrono> -#include <memory> -#include <queue> - -#include "core/hle/service/kernel_helpers.h" -#include "core/hle/service/service.h" - -namespace Kernel { -class KernelCore; -class KReadableEvent; -class KTransferMemory; -} // namespace Kernel +namespace Core { +class System; +} namespace Service::Nvnflinger { class Nvnflinger; @@ -22,443 +13,6 @@ class Nvnflinger; namespace Service::AM { -class AppletMessageQueue { -public: - // This is nn::am::AppletMessage - enum class AppletMessage : u32 { - None = 0, - ChangeIntoForeground = 1, - ChangeIntoBackground = 2, - Exit = 4, - ApplicationExited = 6, - FocusStateChanged = 15, - Resume = 16, - DetectShortPressingHomeButton = 20, - DetectLongPressingHomeButton = 21, - DetectShortPressingPowerButton = 22, - DetectMiddlePressingPowerButton = 23, - DetectLongPressingPowerButton = 24, - RequestToPrepareSleep = 25, - FinishedSleepSequence = 26, - SleepRequiredByHighTemperature = 27, - SleepRequiredByLowBattery = 28, - AutoPowerDown = 29, - OperationModeChanged = 30, - PerformanceModeChanged = 31, - DetectReceivingCecSystemStandby = 32, - SdCardRemoved = 33, - LaunchApplicationRequested = 50, - RequestToDisplay = 51, - ShowApplicationLogo = 55, - HideApplicationLogo = 56, - ForceHideApplicationLogo = 57, - FloatingApplicationDetected = 60, - DetectShortPressingCaptureButton = 90, - AlbumScreenShotTaken = 92, - AlbumRecordingSaved = 93, - }; - - explicit AppletMessageQueue(Core::System& system); - ~AppletMessageQueue(); - - Kernel::KReadableEvent& GetMessageReceiveEvent(); - Kernel::KReadableEvent& GetOperationModeChangedEvent(); - void PushMessage(AppletMessage msg); - AppletMessage PopMessage(); - std::size_t GetMessageCount() const; - void RequestExit(); - void RequestResume(); - void FocusStateChanged(); - void OperationModeChanged(); - -private: - KernelHelpers::ServiceContext service_context; - - Kernel::KEvent* on_new_message; - Kernel::KEvent* on_operation_mode_changed; - - std::queue<AppletMessage> messages; -}; - -class IWindowController final : public ServiceFramework<IWindowController> { -public: - explicit IWindowController(Core::System& system_); - ~IWindowController() override; - -private: - void GetAppletResourceUserId(HLERequestContext& ctx); - void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx); - void AcquireForegroundRights(HLERequestContext& ctx); -}; - -class IAudioController final : public ServiceFramework<IAudioController> { -public: - explicit IAudioController(Core::System& system_); - ~IAudioController() override; - -private: - void SetExpectedMasterVolume(HLERequestContext& ctx); - void GetMainAppletExpectedMasterVolume(HLERequestContext& ctx); - void GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx); - void ChangeMainAppletMasterVolume(HLERequestContext& ctx); - void SetTransparentAudioRate(HLERequestContext& ctx); - - static constexpr float min_allowed_volume = 0.0f; - static constexpr float max_allowed_volume = 1.0f; - - float main_applet_volume{0.25f}; - float library_applet_volume{max_allowed_volume}; - float transparent_volume_rate{min_allowed_volume}; - - // 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 fade_time_ns{0}; -}; - -class IDisplayController final : public ServiceFramework<IDisplayController> { -public: - explicit IDisplayController(Core::System& system_); - ~IDisplayController() override; - -private: - void GetCallerAppletCaptureImageEx(HLERequestContext& ctx); - void TakeScreenShotOfOwnLayer(HLERequestContext& ctx); - void AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx); - void ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx); - void AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx); - void ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx); -}; - -class IDebugFunctions final : public ServiceFramework<IDebugFunctions> { -public: - explicit IDebugFunctions(Core::System& system_); - ~IDebugFunctions() override; -}; - -class ISelfController final : public ServiceFramework<ISelfController> { -public: - explicit ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_); - ~ISelfController() override; - -private: - void Exit(HLERequestContext& ctx); - void LockExit(HLERequestContext& ctx); - void UnlockExit(HLERequestContext& ctx); - void EnterFatalSection(HLERequestContext& ctx); - void LeaveFatalSection(HLERequestContext& ctx); - void GetLibraryAppletLaunchableEvent(HLERequestContext& ctx); - void SetScreenShotPermission(HLERequestContext& ctx); - void SetOperationModeChangedNotification(HLERequestContext& ctx); - void SetPerformanceModeChangedNotification(HLERequestContext& ctx); - void SetFocusHandlingMode(HLERequestContext& ctx); - void SetRestartMessageEnabled(HLERequestContext& ctx); - void SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx); - void SetAlbumImageOrientation(HLERequestContext& ctx); - void IsSystemBufferSharingEnabled(HLERequestContext& ctx); - void GetSystemSharedBufferHandle(HLERequestContext& ctx); - void GetSystemSharedLayerHandle(HLERequestContext& ctx); - void CreateManagedDisplayLayer(HLERequestContext& ctx); - void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx); - void SetHandlesRequestToDisplay(HLERequestContext& ctx); - void ApproveToDisplay(HLERequestContext& ctx); - void SetIdleTimeDetectionExtension(HLERequestContext& ctx); - void GetIdleTimeDetectionExtension(HLERequestContext& ctx); - void ReportUserIsActive(HLERequestContext& ctx); - void SetAutoSleepDisabled(HLERequestContext& ctx); - void IsAutoSleepDisabled(HLERequestContext& ctx); - void GetAccumulatedSuspendedTickValue(HLERequestContext& ctx); - void GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx); - void SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx); - void SaveCurrentScreenshot(HLERequestContext& ctx); - void SetRecordVolumeMuted(HLERequestContext& ctx); - - Result EnsureBufferSharingEnabled(); - - enum class ScreenshotPermission : u32 { - Inherit = 0, - Enable = 1, - Disable = 2, - }; - - Nvnflinger::Nvnflinger& nvnflinger; - - KernelHelpers::ServiceContext service_context; - - Kernel::KEvent* launchable_event; - Kernel::KEvent* accumulated_suspended_tick_changed_event; - - u32 idle_time_detection_extension = 0; - u64 num_fatal_sections_entered = 0; - u64 system_shared_buffer_id = 0; - u64 system_shared_layer_id = 0; - bool is_auto_sleep_disabled = false; - bool buffer_sharing_enabled = false; - ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit; -}; - -class ILockAccessor final : public ServiceFramework<ILockAccessor> { -public: - explicit ILockAccessor(Core::System& system_); - ~ILockAccessor() override; - -private: - void TryLock(HLERequestContext& ctx); - void Unlock(HLERequestContext& ctx); - void GetEvent(HLERequestContext& ctx); - void IsLocked(HLERequestContext& ctx); - - bool is_locked{}; - - Kernel::KEvent* lock_event; - KernelHelpers::ServiceContext service_context; -}; - -class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { -public: - explicit ICommonStateGetter(Core::System& system_, - std::shared_ptr<AppletMessageQueue> msg_queue_); - ~ICommonStateGetter() override; - -private: - // This is nn::oe::FocusState - enum class FocusState : u8 { - InFocus = 1, - NotInFocus = 2, - Background = 3, - }; - - // This is nn::oe::OperationMode - enum class OperationMode : u8 { - Handheld = 0, - Docked = 1, - }; - - // This is nn::am::service::SystemButtonType - enum class SystemButtonType { - None, - HomeButtonShortPressing, - HomeButtonLongPressing, - PowerButtonShortPressing, - PowerButtonLongPressing, - ShutdownSystem, - CaptureButtonShortPressing, - CaptureButtonLongPressing, - }; - - enum class SysPlatformRegion : s32 { - Global = 1, - Terra = 2, - }; - - void GetEventHandle(HLERequestContext& ctx); - void ReceiveMessage(HLERequestContext& ctx); - void GetCurrentFocusState(HLERequestContext& ctx); - void RequestToAcquireSleepLock(HLERequestContext& ctx); - void GetAcquiredSleepLockEvent(HLERequestContext& ctx); - void GetReaderLockAccessorEx(HLERequestContext& ctx); - void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx); - void GetOperationMode(HLERequestContext& ctx); - void GetPerformanceMode(HLERequestContext& ctx); - void GetBootMode(HLERequestContext& ctx); - void IsVrModeEnabled(HLERequestContext& ctx); - void SetVrModeEnabled(HLERequestContext& ctx); - void SetLcdBacklighOffEnabled(HLERequestContext& ctx); - void BeginVrModeEx(HLERequestContext& ctx); - void EndVrModeEx(HLERequestContext& ctx); - void GetDefaultDisplayResolution(HLERequestContext& ctx); - void SetCpuBoostMode(HLERequestContext& ctx); - void GetBuiltInDisplayType(HLERequestContext& ctx); - void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx); - void GetSettingsPlatformRegion(HLERequestContext& ctx); - void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx); - - std::shared_ptr<AppletMessageQueue> msg_queue; - bool vr_mode_state{}; - Kernel::KEvent* sleep_lock_event; - KernelHelpers::ServiceContext service_context; -}; - -class IStorageImpl { -public: - virtual ~IStorageImpl(); - virtual std::vector<u8>& GetData() = 0; - virtual const std::vector<u8>& GetData() const = 0; - virtual std::size_t GetSize() const = 0; -}; - -class IStorage final : public ServiceFramework<IStorage> { -public: - explicit IStorage(Core::System& system_, std::vector<u8>&& buffer); - ~IStorage() override; - - std::vector<u8>& GetData() { - return impl->GetData(); - } - - const std::vector<u8>& GetData() const { - return impl->GetData(); - } - - std::size_t GetSize() const { - return impl->GetSize(); - } - -private: - void Register(); - void Open(HLERequestContext& ctx); - - std::shared_ptr<IStorageImpl> impl; -}; - -class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { -public: - explicit IStorageAccessor(Core::System& system_, IStorage& backing_); - ~IStorageAccessor() override; - -private: - void GetSize(HLERequestContext& ctx); - void Write(HLERequestContext& ctx); - void Read(HLERequestContext& ctx); - - IStorage& backing; -}; - -class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { -public: - explicit ILibraryAppletCreator(Core::System& system_); - ~ILibraryAppletCreator() override; - -private: - void CreateLibraryApplet(HLERequestContext& ctx); - void CreateStorage(HLERequestContext& ctx); - void CreateTransferMemoryStorage(HLERequestContext& ctx); - void CreateHandleStorage(HLERequestContext& ctx); -}; - -class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> { -public: - explicit ILibraryAppletSelfAccessor(Core::System& system_); - ~ILibraryAppletSelfAccessor() override; - -private: - void PopInData(HLERequestContext& ctx); - void PushOutData(HLERequestContext& ctx); - void GetLibraryAppletInfo(HLERequestContext& ctx); - void GetMainAppletIdentityInfo(HLERequestContext& ctx); - void ExitProcessAndReturn(HLERequestContext& ctx); - void GetCallerAppletIdentityInfo(HLERequestContext& ctx); - void GetDesirableKeyboardLayout(HLERequestContext& ctx); - void GetMainAppletAvailableUsers(HLERequestContext& ctx); - void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx); - - void PushInShowAlbum(); - void PushInShowCabinetData(); - void PushInShowMiiEditData(); - void PushInShowSoftwareKeyboard(); - void PushInShowController(); - - std::deque<std::vector<u8>> queue_data; -}; - -class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> { -public: - explicit IAppletCommonFunctions(Core::System& system_); - ~IAppletCommonFunctions() override; - -private: - void SetCpuBoostRequestPriority(HLERequestContext& ctx); -}; - -class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { -public: - explicit IApplicationFunctions(Core::System& system_); - ~IApplicationFunctions() override; - -private: - void PopLaunchParameter(HLERequestContext& ctx); - void CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx); - void EnsureSaveData(HLERequestContext& ctx); - void SetTerminateResult(HLERequestContext& ctx); - void GetDisplayVersion(HLERequestContext& ctx); - void GetDesiredLanguage(HLERequestContext& ctx); - void IsGamePlayRecordingSupported(HLERequestContext& ctx); - void InitializeGamePlayRecording(HLERequestContext& ctx); - void SetGamePlayRecordingState(HLERequestContext& ctx); - void NotifyRunning(HLERequestContext& ctx); - void GetPseudoDeviceId(HLERequestContext& ctx); - void ExtendSaveData(HLERequestContext& ctx); - void GetSaveDataSize(HLERequestContext& ctx); - void CreateCacheStorage(HLERequestContext& ctx); - void GetSaveDataSizeMax(HLERequestContext& ctx); - void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx); - void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx); - void BeginBlockingHomeButton(HLERequestContext& ctx); - void EndBlockingHomeButton(HLERequestContext& ctx); - void EnableApplicationCrashReport(HLERequestContext& ctx); - void InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx); - void SetApplicationCopyrightImage(HLERequestContext& ctx); - void SetApplicationCopyrightVisibility(HLERequestContext& ctx); - void QueryApplicationPlayStatistics(HLERequestContext& ctx); - void QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx); - void ExecuteProgram(HLERequestContext& ctx); - void ClearUserChannel(HLERequestContext& ctx); - void UnpopToUserChannel(HLERequestContext& ctx); - void GetPreviousProgramIndex(HLERequestContext& ctx); - void GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx); - void GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx); - void TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx); - void GetNotificationStorageChannelEvent(HLERequestContext& ctx); - void GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx); - void PrepareForJit(HLERequestContext& ctx); - - KernelHelpers::ServiceContext service_context; - - bool launch_popped_account_preselect = false; - s32 previous_program_index{-1}; - Kernel::KEvent* gpu_error_detected_event; - Kernel::KEvent* friend_invitation_storage_channel_event; - Kernel::KEvent* notification_storage_channel_event; - Kernel::KEvent* health_warning_disappeared_system_event; -}; - -class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { -public: - explicit IHomeMenuFunctions(Core::System& system_); - ~IHomeMenuFunctions() override; - -private: - void RequestToGetForeground(HLERequestContext& ctx); - void GetPopFromGeneralChannelEvent(HLERequestContext& ctx); - - KernelHelpers::ServiceContext service_context; - - Kernel::KEvent* pop_from_general_channel_event; -}; - -class IGlobalStateController final : public ServiceFramework<IGlobalStateController> { -public: - explicit IGlobalStateController(Core::System& system_); - ~IGlobalStateController() override; -}; - -class IApplicationCreator final : public ServiceFramework<IApplicationCreator> { -public: - explicit IApplicationCreator(Core::System& system_); - ~IApplicationCreator() override; -}; - -class IProcessWindingController final : public ServiceFramework<IProcessWindingController> { -public: - explicit IProcessWindingController(Core::System& system_); - ~IProcessWindingController() override; - -private: - void GetLaunchReason(HLERequestContext& ctx); - void OpenCallingLibraryApplet(HLERequestContext& ctx); -}; - void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system); } // namespace Service::AM diff --git a/src/core/hle/service/am/am_results.h b/src/core/hle/service/am/am_results.h new file mode 100644 index 000000000..528b334ad --- /dev/null +++ b/src/core/hle/service/am/am_results.h @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/result.h" + +namespace Service::AM { + +constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2}; +constexpr Result ResultNoMessages{ErrorModule::AM, 3}; +constexpr Result ResultInvalidOffset{ErrorModule::AM, 503}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index e30e6478a..bd9e5f505 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp @@ -1,263 +1,13 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "common/logging/log.h" -#include "core/core.h" -#include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" +#include "core/hle/service/am/library_applet_proxy.h" +#include "core/hle/service/am/system_applet_proxy.h" #include "core/hle/service/ipc_helpers.h" -#include "core/hle/service/nvnflinger/nvnflinger.h" namespace Service::AM { -class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { -public: - explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr<AppletMessageQueue> msg_queue_, - Core::System& system_) - : ServiceFramework{system_, "ILibraryAppletProxy"}, - nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, - {1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"}, - {2, &ILibraryAppletProxy::GetWindowController, "GetWindowController"}, - {3, &ILibraryAppletProxy::GetAudioController, "GetAudioController"}, - {4, &ILibraryAppletProxy::GetDisplayController, "GetDisplayController"}, - {10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"}, - {11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, - {20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"}, - {21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"}, - {22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"}, - {23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"}, - {1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - -private: - void GetCommonStateGetter(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue); - } - - void GetSelfController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ISelfController>(system, nvnflinger); - } - - void GetWindowController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IWindowController>(system); - } - - void GetAudioController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IAudioController>(system); - } - - void GetDisplayController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IDisplayController>(system); - } - - void GetProcessWindingController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IProcessWindingController>(system); - } - - void GetLibraryAppletCreator(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ILibraryAppletCreator>(system); - } - - void OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ILibraryAppletSelfAccessor>(system); - } - - void GetAppletCommonFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IAppletCommonFunctions>(system); - } - - void GetHomeMenuFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IHomeMenuFunctions>(system); - } - - void GetGlobalStateController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IGlobalStateController>(system); - } - - void GetDebugFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IDebugFunctions>(system); - } - - Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr<AppletMessageQueue> msg_queue; -}; - -class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { -public: - explicit ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr<AppletMessageQueue> msg_queue_, - Core::System& system_) - : ServiceFramework{system_, "ISystemAppletProxy"}, - nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, - {1, &ISystemAppletProxy::GetSelfController, "GetSelfController"}, - {2, &ISystemAppletProxy::GetWindowController, "GetWindowController"}, - {3, &ISystemAppletProxy::GetAudioController, "GetAudioController"}, - {4, &ISystemAppletProxy::GetDisplayController, "GetDisplayController"}, - {10, nullptr, "GetProcessWindingController"}, - {11, &ISystemAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, - {20, &ISystemAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"}, - {21, &ISystemAppletProxy::GetGlobalStateController, "GetGlobalStateController"}, - {22, &ISystemAppletProxy::GetApplicationCreator, "GetApplicationCreator"}, - {23, &ISystemAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"}, - {1000, &ISystemAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - -private: - void GetCommonStateGetter(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue); - } - - void GetSelfController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ISelfController>(system, nvnflinger); - } - - void GetWindowController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IWindowController>(system); - } - - void GetAudioController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IAudioController>(system); - } - - void GetDisplayController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IDisplayController>(system); - } - - void GetLibraryAppletCreator(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ILibraryAppletCreator>(system); - } - - void GetHomeMenuFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IHomeMenuFunctions>(system); - } - - void GetGlobalStateController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IGlobalStateController>(system); - } - - void GetApplicationCreator(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IApplicationCreator>(system); - } - - void GetAppletCommonFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IAppletCommonFunctions>(system); - } - - void GetDebugFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IDebugFunctions>(system); - } - - Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr<AppletMessageQueue> msg_queue; -}; - void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); @@ -284,8 +34,8 @@ void AppletAE::OpenLibraryAppletProxyOld(HLERequestContext& ctx) { AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_) - : ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_}, msg_queue{ - std::move(msg_queue_)} { + : ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_}, + msg_queue{std::move(msg_queue_)} { // clang-format off static const FunctionInfo functions[] = { {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, diff --git a/src/core/hle/service/am/applet_common_functions.cpp b/src/core/hle/service/am/applet_common_functions.cpp new file mode 100644 index 000000000..81c01a48b --- /dev/null +++ b/src/core/hle/service/am/applet_common_functions.cpp @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applet_common_functions.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_) + : ServiceFramework{system_, "IAppletCommonFunctions"} { + // 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, nullptr, "GetHomeButtonDoubleClickEnabled"}, + {52, nullptr, "IsHomeButtonShortPressedBlocked"}, + {60, nullptr, "IsVrModeCurtainRequired"}, + {61, nullptr, "IsSleepRequiredByHighTemperature"}, + {62, nullptr, "IsSleepRequiredByLowBattery"}, + {70, &IAppletCommonFunctions::SetCpuBoostRequestPriority, "SetCpuBoostRequestPriority"}, + {80, nullptr, "SetHandlingCaptureButtonShortPressedMessageEnabledForApplet"}, + {81, nullptr, "SetHandlingCaptureButtonLongPressedMessageEnabledForApplet"}, + {90, nullptr, "OpenNamedChannelAsParent"}, + {91, nullptr, "OpenNamedChannelAsChild"}, + {100, nullptr, "SetApplicationCoreUsageMode"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IAppletCommonFunctions::~IAppletCommonFunctions() = default; + +void IAppletCommonFunctions::SetCpuBoostRequestPriority(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet_common_functions.h b/src/core/hle/service/am/applet_common_functions.h new file mode 100644 index 000000000..be87b3820 --- /dev/null +++ b/src/core/hle/service/am/applet_common_functions.h @@ -0,0 +1,19 @@ +// 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 IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> { +public: + explicit IAppletCommonFunctions(Core::System& system_); + ~IAppletCommonFunctions() override; + +private: + void SetCpuBoostRequestPriority(HLERequestContext& ctx); +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet_message_queue.cpp b/src/core/hle/service/am/applet_message_queue.cpp new file mode 100644 index 000000000..e4931031d --- /dev/null +++ b/src/core/hle/service/am/applet_message_queue.cpp @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applet_message_queue.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +AppletMessageQueue::AppletMessageQueue(Core::System& system) + : service_context{system, "AppletMessageQueue"} { + on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived"); + on_operation_mode_changed = service_context.CreateEvent("AMMessageQueue:OperationModeChanged"); +} + +AppletMessageQueue::~AppletMessageQueue() { + service_context.CloseEvent(on_new_message); + service_context.CloseEvent(on_operation_mode_changed); +} + +Kernel::KReadableEvent& AppletMessageQueue::GetMessageReceiveEvent() { + return on_new_message->GetReadableEvent(); +} + +Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() { + return on_operation_mode_changed->GetReadableEvent(); +} + +void AppletMessageQueue::PushMessage(AppletMessage msg) { + messages.push(msg); + on_new_message->Signal(); +} + +AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { + if (messages.empty()) { + on_new_message->Clear(); + return AppletMessage::None; + } + auto msg = messages.front(); + messages.pop(); + if (messages.empty()) { + on_new_message->Clear(); + } + return msg; +} + +std::size_t AppletMessageQueue::GetMessageCount() const { + return messages.size(); +} + +void AppletMessageQueue::RequestExit() { + PushMessage(AppletMessage::Exit); +} + +void AppletMessageQueue::RequestResume() { + PushMessage(AppletMessage::Resume); +} + +void AppletMessageQueue::FocusStateChanged() { + PushMessage(AppletMessage::FocusStateChanged); +} + +void AppletMessageQueue::OperationModeChanged() { + PushMessage(AppletMessage::OperationModeChanged); + PushMessage(AppletMessage::PerformanceModeChanged); + on_operation_mode_changed->Signal(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet_message_queue.h b/src/core/hle/service/am/applet_message_queue.h new file mode 100644 index 000000000..60145aae9 --- /dev/null +++ b/src/core/hle/service/am/applet_message_queue.h @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <queue> + +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/service.h" + +namespace Kernel { +class KReadableEvent; +} // namespace Kernel + +namespace Service::AM { + +class AppletMessageQueue { +public: + // This is nn::am::AppletMessage + enum class AppletMessage : u32 { + None = 0, + ChangeIntoForeground = 1, + ChangeIntoBackground = 2, + Exit = 4, + ApplicationExited = 6, + FocusStateChanged = 15, + Resume = 16, + DetectShortPressingHomeButton = 20, + DetectLongPressingHomeButton = 21, + DetectShortPressingPowerButton = 22, + DetectMiddlePressingPowerButton = 23, + DetectLongPressingPowerButton = 24, + RequestToPrepareSleep = 25, + FinishedSleepSequence = 26, + SleepRequiredByHighTemperature = 27, + SleepRequiredByLowBattery = 28, + AutoPowerDown = 29, + OperationModeChanged = 30, + PerformanceModeChanged = 31, + DetectReceivingCecSystemStandby = 32, + SdCardRemoved = 33, + LaunchApplicationRequested = 50, + RequestToDisplay = 51, + ShowApplicationLogo = 55, + HideApplicationLogo = 56, + ForceHideApplicationLogo = 57, + FloatingApplicationDetected = 60, + DetectShortPressingCaptureButton = 90, + AlbumScreenShotTaken = 92, + AlbumRecordingSaved = 93, + }; + + explicit AppletMessageQueue(Core::System& system); + ~AppletMessageQueue(); + + Kernel::KReadableEvent& GetMessageReceiveEvent(); + Kernel::KReadableEvent& GetOperationModeChangedEvent(); + void PushMessage(AppletMessage msg); + AppletMessage PopMessage(); + std::size_t GetMessageCount() const; + void RequestExit(); + void RequestResume(); + void FocusStateChanged(); + void OperationModeChanged(); + +private: + KernelHelpers::ServiceContext service_context; + + Kernel::KEvent* on_new_message; + Kernel::KEvent* on_operation_mode_changed; + + std::queue<AppletMessage> messages; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index d6c565d85..f373d1136 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp @@ -1,107 +1,13 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "common/logging/log.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_oe.h" +#include "core/hle/service/am/application_proxy.h" #include "core/hle/service/ipc_helpers.h" -#include "core/hle/service/nvnflinger/nvnflinger.h" namespace Service::AM { -class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { -public: - explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr<AppletMessageQueue> msg_queue_, - Core::System& system_) - : ServiceFramework{system_, "IApplicationProxy"}, - nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"}, - {1, &IApplicationProxy::GetSelfController, "GetSelfController"}, - {2, &IApplicationProxy::GetWindowController, "GetWindowController"}, - {3, &IApplicationProxy::GetAudioController, "GetAudioController"}, - {4, &IApplicationProxy::GetDisplayController, "GetDisplayController"}, - {10, nullptr, "GetProcessWindingController"}, - {11, &IApplicationProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, - {20, &IApplicationProxy::GetApplicationFunctions, "GetApplicationFunctions"}, - {1000, &IApplicationProxy::GetDebugFunctions, "GetDebugFunctions"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - -private: - void GetAudioController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IAudioController>(system); - } - - void GetDisplayController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IDisplayController>(system); - } - - void GetDebugFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IDebugFunctions>(system); - } - - void GetWindowController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IWindowController>(system); - } - - void GetSelfController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ISelfController>(system, nvnflinger); - } - - void GetCommonStateGetter(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue); - } - - void GetLibraryAppletCreator(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ILibraryAppletCreator>(system); - } - - void GetApplicationFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IApplicationFunctions>(system); - } - - Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr<AppletMessageQueue> msg_queue; -}; - void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); @@ -112,8 +18,8 @@ void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) { AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_) - : ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_}, msg_queue{ - std::move(msg_queue_)} { + : ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_}, + msg_queue{std::move(msg_queue_)} { static const FunctionInfo functions[] = { {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, }; diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp index c2ff444a6..1b756fbd7 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp @@ -9,6 +9,7 @@ #include "core/hle/kernel/k_readable_event.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_cabinet.h" +#include "core/hle/service/am/storage.h" #include "core/hle/service/mii/mii_manager.h" #include "core/hle/service/nfc/common/device.h" #include "hid_core/hid_core.h" @@ -17,9 +18,8 @@ namespace Service::AM::Applets { Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, const Core::Frontend::CabinetApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, service_context{ - system_, - "CabinetApplet"} { + : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, + service_context{system_, "CabinetApplet"} { availability_change_event = service_context.CreateEvent("CabinetApplet:AvailabilityChangeEvent"); diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/applets/applet_controller.cpp index 0e4d9cc39..bc8de6b60 100644 --- a/src/core/hle/service/am/applets/applet_controller.cpp +++ b/src/core/hle/service/am/applets/applet_controller.cpp @@ -12,6 +12,7 @@ #include "core/hle/result.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_controller.h" +#include "core/hle/service/am/storage.h" #include "hid_core/frontend/emulated_controller.h" #include "hid_core/hid_core.h" #include "hid_core/hid_types.h" diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp index 084bc138c..96126832c 100644 --- a/src/core/hle/service/am/applets/applet_error.cpp +++ b/src/core/hle/service/am/applets/applet_error.cpp @@ -10,6 +10,7 @@ #include "core/frontend/applets/error.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_error.h" +#include "core/hle/service/am/storage.h" #include "core/reporter.h" namespace Service::AM::Applets { diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/applets/applet_general_backend.cpp index c0032f652..c010c78e2 100644 --- a/src/core/hle/service/am/applets/applet_general_backend.cpp +++ b/src/core/hle/service/am/applets/applet_general_backend.cpp @@ -9,6 +9,7 @@ #include "core/hle/result.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_general_backend.h" +#include "core/hle/service/am/storage.h" #include "core/reporter.h" namespace Service::AM::Applets { diff --git a/src/core/hle/service/am/applets/applet_mii_edit.cpp b/src/core/hle/service/am/applets/applet_mii_edit.cpp index e83e931c5..1576b45c4 100644 --- a/src/core/hle/service/am/applets/applet_mii_edit.cpp +++ b/src/core/hle/service/am/applets/applet_mii_edit.cpp @@ -7,6 +7,7 @@ #include "core/frontend/applets/mii_edit.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_mii_edit.h" +#include "core/hle/service/am/storage.h" #include "core/hle/service/mii/mii.h" #include "core/hle/service/mii/mii_manager.h" #include "core/hle/service/sm/sm.h" diff --git a/src/core/hle/service/am/applets/applet_profile_select.cpp b/src/core/hle/service/am/applets/applet_profile_select.cpp index 89cb323e9..f32db6842 100644 --- a/src/core/hle/service/am/applets/applet_profile_select.cpp +++ b/src/core/hle/service/am/applets/applet_profile_select.cpp @@ -10,6 +10,7 @@ #include "core/hle/service/acc/errors.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_profile_select.h" +#include "core/hle/service/am/storage.h" namespace Service::AM::Applets { diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.cpp b/src/core/hle/service/am/applets/applet_software_keyboard.cpp index 4145bb84f..a6a07cef3 100644 --- a/src/core/hle/service/am/applets/applet_software_keyboard.cpp +++ b/src/core/hle/service/am/applets/applet_software_keyboard.cpp @@ -6,6 +6,7 @@ #include "core/frontend/applets/software_keyboard.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_software_keyboard.h" +#include "core/hle/service/am/storage.h" namespace Service::AM::Applets { diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/applets/applet_web_browser.cpp index 19057ad7b..871737b3e 100644 --- a/src/core/hle/service/am/applets/applet_web_browser.cpp +++ b/src/core/hle/service/am/applets/applet_web_browser.cpp @@ -20,6 +20,7 @@ #include "core/hle/result.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_web_browser.h" +#include "core/hle/service/am/storage.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/ns/iplatform_service_manager.h" #include "core/loader/loader.h" diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 89d5434af..6a47f4b7a 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -16,6 +16,7 @@ #include "core/hle/kernel/k_event.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" +#include "core/hle/service/am/applet_message_queue.h" #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/am/applets/applet_cabinet.h" #include "core/hle/service/am/applets/applet_controller.h" @@ -26,13 +27,14 @@ #include "core/hle/service/am/applets/applet_software_keyboard.h" #include "core/hle/service/am/applets/applet_web_browser.h" #include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/storage.h" #include "core/hle/service/sm/sm.h" namespace Service::AM::Applets { AppletDataBroker::AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_) - : system{system_}, applet_mode{applet_mode_}, service_context{system, - "ILibraryAppletAccessor"} { + : system{system_}, applet_mode{applet_mode_}, + service_context{system, "ILibraryAppletAccessor"} { state_changed_event = service_context.CreateEvent("ILibraryAppletAccessor:StateChangedEvent"); pop_out_data_event = service_context.CreateEvent("ILibraryAppletAccessor:PopDataOutEvent"); pop_interactive_out_data_event = diff --git a/src/core/hle/service/am/application_creator.cpp b/src/core/hle/service/am/application_creator.cpp new file mode 100644 index 000000000..79ea045a3 --- /dev/null +++ b/src/core/hle/service/am/application_creator.cpp @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/application_creator.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IApplicationCreator::IApplicationCreator(Core::System& system_) + : ServiceFramework{system_, "IApplicationCreator"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "CreateApplication"}, + {1, nullptr, "PopLaunchRequestedApplication"}, + {10, nullptr, "CreateSystemApplication"}, + {100, nullptr, "PopFloatingApplicationForDevelopment"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IApplicationCreator::~IApplicationCreator() = default; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/application_creator.h b/src/core/hle/service/am/application_creator.h new file mode 100644 index 000000000..375a3c476 --- /dev/null +++ b/src/core/hle/service/am/application_creator.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 IApplicationCreator final : public ServiceFramework<IApplicationCreator> { +public: + explicit IApplicationCreator(Core::System& system_); + ~IApplicationCreator() override; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/application_functions.cpp b/src/core/hle/service/am/application_functions.cpp new file mode 100644 index 000000000..fef45c732 --- /dev/null +++ b/src/core/hle/service/am/application_functions.cpp @@ -0,0 +1,610 @@ +// 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/service/acc/profile_manager.h" +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/application_functions.h" +#include "core/hle/service/am/storage.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/filesystem/save_data_controller.h" +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/ns/ns.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::AM { + +enum class LaunchParameterKind : u32 { + UserChannel = 1, + AccountPreselectedUser = 2, +}; + +constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA; + +struct LaunchParameterAccountPreselectedUser { + u32_le magic; + u32_le is_account_selected; + Common::UUID current_user; + INSERT_PADDING_BYTES(0x70); +}; +static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); + +IApplicationFunctions::IApplicationFunctions(Core::System& system_) + : ServiceFramework{system_, "IApplicationFunctions"}, + service_context{system, "IApplicationFunctions"} { + // clang-format off + static const FunctionInfo functions[] = { + {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, + {10, nullptr, "CreateApplicationAndPushAndRequestToStart"}, + {11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"}, + {12, nullptr, "CreateApplicationAndRequestToStart"}, + {13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, "CreateApplicationAndRequestToStartForQuest"}, + {14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"}, + {15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"}, + {20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"}, + {21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"}, + {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"}, + {23, &IApplicationFunctions::GetDisplayVersion, "GetDisplayVersion"}, + {24, nullptr, "GetLaunchStorageInfoForDebug"}, + {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"}, + {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"}, + {27, &IApplicationFunctions::CreateCacheStorage, "CreateCacheStorage"}, + {28, &IApplicationFunctions::GetSaveDataSizeMax, "GetSaveDataSizeMax"}, + {29, nullptr, "GetCacheStorageMax"}, + {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"}, + {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"}, + {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"}, + {33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"}, + {34, nullptr, "SelectApplicationLicense"}, + {35, nullptr, "GetDeviceSaveDataSizeMax"}, + {36, nullptr, "GetLimitedApplicationLicense"}, + {37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"}, + {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"}, + {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"}, + {60, nullptr, "SetMediaPlaybackStateForApplication"}, + {65, &IApplicationFunctions::IsGamePlayRecordingSupported, "IsGamePlayRecordingSupported"}, + {66, &IApplicationFunctions::InitializeGamePlayRecording, "InitializeGamePlayRecording"}, + {67, &IApplicationFunctions::SetGamePlayRecordingState, "SetGamePlayRecordingState"}, + {68, nullptr, "RequestFlushGamePlayingMovieForDebug"}, + {70, nullptr, "RequestToShutdown"}, + {71, nullptr, "RequestToReboot"}, + {72, nullptr, "RequestToSleep"}, + {80, nullptr, "ExitAndRequestToShowThanksMessage"}, + {90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"}, + {100, &IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer, "InitializeApplicationCopyrightFrameBuffer"}, + {101, &IApplicationFunctions::SetApplicationCopyrightImage, "SetApplicationCopyrightImage"}, + {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"}, + {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"}, + {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"}, + {120, &IApplicationFunctions::ExecuteProgram, "ExecuteProgram"}, + {121, &IApplicationFunctions::ClearUserChannel, "ClearUserChannel"}, + {122, &IApplicationFunctions::UnpopToUserChannel, "UnpopToUserChannel"}, + {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"}, + {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, + {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, + {131, nullptr, "SetDelayTimeToAbortOnGpuError"}, + {140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"}, + {141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"}, + {150, &IApplicationFunctions::GetNotificationStorageChannelEvent, "GetNotificationStorageChannelEvent"}, + {151, nullptr, "TryPopFromNotificationStorageChannel"}, + {160, &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, &IApplicationFunctions::PrepareForJit, "PrepareForJit"}, + }; + // clang-format on + + RegisterHandlers(functions); + + gpu_error_detected_event = + service_context.CreateEvent("IApplicationFunctions:GpuErrorDetectedSystemEvent"); + friend_invitation_storage_channel_event = + service_context.CreateEvent("IApplicationFunctions:FriendInvitationStorageChannelEvent"); + notification_storage_channel_event = + service_context.CreateEvent("IApplicationFunctions:NotificationStorageChannelEvent"); + health_warning_disappeared_system_event = + service_context.CreateEvent("IApplicationFunctions:HealthWarningDisappearedSystemEvent"); +} + +IApplicationFunctions::~IApplicationFunctions() { + service_context.CloseEvent(gpu_error_detected_event); + service_context.CloseEvent(friend_invitation_storage_channel_event); + service_context.CloseEvent(notification_storage_channel_event); + service_context.CloseEvent(health_warning_disappeared_system_event); +} + +void IApplicationFunctions::EnableApplicationCrashReport(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::SetApplicationCopyrightImage(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::SetApplicationCopyrightVisibility(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto is_visible = rp.Pop<bool>(); + + LOG_WARNING(Service_AM, "(STUBBED) called, is_visible={}", is_visible); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::BeginBlockingHomeButton(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::EndBlockingHomeButton(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto kind = rp.PopEnum<LaunchParameterKind>(); + + LOG_INFO(Service_AM, "called, kind={:08X}", kind); + + if (kind == LaunchParameterKind::UserChannel) { + auto channel = system.GetUserChannel(); + if (channel.empty()) { + LOG_ERROR(Service_AM, "Attempted to load launch parameter but none was found!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultNoDataInChannel); + return; + } + + auto data = channel.back(); + channel.pop_back(); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IStorage>(system, std::move(data)); + } else if (kind == LaunchParameterKind::AccountPreselectedUser && + !launch_popped_account_preselect) { + // TODO: Verify this is hw-accurate + LaunchParameterAccountPreselectedUser params{}; + + params.magic = LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC; + params.is_account_selected = 1; + + Account::ProfileManager profile_manager{}; + const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user)); + ASSERT(uuid.has_value() && uuid->IsValid()); + params.current_user = *uuid; + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + + std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); + std::memcpy(buffer.data(), ¶ms, buffer.size()); + + rb.PushIpcInterface<IStorage>(system, std::move(buffer)); + launch_popped_account_preselect = true; + } else { + LOG_ERROR(Service_AM, "Unknown launch parameter kind."); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultNoDataInChannel); + } +} + +void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + u128 user_id = rp.PopRaw<u128>(); + + LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]); + + FileSys::SaveDataAttribute attribute{}; + attribute.title_id = system.GetApplicationProcessProgramID(); + attribute.user_id = user_id; + attribute.type = FileSys::SaveDataType::SaveData; + + FileSys::VirtualDir save_data{}; + const auto res = system.GetFileSystemController().OpenSaveDataController()->CreateSaveData( + &save_data, FileSys::SaveDataSpaceId::NandUser, attribute); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.Push<u64>(0); +} + +void IApplicationFunctions::SetTerminateResult(HLERequestContext& ctx) { + // Takes an input u32 Result, no output. + // For example, in some cases official apps use this with error 0x2A2 then + // uses svcBreak. + + IPC::RequestParser rp{ctx}; + u32 result = rp.Pop<u32>(); + LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::GetDisplayVersion(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + std::array<u8, 0x10> version_string{}; + + const auto res = [this] { + const auto title_id = system.GetApplicationProcessProgramID(); + + const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), + system.GetContentProvider()}; + auto metadata = pm.GetControlMetadata(); + if (metadata.first != nullptr) { + return metadata; + } + + const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), + system.GetFileSystemController(), + system.GetContentProvider()}; + return pm_update.GetControlMetadata(); + }(); + + if (res.first != nullptr) { + const auto& version = res.first->GetVersionString(); + std::copy(version.begin(), version.end(), version_string.begin()); + } else { + static constexpr char default_version[]{"1.0.0"}; + std::memcpy(version_string.data(), default_version, sizeof(default_version)); + } + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.PushRaw(version_string); +} + +void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) { + // 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 auto title_id = system.GetApplicationProcessProgramID(); + + const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), + system.GetContentProvider()}; + auto metadata = pm.GetControlMetadata(); + if (metadata.first != nullptr) { + return metadata; + } + + const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_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{}; + const auto res_lang = + app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages); + if (res_lang != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res_lang); + return; + } + + // Convert to settings language code. + u64 language_code{}; + const auto res_code = + app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language); + if (res_code != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res_code); + return; + } + + LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(language_code); +} + +void IApplicationFunctions::IsGamePlayRecordingSupported(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + constexpr bool gameplay_recording_supported = false; + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(gameplay_recording_supported); +} + +void IApplicationFunctions::InitializeGamePlayRecording(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::SetGamePlayRecordingState(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::NotifyRunning(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u8>(0); // Unknown, seems to be ignored by official processes +} + +void IApplicationFunctions::GetPseudoDeviceId(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + + // Returns a 128-bit UUID + rb.Push<u64>(0); + rb.Push<u64>(0); +} + +void IApplicationFunctions::ExtendSaveData(HLERequestContext& ctx) { + struct Parameters { + FileSys::SaveDataType type; + u128 user_id; + u64 new_normal_size; + u64 new_journal_size; + }; + static_assert(sizeof(Parameters) == 40); + + IPC::RequestParser rp{ctx}; + const auto [type, user_id, new_normal_size, new_journal_size] = rp.PopRaw<Parameters>(); + + LOG_DEBUG(Service_AM, + "called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, " + "new_journal={:016X}", + static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size); + + system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize( + type, system.GetApplicationProcessProgramID(), user_id, + {new_normal_size, new_journal_size}); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + + // The following value is used upon failure to help the system recover. + // Since we always succeed, this should be 0. + rb.Push<u64>(0); +} + +void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) { + struct Parameters { + FileSys::SaveDataType type; + u128 user_id; + }; + static_assert(sizeof(Parameters) == 24); + + IPC::RequestParser rp{ctx}; + const auto [type, user_id] = rp.PopRaw<Parameters>(); + + LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1], + user_id[0]); + + const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize( + type, system.GetApplicationProcessProgramID(), user_id); + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.Push(size.normal); + rb.Push(size.journal); +} + +void IApplicationFunctions::CreateCacheStorage(HLERequestContext& ctx) { + struct InputParameters { + u16 index; + s64 size; + s64 journal_size; + }; + static_assert(sizeof(InputParameters) == 24); + + struct OutputParameters { + u32 storage_target; + u64 required_size; + }; + static_assert(sizeof(OutputParameters) == 16); + + IPC::RequestParser rp{ctx}; + const auto params = rp.PopRaw<InputParameters>(); + + LOG_WARNING(Service_AM, "(STUBBED) called with index={}, size={:#x}, journal_size={:#x}", + params.index, params.size, params.journal_size); + + const OutputParameters resp{ + .storage_target = 1, + .required_size = 0, + }; + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.PushRaw(resp); +} + +void IApplicationFunctions::GetSaveDataSizeMax(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + constexpr u64 size_max_normal = 0xFFFFFFF; + constexpr u64 size_max_journal = 0xFFFFFFF; + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.Push(size_max_normal); + rb.Push(size_max_journal); +} + +void IApplicationFunctions::QueryApplicationPlayStatistics(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u32>(0); +} + +void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u32>(0); +} + +void IApplicationFunctions::ExecuteProgram(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::RequestParser rp{ctx}; + [[maybe_unused]] const auto unk_1 = rp.Pop<u32>(); + [[maybe_unused]] const auto unk_2 = rp.Pop<u32>(); + const auto program_index = rp.Pop<u64>(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + + system.ExecuteProgram(program_index); +} + +void IApplicationFunctions::ClearUserChannel(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + system.GetUserChannel().clear(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::UnpopToUserChannel(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::RequestParser rp{ctx}; + const auto storage = rp.PopIpcInterface<IStorage>().lock(); + if (storage) { + system.GetUserChannel().push_back(storage->GetData()); + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::GetPreviousProgramIndex(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<s32>(previous_program_index); +} + +void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(gpu_error_detected_event->GetReadableEvent()); +} + +void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(friend_invitation_storage_channel_event->GetReadableEvent()); +} + +void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultNoDataInChannel); +} + +void IApplicationFunctions::GetNotificationStorageChannelEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(notification_storage_channel_event->GetReadableEvent()); +} + +void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent()); +} + +void IApplicationFunctions::PrepareForJit(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/application_functions.h b/src/core/hle/service/am/application_functions.h new file mode 100644 index 000000000..22aab1c8f --- /dev/null +++ b/src/core/hle/service/am/application_functions.h @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { +public: + explicit IApplicationFunctions(Core::System& system_); + ~IApplicationFunctions() override; + +private: + void PopLaunchParameter(HLERequestContext& ctx); + void CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx); + void EnsureSaveData(HLERequestContext& ctx); + void SetTerminateResult(HLERequestContext& ctx); + void GetDisplayVersion(HLERequestContext& ctx); + void GetDesiredLanguage(HLERequestContext& ctx); + void IsGamePlayRecordingSupported(HLERequestContext& ctx); + void InitializeGamePlayRecording(HLERequestContext& ctx); + void SetGamePlayRecordingState(HLERequestContext& ctx); + void NotifyRunning(HLERequestContext& ctx); + void GetPseudoDeviceId(HLERequestContext& ctx); + void ExtendSaveData(HLERequestContext& ctx); + void GetSaveDataSize(HLERequestContext& ctx); + void CreateCacheStorage(HLERequestContext& ctx); + void GetSaveDataSizeMax(HLERequestContext& ctx); + void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx); + void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx); + void BeginBlockingHomeButton(HLERequestContext& ctx); + void EndBlockingHomeButton(HLERequestContext& ctx); + void EnableApplicationCrashReport(HLERequestContext& ctx); + void InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx); + void SetApplicationCopyrightImage(HLERequestContext& ctx); + void SetApplicationCopyrightVisibility(HLERequestContext& ctx); + void QueryApplicationPlayStatistics(HLERequestContext& ctx); + void QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx); + void ExecuteProgram(HLERequestContext& ctx); + void ClearUserChannel(HLERequestContext& ctx); + void UnpopToUserChannel(HLERequestContext& ctx); + void GetPreviousProgramIndex(HLERequestContext& ctx); + void GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx); + void GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx); + void TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx); + void GetNotificationStorageChannelEvent(HLERequestContext& ctx); + void GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx); + void PrepareForJit(HLERequestContext& ctx); + + KernelHelpers::ServiceContext service_context; + + bool launch_popped_account_preselect = false; + s32 previous_program_index{-1}; + Kernel::KEvent* gpu_error_detected_event; + Kernel::KEvent* friend_invitation_storage_channel_event; + Kernel::KEvent* notification_storage_channel_event; + Kernel::KEvent* health_warning_disappeared_system_event; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/application_proxy.cpp b/src/core/hle/service/am/application_proxy.cpp new file mode 100644 index 000000000..e9cd0aa71 --- /dev/null +++ b/src/core/hle/service/am/application_proxy.cpp @@ -0,0 +1,114 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applet_common_functions.h" +#include "core/hle/service/am/application_functions.h" +#include "core/hle/service/am/application_proxy.h" +#include "core/hle/service/am/audio_controller.h" +#include "core/hle/service/am/common_state_getter.h" +#include "core/hle/service/am/debug_functions.h" +#include "core/hle/service/am/display_controller.h" +#include "core/hle/service/am/library_applet_creator.h" +#include "core/hle/service/am/library_applet_self_accessor.h" +#include "core/hle/service/am/process_winding_controller.h" +#include "core/hle/service/am/self_controller.h" +#include "core/hle/service/am/window_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IApplicationProxy::IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, + std::shared_ptr<AppletMessageQueue> msg_queue_, + Core::System& system_) + : ServiceFramework{system_, "IApplicationProxy"}, nvnflinger{nvnflinger_}, + msg_queue{std::move(msg_queue_)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"}, + {1, &IApplicationProxy::GetSelfController, "GetSelfController"}, + {2, &IApplicationProxy::GetWindowController, "GetWindowController"}, + {3, &IApplicationProxy::GetAudioController, "GetAudioController"}, + {4, &IApplicationProxy::GetDisplayController, "GetDisplayController"}, + {10, &IApplicationProxy::GetProcessWindingController, "GetProcessWindingController"}, + {11, &IApplicationProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, + {20, &IApplicationProxy::GetApplicationFunctions, "GetApplicationFunctions"}, + {1000, &IApplicationProxy::GetDebugFunctions, "GetDebugFunctions"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +void IApplicationProxy::GetAudioController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IAudioController>(system); +} + +void IApplicationProxy::GetDisplayController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IDisplayController>(system); +} + +void IApplicationProxy::GetProcessWindingController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IProcessWindingController>(system); +} + +void IApplicationProxy::GetDebugFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IDebugFunctions>(system); +} + +void IApplicationProxy::GetWindowController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IWindowController>(system); +} + +void IApplicationProxy::GetSelfController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ISelfController>(system, nvnflinger); +} + +void IApplicationProxy::GetCommonStateGetter(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue); +} + +void IApplicationProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILibraryAppletCreator>(system); +} + +void IApplicationProxy::GetApplicationFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IApplicationFunctions>(system); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/application_proxy.h b/src/core/hle/service/am/application_proxy.h new file mode 100644 index 000000000..4f620242b --- /dev/null +++ b/src/core/hle/service/am/application_proxy.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/am/applet_message_queue.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { +public: + explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, + std::shared_ptr<AppletMessageQueue> msg_queue_, + Core::System& system_); + +private: + void GetAudioController(HLERequestContext& ctx); + void GetDisplayController(HLERequestContext& ctx); + void GetProcessWindingController(HLERequestContext& ctx); + void GetDebugFunctions(HLERequestContext& ctx); + void GetWindowController(HLERequestContext& ctx); + void GetSelfController(HLERequestContext& ctx); + void GetCommonStateGetter(HLERequestContext& ctx); + void GetLibraryAppletCreator(HLERequestContext& ctx); + void GetApplicationFunctions(HLERequestContext& ctx); + + Nvnflinger::Nvnflinger& nvnflinger; + std::shared_ptr<AppletMessageQueue> msg_queue; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/audio_controller.cpp b/src/core/hle/service/am/audio_controller.cpp new file mode 100644 index 000000000..ae75db174 --- /dev/null +++ b/src/core/hle/service/am/audio_controller.cpp @@ -0,0 +1,91 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/audio_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IAudioController::IAudioController(Core::System& system_) + : ServiceFramework{system_, "IAudioController"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IAudioController::SetExpectedMasterVolume, "SetExpectedMasterVolume"}, + {1, &IAudioController::GetMainAppletExpectedMasterVolume, "GetMainAppletExpectedMasterVolume"}, + {2, &IAudioController::GetLibraryAppletExpectedMasterVolume, "GetLibraryAppletExpectedMasterVolume"}, + {3, &IAudioController::ChangeMainAppletMasterVolume, "ChangeMainAppletMasterVolume"}, + {4, &IAudioController::SetTransparentAudioRate, "SetTransparentVolumeRate"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IAudioController::~IAudioController() = default; + +void IAudioController::SetExpectedMasterVolume(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const float main_applet_volume_tmp = rp.Pop<float>(); + const float library_applet_volume_tmp = rp.Pop<float>(); + + LOG_DEBUG(Service_AM, "called. main_applet_volume={}, library_applet_volume={}", + main_applet_volume_tmp, library_applet_volume_tmp); + + // Ensure the volume values remain within the 0-100% range + main_applet_volume = std::clamp(main_applet_volume_tmp, min_allowed_volume, max_allowed_volume); + library_applet_volume = + std::clamp(library_applet_volume_tmp, min_allowed_volume, max_allowed_volume); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IAudioController::GetMainAppletExpectedMasterVolume(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called. main_applet_volume={}", main_applet_volume); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(main_applet_volume); +} + +void IAudioController::GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called. library_applet_volume={}", library_applet_volume); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(library_applet_volume); +} + +void IAudioController::ChangeMainAppletMasterVolume(HLERequestContext& ctx) { + struct Parameters { + float volume; + s64 fade_time_ns; + }; + static_assert(sizeof(Parameters) == 16); + + IPC::RequestParser rp{ctx}; + const auto parameters = rp.PopRaw<Parameters>(); + + LOG_DEBUG(Service_AM, "called. volume={}, fade_time_ns={}", parameters.volume, + parameters.fade_time_ns); + + main_applet_volume = std::clamp(parameters.volume, min_allowed_volume, max_allowed_volume); + fade_time_ns = std::chrono::nanoseconds{parameters.fade_time_ns}; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IAudioController::SetTransparentAudioRate(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const float transparent_volume_rate_tmp = rp.Pop<float>(); + + LOG_DEBUG(Service_AM, "called. transparent_volume_rate={}", transparent_volume_rate_tmp); + + // Clamp volume range to 0-100%. + transparent_volume_rate = + std::clamp(transparent_volume_rate_tmp, min_allowed_volume, max_allowed_volume); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/audio_controller.h b/src/core/hle/service/am/audio_controller.h new file mode 100644 index 000000000..a47e3bad8 --- /dev/null +++ b/src/core/hle/service/am/audio_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/service.h" + +namespace Service::AM { + +class IAudioController final : public ServiceFramework<IAudioController> { +public: + explicit IAudioController(Core::System& system_); + ~IAudioController() override; + +private: + void SetExpectedMasterVolume(HLERequestContext& ctx); + void GetMainAppletExpectedMasterVolume(HLERequestContext& ctx); + void GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx); + void ChangeMainAppletMasterVolume(HLERequestContext& ctx); + void SetTransparentAudioRate(HLERequestContext& ctx); + + static constexpr float min_allowed_volume = 0.0f; + static constexpr float max_allowed_volume = 1.0f; + + float main_applet_volume{0.25f}; + float library_applet_volume{max_allowed_volume}; + float transparent_volume_rate{min_allowed_volume}; + + // 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 fade_time_ns{0}; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/common_state_getter.cpp b/src/core/hle/service/am/common_state_getter.cpp new file mode 100644 index 000000000..0b54b769d --- /dev/null +++ b/src/core/hle/service/am/common_state_getter.cpp @@ -0,0 +1,288 @@ +// 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/common_state_getter.h" +#include "core/hle/service/am/lock_accessor.h" +#include "core/hle/service/apm/apm_controller.h" +#include "core/hle/service/apm/apm_interface.h" +#include "core/hle/service/ipc_helpers.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<AppletMessageQueue> msg_queue_) + : ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)}, + service_context{system_, "ICommonStateGetter"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, + {1, &ICommonStateGetter::ReceiveMessage, "ReceiveMessage"}, + {2, nullptr, "GetThisAppletKind"}, + {3, nullptr, "AllowToEnterSleep"}, + {4, nullptr, "DisallowToEnterSleep"}, + {5, &ICommonStateGetter::GetOperationMode, "GetOperationMode"}, + {6, &ICommonStateGetter::GetPerformanceMode, "GetPerformanceMode"}, + {7, nullptr, "GetCradleStatus"}, + {8, &ICommonStateGetter::GetBootMode, "GetBootMode"}, + {9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"}, + {10, &ICommonStateGetter::RequestToAcquireSleepLock, "RequestToAcquireSleepLock"}, + {11, nullptr, "ReleaseSleepLock"}, + {12, nullptr, "ReleaseSleepLockTransiently"}, + {13, &ICommonStateGetter::GetAcquiredSleepLockEvent, "GetAcquiredSleepLockEvent"}, + {14, nullptr, "GetWakeupCount"}, + {20, nullptr, "PushToGeneralChannel"}, + {30, nullptr, "GetHomeButtonReaderLockAccessor"}, + {31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"}, + {32, nullptr, "GetWriterLockAccessorEx"}, + {40, nullptr, "GetCradleFwVersion"}, + {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"}, + {51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"}, + {52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"}, + {53, &ICommonStateGetter::BeginVrModeEx, "BeginVrModeEx"}, + {54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"}, + {55, nullptr, "IsInControllerFirmwareUpdateSection"}, + {59, nullptr, "SetVrPositionForDebug"}, + {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"}, + {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"}, + {62, nullptr, "GetHdcpAuthenticationState"}, + {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"}, + {64, nullptr, "SetTvPowerStateMatchingMode"}, + {65, nullptr, "GetApplicationIdByContentActionName"}, + {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"}, + {67, nullptr, "CancelCpuBoostMode"}, + {68, &ICommonStateGetter::GetBuiltInDisplayType, "GetBuiltInDisplayType"}, + {80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"}, + {90, nullptr, "SetPerformanceConfigurationChangedNotification"}, + {91, nullptr, "GetCurrentPerformanceConfiguration"}, + {100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"}, + {110, nullptr, "OpenMyGpuErrorHandler"}, + {120, nullptr, "GetAppletLaunchedHistory"}, + {200, nullptr, "GetOperationModeSystemInfo"}, + {300, &ICommonStateGetter::GetSettingsPlatformRegion, "GetSettingsPlatformRegion"}, + {400, nullptr, "ActivateMigrationService"}, + {401, nullptr, "DeactivateMigrationService"}, + {500, nullptr, "DisableSleepTillShutdown"}, + {501, nullptr, "SuppressDisablingSleepTemporarily"}, + {502, nullptr, "IsSleepEnabled"}, + {503, nullptr, "IsDisablingSleepSuppressed"}, + {900, &ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"}, + }; + // clang-format on + + RegisterHandlers(functions); + + sleep_lock_event = service_context.CreateEvent("ICommonStateGetter::SleepLockEvent"); + + // Configure applets to be in foreground state + msg_queue->PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); + msg_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); +} + +ICommonStateGetter::~ICommonStateGetter() { + service_context.CloseEvent(sleep_lock_event); +}; + +void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode +} + +void ICommonStateGetter::GetEventHandle(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(msg_queue->GetMessageReceiveEvent()); +} + +void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + const auto message = msg_queue->PopMessage(); + IPC::ResponseBuilder rb{ctx, 3}; + + if (message == AppletMessageQueue::AppletMessage::None) { + LOG_ERROR(Service_AM, "Message queue is empty"); + rb.Push(AM::ResultNoMessages); + rb.PushEnum<AppletMessageQueue::AppletMessage>(message); + return; + } + + rb.Push(ResultSuccess); + rb.PushEnum<AppletMessageQueue::AppletMessage>(message); +} + +void ICommonStateGetter::GetCurrentFocusState(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast<u8>(FocusState::InFocus)); +} + +void ICommonStateGetter::GetOperationMode(HLERequestContext& ctx) { + const bool use_docked_mode{Settings::IsDockedMode()}; + LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld)); +} + +void ICommonStateGetter::GetPerformanceMode(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(system.GetAPMController().GetCurrentPerformanceMode()); +} + +void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + // Sleep lock is acquired immediately. + sleep_lock_event->Signal(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ICommonStateGetter::GetReaderLockAccessorEx(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto unknown = rp.Pop<u32>(); + + LOG_INFO(Service_AM, "called, unknown={}", unknown); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILockAccessor>(system); +} + +void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(sleep_lock_event->GetReadableEvent()); +} + +void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(vr_mode_state); +} + +void ICommonStateGetter::SetVrModeEnabled(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + vr_mode_state = rp.Pop<bool>(); + + LOG_WARNING(Service_AM, "VR Mode is {}", vr_mode_state ? "on" : "off"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ICommonStateGetter::SetLcdBacklighOffEnabled(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto is_lcd_backlight_off_enabled = rp.Pop<bool>(); + + LOG_WARNING(Service_AM, "(STUBBED) called. is_lcd_backlight_off_enabled={}", + is_lcd_backlight_off_enabled); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ICommonStateGetter::BeginVrModeEx(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ICommonStateGetter::EndVrModeEx(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent()); +} + +void ICommonStateGetter::GetDefaultDisplayResolution(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + + if (Settings::IsDockedMode()) { + rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); + rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); + } else { + rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); + rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight)); + } +} + +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); +} + +void ICommonStateGetter::GetBuiltInDisplayType(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(0); +} + +void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto system_button{rp.PopEnum<SystemButtonType>()}; + + LOG_WARNING(Service_AM, "(STUBBED) called, system_button={}", system_button); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ICommonStateGetter::GetSettingsPlatformRegion(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(SysPlatformRegion::Global); +} + +void ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled( + HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/common_state_getter.h b/src/core/hle/service/am/common_state_getter.h new file mode 100644 index 000000000..11d66f10a --- /dev/null +++ b/src/core/hle/service/am/common_state_getter.h @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/service.h" + +#include "core/hle/service/am/applet_message_queue.h" + +namespace Service::AM { + +class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { +public: + explicit ICommonStateGetter(Core::System& system_, + std::shared_ptr<AppletMessageQueue> msg_queue_); + ~ICommonStateGetter() override; + +private: + // This is nn::oe::FocusState + enum class FocusState : u8 { + InFocus = 1, + NotInFocus = 2, + Background = 3, + }; + + // This is nn::oe::OperationMode + enum class OperationMode : u8 { + Handheld = 0, + Docked = 1, + }; + + // This is nn::am::service::SystemButtonType + enum class SystemButtonType { + None, + HomeButtonShortPressing, + HomeButtonLongPressing, + PowerButtonShortPressing, + PowerButtonLongPressing, + ShutdownSystem, + CaptureButtonShortPressing, + CaptureButtonLongPressing, + }; + + enum class SysPlatformRegion : s32 { + Global = 1, + Terra = 2, + }; + + void GetEventHandle(HLERequestContext& ctx); + void ReceiveMessage(HLERequestContext& ctx); + void GetCurrentFocusState(HLERequestContext& ctx); + void RequestToAcquireSleepLock(HLERequestContext& ctx); + void GetAcquiredSleepLockEvent(HLERequestContext& ctx); + void GetReaderLockAccessorEx(HLERequestContext& ctx); + void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx); + void GetOperationMode(HLERequestContext& ctx); + void GetPerformanceMode(HLERequestContext& ctx); + void GetBootMode(HLERequestContext& ctx); + void IsVrModeEnabled(HLERequestContext& ctx); + void SetVrModeEnabled(HLERequestContext& ctx); + void SetLcdBacklighOffEnabled(HLERequestContext& ctx); + void BeginVrModeEx(HLERequestContext& ctx); + void EndVrModeEx(HLERequestContext& ctx); + void GetDefaultDisplayResolution(HLERequestContext& ctx); + void SetCpuBoostMode(HLERequestContext& ctx); + void GetBuiltInDisplayType(HLERequestContext& ctx); + void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx); + void GetSettingsPlatformRegion(HLERequestContext& ctx); + void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx); + + std::shared_ptr<AppletMessageQueue> msg_queue; + bool vr_mode_state{}; + Kernel::KEvent* sleep_lock_event; + KernelHelpers::ServiceContext service_context; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/debug_functions.cpp b/src/core/hle/service/am/debug_functions.cpp new file mode 100644 index 000000000..f80b970f2 --- /dev/null +++ b/src/core/hle/service/am/debug_functions.cpp @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/debug_functions.h" +#include "core/hle/service/ipc_helpers.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/debug_functions.h b/src/core/hle/service/am/debug_functions.h new file mode 100644 index 000000000..d55968743 --- /dev/null +++ b/src/core/hle/service/am/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/display_controller.cpp b/src/core/hle/service/am/display_controller.cpp new file mode 100644 index 000000000..d4d3d60e7 --- /dev/null +++ b/src/core/hle/service/am/display_controller.cpp @@ -0,0 +1,97 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/display_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IDisplayController::IDisplayController(Core::System& system_) + : ServiceFramework{system_, "IDisplayController"} { + // 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, &IDisplayController::GetCallerAppletCaptureImageEx, "GetCallerAppletCaptureImageEx"}, + {8, &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, nullptr, "ClearCaptureBuffer"}, + {21, nullptr, "ClearAppletTransitionBuffer"}, + {22, nullptr, "AcquireLastApplicationCaptureSharedBuffer"}, + {23, nullptr, "ReleaseLastApplicationCaptureSharedBuffer"}, + {24, &IDisplayController::AcquireLastForegroundCaptureSharedBuffer, "AcquireLastForegroundCaptureSharedBuffer"}, + {25, &IDisplayController::ReleaseLastForegroundCaptureSharedBuffer, "ReleaseLastForegroundCaptureSharedBuffer"}, + {26, &IDisplayController::AcquireCallerAppletCaptureSharedBuffer, "AcquireCallerAppletCaptureSharedBuffer"}, + {27, &IDisplayController::ReleaseCallerAppletCaptureSharedBuffer, "ReleaseCallerAppletCaptureSharedBuffer"}, + {28, nullptr, "TakeScreenShotOfOwnLayerEx"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IDisplayController::~IDisplayController() = default; + +void IDisplayController::GetCallerAppletCaptureImageEx(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(1u); + rb.Push(1); +} + +void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IDisplayController::AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(1U); + rb.Push(1); +} + +void IDisplayController::ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IDisplayController::AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(1U); + rb.Push(1); +} + +void IDisplayController::ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/display_controller.h b/src/core/hle/service/am/display_controller.h new file mode 100644 index 000000000..32f819294 --- /dev/null +++ b/src/core/hle/service/am/display_controller.h @@ -0,0 +1,24 @@ +// 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 IDisplayController final : public ServiceFramework<IDisplayController> { +public: + explicit IDisplayController(Core::System& system_); + ~IDisplayController() override; + +private: + void GetCallerAppletCaptureImageEx(HLERequestContext& ctx); + void TakeScreenShotOfOwnLayer(HLERequestContext& ctx); + void AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx); + void ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx); + void AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx); + void ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx); +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/global_state_controller.cpp b/src/core/hle/service/am/global_state_controller.cpp new file mode 100644 index 000000000..ed0eb7108 --- /dev/null +++ b/src/core/hle/service/am/global_state_controller.cpp @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/global_state_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IGlobalStateController::IGlobalStateController(Core::System& system_) + : ServiceFramework{system_, "IGlobalStateController"} { + // 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, nullptr, "LoadAndApplyIdlePolicySettings"}, + {11, nullptr, "NotifyCecSettingsChanged"}, + {12, nullptr, "SetDefaultHomeButtonLongPressTime"}, + {13, nullptr, "UpdateDefaultDisplayResolution"}, + {14, nullptr, "ShouldSleepOnBoot"}, + {15, nullptr, "GetHdcpAuthenticationFailedEvent"}, + {30, nullptr, "OpenCradleFirmwareUpdater"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IGlobalStateController::~IGlobalStateController() = default; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/global_state_controller.h b/src/core/hle/service/am/global_state_controller.h new file mode 100644 index 000000000..7125464a1 --- /dev/null +++ b/src/core/hle/service/am/global_state_controller.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 IGlobalStateController final : public ServiceFramework<IGlobalStateController> { +public: + explicit IGlobalStateController(Core::System& system_); + ~IGlobalStateController() override; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/home_menu_functions.cpp b/src/core/hle/service/am/home_menu_functions.cpp new file mode 100644 index 000000000..640e9fbb7 --- /dev/null +++ b/src/core/hle/service/am/home_menu_functions.cpp @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/home_menu_functions.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_) + : ServiceFramework{system_, "IHomeMenuFunctions"}, service_context{system, + "IHomeMenuFunctions"} { + // clang-format off + static const FunctionInfo functions[] = { + {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"}, + {11, nullptr, "LockForeground"}, + {12, nullptr, "UnlockForeground"}, + {20, nullptr, "PopFromGeneralChannel"}, + {21, &IHomeMenuFunctions::GetPopFromGeneralChannelEvent, "GetPopFromGeneralChannelEvent"}, + {30, nullptr, "GetHomeButtonWriterLockAccessor"}, + {31, nullptr, "GetWriterLockAccessorEx"}, + {40, nullptr, "IsSleepEnabled"}, + {41, nullptr, "IsRebootEnabled"}, + {50, nullptr, "LaunchSystemApplet"}, + {51, nullptr, "LaunchStarter"}, + {100, nullptr, "PopRequestLaunchApplicationForDebug"}, + {110, nullptr, "IsForceTerminateApplicationDisabledForDebug"}, + {200, nullptr, "LaunchDevMenu"}, + {1000, nullptr, "SetLastApplicationExitReason"}, + }; + // clang-format on + + RegisterHandlers(functions); + + pop_from_general_channel_event = + service_context.CreateEvent("IHomeMenuFunctions:PopFromGeneralChannelEvent"); +} + +IHomeMenuFunctions::~IHomeMenuFunctions() { + service_context.CloseEvent(pop_from_general_channel_event); +} + +void IHomeMenuFunctions::RequestToGetForeground(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(pop_from_general_channel_event->GetReadableEvent()); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/home_menu_functions.h b/src/core/hle/service/am/home_menu_functions.h new file mode 100644 index 000000000..e082d5d73 --- /dev/null +++ b/src/core/hle/service/am/home_menu_functions.h @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { +public: + explicit IHomeMenuFunctions(Core::System& system_); + ~IHomeMenuFunctions() override; + +private: + void RequestToGetForeground(HLERequestContext& ctx); + void GetPopFromGeneralChannelEvent(HLERequestContext& ctx); + + KernelHelpers::ServiceContext service_context; + + Kernel::KEvent* pop_from_general_channel_event; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_accessor.cpp b/src/core/hle/service/am/library_applet_accessor.cpp new file mode 100644 index 000000000..1cccdfcf2 --- /dev/null +++ b/src/core/hle/service/am/library_applet_accessor.cpp @@ -0,0 +1,178 @@ +// 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_accessor.h" +#include "core/hle/service/am/storage.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_, + std::shared_ptr<Applets::Applet> applet_) + : ServiceFramework{system_, "ILibraryAppletAccessor"}, applet{std::move(applet_)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, + {1, &ILibraryAppletAccessor::IsCompleted, "IsCompleted"}, + {10, &ILibraryAppletAccessor::Start, "Start"}, + {20, &ILibraryAppletAccessor::RequestExit, "RequestExit"}, + {25, nullptr, "Terminate"}, + {30, &ILibraryAppletAccessor::GetResult, "GetResult"}, + {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, + {60, &ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero, "PresetLibraryAppletGpuTimeSliceZero"}, + {100, &ILibraryAppletAccessor::PushInData, "PushInData"}, + {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"}, + {102, nullptr, "PushExtraStorage"}, + {103, &ILibraryAppletAccessor::PushInteractiveInData, "PushInteractiveInData"}, + {104, &ILibraryAppletAccessor::PopInteractiveOutData, "PopInteractiveOutData"}, + {105, &ILibraryAppletAccessor::GetPopOutDataEvent, "GetPopOutDataEvent"}, + {106, &ILibraryAppletAccessor::GetPopInteractiveOutDataEvent, "GetPopInteractiveOutDataEvent"}, + {110, nullptr, "NeedsToExitProcess"}, + {120, nullptr, "GetLibraryAppletInfo"}, + {150, nullptr, "RequestForAppletToGetForeground"}, + {160, &ILibraryAppletAccessor::GetIndirectLayerConsumerHandle, "GetIndirectLayerConsumerHandle"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +void ILibraryAppletAccessor::GetAppletStateChangedEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(applet->GetBroker().GetStateChangedEvent()); +} + +void ILibraryAppletAccessor::IsCompleted(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u32>(applet->TransactionComplete()); +} + +void ILibraryAppletAccessor::GetResult(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(applet->GetStatus()); +} + +void ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletAccessor::Start(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + ASSERT(applet != nullptr); + + applet->Initialize(); + applet->Execute(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletAccessor::RequestExit(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + ASSERT(applet != nullptr); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(applet->RequestExit()); +} + +void ILibraryAppletAccessor::PushInData(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::RequestParser rp{ctx}; + applet->GetBroker().PushNormalDataFromGame(rp.PopIpcInterface<IStorage>().lock()); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletAccessor::PopOutData(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + auto storage = applet->GetBroker().PopNormalDataToGame(); + if (storage == nullptr) { + LOG_DEBUG(Service_AM, + "storage is a nullptr. There is no data in the current normal channel"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultNoDataInChannel); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IStorage>(std::move(storage)); +} + +void ILibraryAppletAccessor::PushInteractiveInData(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::RequestParser rp{ctx}; + applet->GetBroker().PushInteractiveDataFromGame(rp.PopIpcInterface<IStorage>().lock()); + + ASSERT(applet->IsInitialized()); + applet->ExecuteInteractive(); + applet->Execute(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletAccessor::PopInteractiveOutData(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + auto storage = applet->GetBroker().PopInteractiveDataToGame(); + if (storage == nullptr) { + LOG_DEBUG(Service_AM, + "storage is a nullptr. There is no data in the current interactive channel"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultNoDataInChannel); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IStorage>(std::move(storage)); +} + +void ILibraryAppletAccessor::GetPopOutDataEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent()); +} + +void ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent()); +} + +void ILibraryAppletAccessor::GetIndirectLayerConsumerHandle(HLERequestContext& ctx) { + 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 + constexpr u64 handle = 0xdeadbeef; + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(handle); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_accessor.h b/src/core/hle/service/am/library_applet_accessor.h new file mode 100644 index 000000000..698467233 --- /dev/null +++ b/src/core/hle/service/am/library_applet_accessor.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/am/applets/applets.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { +public: + explicit ILibraryAppletAccessor(Core::System& system_, + std::shared_ptr<Applets::Applet> applet_); + +private: + void GetAppletStateChangedEvent(HLERequestContext& ctx); + void IsCompleted(HLERequestContext& ctx); + void GetResult(HLERequestContext& ctx); + void PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx); + void Start(HLERequestContext& ctx); + void RequestExit(HLERequestContext& ctx); + void PushInData(HLERequestContext& ctx); + void PopOutData(HLERequestContext& ctx); + void PushInteractiveInData(HLERequestContext& ctx); + void PopInteractiveOutData(HLERequestContext& ctx); + void GetPopOutDataEvent(HLERequestContext& ctx); + void GetPopInteractiveOutDataEvent(HLERequestContext& ctx); + void GetIndirectLayerConsumerHandle(HLERequestContext& ctx); + + std::shared_ptr<Applets::Applet> applet; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_creator.cpp b/src/core/hle/service/am/library_applet_creator.cpp new file mode 100644 index 000000000..c33f50a40 --- /dev/null +++ b/src/core/hle/service/am/library_applet_creator.cpp @@ -0,0 +1,145 @@ +// 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/applets/applets.h" +#include "core/hle/service/am/library_applet_accessor.h" +#include "core/hle/service/am/library_applet_creator.h" +#include "core/hle/service/am/storage.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_) + : ServiceFramework{system_, "ILibraryAppletCreator"} { + static const FunctionInfo functions[] = { + {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"}, + {1, nullptr, "TerminateAllLibraryApplets"}, + {2, nullptr, "AreAnyLibraryAppletsLeft"}, + {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"}, + {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"}, + {12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"}, + }; + RegisterHandlers(functions); +} + +ILibraryAppletCreator::~ILibraryAppletCreator() = default; + +void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto applet_id = rp.PopRaw<Applets::AppletId>(); + const auto applet_mode = rp.PopRaw<Applets::LibraryAppletMode>(); + + LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, + applet_mode); + + const auto& applet_manager{system.GetAppletManager()}; + const auto applet = applet_manager.GetApplet(applet_id, applet_mode); + + if (applet == nullptr) { + LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet); +} + +void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const s64 size{rp.Pop<s64>()}; + + LOG_DEBUG(Service_AM, "called, size={}", size); + + if (size <= 0) { + LOG_ERROR(Service_AM, "size is less than or equal to 0"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + std::vector<u8> buffer(size); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IStorage>(system, std::move(buffer)); +} + +void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + struct Parameters { + u8 permissions; + s64 size; + }; + + const auto parameters{rp.PopRaw<Parameters>()}; + const auto handle{ctx.GetCopyHandle(0)}; + + LOG_DEBUG(Service_AM, "called, permissions={}, size={}, handle={:08X}", parameters.permissions, + parameters.size, handle); + + if (parameters.size <= 0) { + LOG_ERROR(Service_AM, "size is less than or equal to 0"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle); + + if (transfer_mem.IsNull()) { + LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + std::vector<u8> memory(transfer_mem->GetSize()); + ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size()); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IStorage>(system, std::move(memory)); +} + +void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const s64 size{rp.Pop<s64>()}; + const auto handle{ctx.GetCopyHandle(0)}; + + LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle); + + if (size <= 0) { + LOG_ERROR(Service_AM, "size is less than or equal to 0"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle); + + if (transfer_mem.IsNull()) { + LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + std::vector<u8> memory(transfer_mem->GetSize()); + ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size()); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IStorage>(system, std::move(memory)); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_creator.h b/src/core/hle/service/am/library_applet_creator.h new file mode 100644 index 000000000..97f236fbc --- /dev/null +++ b/src/core/hle/service/am/library_applet_creator.h @@ -0,0 +1,22 @@ +// 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 ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { +public: + explicit ILibraryAppletCreator(Core::System& system_); + ~ILibraryAppletCreator() override; + +private: + void CreateLibraryApplet(HLERequestContext& ctx); + void CreateStorage(HLERequestContext& ctx); + void CreateTransferMemoryStorage(HLERequestContext& ctx); + void CreateHandleStorage(HLERequestContext& ctx); +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_proxy.cpp b/src/core/hle/service/am/library_applet_proxy.cpp new file mode 100644 index 000000000..047fc40f4 --- /dev/null +++ b/src/core/hle/service/am/library_applet_proxy.cpp @@ -0,0 +1,142 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applet_common_functions.h" +#include "core/hle/service/am/audio_controller.h" +#include "core/hle/service/am/common_state_getter.h" +#include "core/hle/service/am/debug_functions.h" +#include "core/hle/service/am/display_controller.h" +#include "core/hle/service/am/global_state_controller.h" +#include "core/hle/service/am/home_menu_functions.h" +#include "core/hle/service/am/library_applet_creator.h" +#include "core/hle/service/am/library_applet_proxy.h" +#include "core/hle/service/am/library_applet_self_accessor.h" +#include "core/hle/service/am/process_winding_controller.h" +#include "core/hle/service/am/self_controller.h" +#include "core/hle/service/am/window_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +ILibraryAppletProxy::ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, + std::shared_ptr<AppletMessageQueue> msg_queue_, + Core::System& system_) + : ServiceFramework{system_, "ILibraryAppletProxy"}, nvnflinger{nvnflinger_}, + msg_queue{std::move(msg_queue_)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, + {1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"}, + {2, &ILibraryAppletProxy::GetWindowController, "GetWindowController"}, + {3, &ILibraryAppletProxy::GetAudioController, "GetAudioController"}, + {4, &ILibraryAppletProxy::GetDisplayController, "GetDisplayController"}, + {10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"}, + {11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, + {20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"}, + {21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"}, + {22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"}, + {23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"}, + {1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +void ILibraryAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue); +} + +void ILibraryAppletProxy::GetSelfController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ISelfController>(system, nvnflinger); +} + +void ILibraryAppletProxy::GetWindowController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IWindowController>(system); +} + +void ILibraryAppletProxy::GetAudioController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IAudioController>(system); +} + +void ILibraryAppletProxy::GetDisplayController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IDisplayController>(system); +} + +void ILibraryAppletProxy::GetProcessWindingController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IProcessWindingController>(system); +} + +void ILibraryAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILibraryAppletCreator>(system); +} + +void ILibraryAppletProxy::OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILibraryAppletSelfAccessor>(system); +} + +void ILibraryAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IAppletCommonFunctions>(system); +} + +void ILibraryAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IHomeMenuFunctions>(system); +} + +void ILibraryAppletProxy::GetGlobalStateController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IGlobalStateController>(system); +} + +void ILibraryAppletProxy::GetDebugFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IDebugFunctions>(system); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_proxy.h b/src/core/hle/service/am/library_applet_proxy.h new file mode 100644 index 000000000..cd9e6d02b --- /dev/null +++ b/src/core/hle/service/am/library_applet_proxy.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/applet_message_queue.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { +public: + explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, + std::shared_ptr<AppletMessageQueue> msg_queue_, + Core::System& system_); + +private: + void GetCommonStateGetter(HLERequestContext& ctx); + void GetSelfController(HLERequestContext& ctx); + void GetWindowController(HLERequestContext& ctx); + void GetAudioController(HLERequestContext& ctx); + void GetDisplayController(HLERequestContext& ctx); + void GetProcessWindingController(HLERequestContext& ctx); + void GetLibraryAppletCreator(HLERequestContext& ctx); + void OpenLibraryAppletSelfAccessor(HLERequestContext& ctx); + void GetAppletCommonFunctions(HLERequestContext& ctx); + void GetHomeMenuFunctions(HLERequestContext& ctx); + void GetGlobalStateController(HLERequestContext& ctx); + void GetDebugFunctions(HLERequestContext& ctx); + + Nvnflinger::Nvnflinger& nvnflinger; + std::shared_ptr<AppletMessageQueue> msg_queue; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_self_accessor.cpp b/src/core/hle/service/am/library_applet_self_accessor.cpp new file mode 100644 index 000000000..0a12afbbd --- /dev/null +++ b/src/core/hle/service/am/library_applet_self_accessor.cpp @@ -0,0 +1,382 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core_timing.h" +#include "core/hle/service/acc/profile_manager.h" +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/applets/applet_cabinet.h" +#include "core/hle/service/am/applets/applet_controller.h" +#include "core/hle/service/am/applets/applet_mii_edit_types.h" +#include "core/hle/service/am/applets/applet_software_keyboard_types.h" +#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/library_applet_self_accessor.h" +#include "core/hle/service/am/storage.h" +#include "core/hle/service/ipc_helpers.h" +#include "hid_core/hid_types.h" + +namespace Service::AM { + +ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_) + : ServiceFramework{system_, "ILibraryAppletSelfAccessor"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ILibraryAppletSelfAccessor::PopInData, "PopInData"}, + {1, &ILibraryAppletSelfAccessor::PushOutData, "PushOutData"}, + {2, nullptr, "PopInteractiveInData"}, + {3, nullptr, "PushInteractiveOutData"}, + {5, nullptr, "GetPopInDataEvent"}, + {6, nullptr, "GetPopInteractiveInDataEvent"}, + {10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"}, + {11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"}, + {12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"}, + {13, nullptr, "CanUseApplicationCore"}, + {14, &ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo, "GetCallerAppletIdentityInfo"}, + {15, nullptr, "GetMainAppletApplicationControlProperty"}, + {16, nullptr, "GetMainAppletStorageId"}, + {17, nullptr, "GetCallerAppletIdentityInfoStack"}, + {18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"}, + {19, &ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout, "GetDesirableKeyboardLayout"}, + {20, nullptr, "PopExtraStorage"}, + {25, nullptr, "GetPopExtraStorageEvent"}, + {30, nullptr, "UnpopInData"}, + {31, nullptr, "UnpopExtraStorage"}, + {40, nullptr, "GetIndirectLayerProducerHandle"}, + {50, nullptr, "ReportVisibleError"}, + {51, nullptr, "ReportVisibleErrorWithErrorContext"}, + {60, nullptr, "GetMainAppletApplicationDesiredLanguage"}, + {70, nullptr, "GetCurrentApplicationId"}, + {80, nullptr, "RequestExitToSelf"}, + {90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"}, + {100, nullptr, "CreateGameMovieTrimmer"}, + {101, nullptr, "ReserveResourceForMovieOperation"}, + {102, nullptr, "UnreserveResourceForMovieOperation"}, + {110, &ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers, "GetMainAppletAvailableUsers"}, + {120, nullptr, "GetLaunchStorageInfoForDebug"}, + {130, nullptr, "GetGpuErrorDetectedSystemEvent"}, + {140, nullptr, "SetApplicationMemoryReservation"}, + {150, &ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually, "ShouldSetGpuTimeSliceManually"}, + }; + // clang-format on + RegisterHandlers(functions); + + switch (system.GetAppletManager().GetCurrentAppletId()) { + case Applets::AppletId::Cabinet: + PushInShowCabinetData(); + break; + case Applets::AppletId::MiiEdit: + PushInShowMiiEditData(); + break; + case Applets::AppletId::PhotoViewer: + PushInShowAlbum(); + break; + case Applets::AppletId::SoftwareKeyboard: + PushInShowSoftwareKeyboard(); + break; + case Applets::AppletId::Controller: + PushInShowController(); + break; + default: + break; + } +} + +ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default; + +void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + if (queue_data.empty()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultNoDataInChannel); + return; + } + + auto data = queue_data.front(); + queue_data.pop_front(); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IStorage>(system, std::move(data)); +} + +void ILibraryAppletSelfAccessor::PushOutData(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + system.Exit(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) { + struct LibraryAppletInfo { + Applets::AppletId applet_id; + Applets::LibraryAppletMode library_applet_mode; + }; + + LOG_WARNING(Service_AM, "(STUBBED) called"); + + const LibraryAppletInfo applet_info{ + .applet_id = system.GetAppletManager().GetCurrentAppletId(), + .library_applet_mode = Applets::LibraryAppletMode::AllForeground, + }; + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.PushRaw(applet_info); +} + +void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) { + struct AppletIdentityInfo { + Applets::AppletId applet_id; + INSERT_PADDING_BYTES(0x4); + u64 application_id; + }; + static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); + + LOG_WARNING(Service_AM, "(STUBBED) called"); + + const AppletIdentityInfo applet_info{ + .applet_id = Applets::AppletId::QLaunch, + .application_id = 0x0100000000001000ull, + }; + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.PushRaw(applet_info); +} + +void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) { + struct AppletIdentityInfo { + Applets::AppletId applet_id; + INSERT_PADDING_BYTES(0x4); + u64 application_id; + }; + static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); + LOG_WARNING(Service_AM, "(STUBBED) called"); + + const AppletIdentityInfo applet_info{ + .applet_id = Applets::AppletId::QLaunch, + .application_id = 0x0100000000001000ull, + }; + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.PushRaw(applet_info); +} + +void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u32>(0); +} + +void ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(HLERequestContext& ctx) { + const Service::Account::ProfileManager manager{}; + bool is_empty{true}; + s32 user_count{-1}; + + LOG_INFO(Service_AM, "called"); + + if (manager.GetUserCount() > 0) { + is_empty = false; + user_count = static_cast<s32>(manager.GetUserCount()); + ctx.WriteBuffer(manager.GetAllUsers()); + } + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u8>(is_empty); + rb.Push(user_count); +} + +void ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u8>(0); +} + +void ILibraryAppletSelfAccessor::PushInShowAlbum() { + const Applets::CommonArguments arguments{ + .arguments_version = Applets::CommonArgumentVersion::Version3, + .size = Applets::CommonArgumentSize::Version3, + .library_version = 1, + .theme_color = Applets::ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + + std::vector<u8> argument_data(sizeof(arguments)); + std::vector<u8> settings_data{2}; + std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); + queue_data.emplace_back(std::move(argument_data)); + queue_data.emplace_back(std::move(settings_data)); +} + +void ILibraryAppletSelfAccessor::PushInShowController() { + const Applets::CommonArguments common_args = { + .arguments_version = Applets::CommonArgumentVersion::Version3, + .size = Applets::CommonArgumentSize::Version3, + .library_version = static_cast<u32>(Applets::ControllerAppletVersion::Version8), + .theme_color = Applets::ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + + Applets::ControllerSupportArgNew user_args = { + .header = {.player_count_min = 1, + .player_count_max = 4, + .enable_take_over_connection = true, + .enable_left_justify = false, + .enable_permit_joy_dual = true, + .enable_single_mode = false, + .enable_identification_color = false}, + .identification_colors = {}, + .enable_explain_text = false, + .explain_text = {}, + }; + + Applets::ControllerSupportArgPrivate private_args = { + .arg_private_size = sizeof(Applets::ControllerSupportArgPrivate), + .arg_size = sizeof(Applets::ControllerSupportArgNew), + .is_home_menu = true, + .flag_1 = true, + .mode = Applets::ControllerSupportMode::ShowControllerSupport, + .caller = Applets::ControllerSupportCaller:: + Application, // switchbrew: Always zero except with + // ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem, + // which sets this to the input param + .style_set = Core::HID::NpadStyleSet::None, + .joy_hold_type = 0, + }; + std::vector<u8> common_args_data(sizeof(common_args)); + std::vector<u8> private_args_data(sizeof(private_args)); + std::vector<u8> user_args_data(sizeof(user_args)); + + std::memcpy(common_args_data.data(), &common_args, sizeof(common_args)); + std::memcpy(private_args_data.data(), &private_args, sizeof(private_args)); + std::memcpy(user_args_data.data(), &user_args, sizeof(user_args)); + + queue_data.emplace_back(std::move(common_args_data)); + queue_data.emplace_back(std::move(private_args_data)); + queue_data.emplace_back(std::move(user_args_data)); +} + +void ILibraryAppletSelfAccessor::PushInShowCabinetData() { + const Applets::CommonArguments arguments{ + .arguments_version = Applets::CommonArgumentVersion::Version3, + .size = Applets::CommonArgumentSize::Version3, + .library_version = static_cast<u32>(Applets::CabinetAppletVersion::Version1), + .theme_color = Applets::ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + + const Applets::StartParamForAmiiboSettings amiibo_settings{ + .param_1 = 0, + .applet_mode = system.GetAppletManager().GetCabinetMode(), + .flags = Applets::CabinetFlags::None, + .amiibo_settings_1 = 0, + .device_handle = 0, + .tag_info{}, + .register_info{}, + .amiibo_settings_3{}, + }; + + std::vector<u8> argument_data(sizeof(arguments)); + std::vector<u8> settings_data(sizeof(amiibo_settings)); + std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); + std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings)); + queue_data.emplace_back(std::move(argument_data)); + queue_data.emplace_back(std::move(settings_data)); +} + +void ILibraryAppletSelfAccessor::PushInShowMiiEditData() { + struct MiiEditV3 { + Applets::MiiEditAppletInputCommon common; + Applets::MiiEditAppletInputV3 input; + }; + static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size."); + + MiiEditV3 mii_arguments{ + .common = + { + .version = Applets::MiiEditAppletVersion::Version3, + .applet_mode = Applets::MiiEditAppletMode::ShowMiiEdit, + }, + .input{}, + }; + + std::vector<u8> argument_data(sizeof(mii_arguments)); + std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments)); + + queue_data.emplace_back(std::move(argument_data)); +} + +void ILibraryAppletSelfAccessor::PushInShowSoftwareKeyboard() { + const Applets::CommonArguments arguments{ + .arguments_version = Applets::CommonArgumentVersion::Version3, + .size = Applets::CommonArgumentSize::Version3, + .library_version = static_cast<u32>(Applets::SwkbdAppletVersion::Version524301), + .theme_color = Applets::ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + + std::vector<char16_t> initial_string(0); + + const Applets::SwkbdConfigCommon swkbd_config{ + .type = Applets::SwkbdType::Qwerty, + .ok_text{}, + .left_optional_symbol_key{}, + .right_optional_symbol_key{}, + .use_prediction = false, + .key_disable_flags{}, + .initial_cursor_position = Applets::SwkbdInitialCursorPosition::Start, + .header_text{}, + .sub_text{}, + .guide_text{}, + .max_text_length = 500, + .min_text_length = 0, + .password_mode = Applets::SwkbdPasswordMode::Disabled, + .text_draw_type = Applets::SwkbdTextDrawType::Box, + .enable_return_button = true, + .use_utf8 = false, + .use_blur_background = true, + .initial_string_offset{}, + .initial_string_length = static_cast<u32>(initial_string.size()), + .user_dictionary_offset{}, + .user_dictionary_entries{}, + .use_text_check = false, + }; + + Applets::SwkbdConfigNew swkbd_config_new{}; + + std::vector<u8> argument_data(sizeof(arguments)); + std::vector<u8> swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new)); + std::vector<u8> work_buffer(swkbd_config.initial_string_length * sizeof(char16_t)); + + std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); + std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config)); + std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new, + sizeof(Applets::SwkbdConfigNew)); + std::memcpy(work_buffer.data(), initial_string.data(), + swkbd_config.initial_string_length * sizeof(char16_t)); + + queue_data.emplace_back(std::move(argument_data)); + queue_data.emplace_back(std::move(swkbd_data)); + queue_data.emplace_back(std::move(work_buffer)); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/library_applet_self_accessor.h b/src/core/hle/service/am/library_applet_self_accessor.h new file mode 100644 index 000000000..45b325b77 --- /dev/null +++ b/src/core/hle/service/am/library_applet_self_accessor.h @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <deque> +#include <vector> + +#include "core/hle/service/service.h" + +namespace Service::AM { + +class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> { +public: + explicit ILibraryAppletSelfAccessor(Core::System& system_); + ~ILibraryAppletSelfAccessor() override; + +private: + void PopInData(HLERequestContext& ctx); + void PushOutData(HLERequestContext& ctx); + void GetLibraryAppletInfo(HLERequestContext& ctx); + void GetMainAppletIdentityInfo(HLERequestContext& ctx); + void ExitProcessAndReturn(HLERequestContext& ctx); + void GetCallerAppletIdentityInfo(HLERequestContext& ctx); + void GetDesirableKeyboardLayout(HLERequestContext& ctx); + void GetMainAppletAvailableUsers(HLERequestContext& ctx); + void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx); + + void PushInShowAlbum(); + void PushInShowCabinetData(); + void PushInShowMiiEditData(); + void PushInShowSoftwareKeyboard(); + void PushInShowController(); + + std::deque<std::vector<u8>> queue_data; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/lock_accessor.cpp b/src/core/hle/service/am/lock_accessor.cpp new file mode 100644 index 000000000..d0bd8d95e --- /dev/null +++ b/src/core/hle/service/am/lock_accessor.cpp @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/lock_accessor.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +ILockAccessor::ILockAccessor(Core::System& system_) + : ServiceFramework{system_, "ILockAccessor"}, service_context{system_, "ILockAccessor"} { + // clang-format off + static const FunctionInfo functions[] = { + {1, &ILockAccessor::TryLock, "TryLock"}, + {2, &ILockAccessor::Unlock, "Unlock"}, + {3, &ILockAccessor::GetEvent, "GetEvent"}, + {4,&ILockAccessor::IsLocked, "IsLocked"}, + }; + // clang-format on + + RegisterHandlers(functions); + + lock_event = service_context.CreateEvent("ILockAccessor::LockEvent"); +} + +ILockAccessor::~ILockAccessor() { + service_context.CloseEvent(lock_event); +}; + +void ILockAccessor::TryLock(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto return_handle = rp.Pop<bool>(); + + LOG_WARNING(Service_AM, "(STUBBED) called, return_handle={}", return_handle); + + // TODO: When return_handle is true this function should return the lock handle + + is_locked = true; + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u8>(is_locked); +} + +void ILockAccessor::Unlock(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + is_locked = false; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILockAccessor::GetEvent(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + lock_event->Signal(); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(lock_event->GetReadableEvent()); +} + +void ILockAccessor::IsLocked(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + rb.Push<u8>(is_locked); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/lock_accessor.h b/src/core/hle/service/am/lock_accessor.h new file mode 100644 index 000000000..626f60e07 --- /dev/null +++ b/src/core/hle/service/am/lock_accessor.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/kernel_helpers.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: + void TryLock(HLERequestContext& ctx); + void Unlock(HLERequestContext& ctx); + void GetEvent(HLERequestContext& ctx); + void IsLocked(HLERequestContext& ctx); + + bool is_locked{}; + + Kernel::KEvent* lock_event; + KernelHelpers::ServiceContext service_context; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/process_winding_controller.cpp b/src/core/hle/service/am/process_winding_controller.cpp new file mode 100644 index 000000000..7b3ab157f --- /dev/null +++ b/src/core/hle/service/am/process_winding_controller.cpp @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/library_applet_accessor.h" +#include "core/hle/service/am/process_winding_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IProcessWindingController::IProcessWindingController(Core::System& system_) + : ServiceFramework{system_, "IProcessWindingController"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IProcessWindingController::GetLaunchReason, "GetLaunchReason"}, + {11, &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; + +void IProcessWindingController::GetLaunchReason(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + struct AppletProcessLaunchReason { + u8 flag; + INSERT_PADDING_BYTES(3); + }; + static_assert(sizeof(AppletProcessLaunchReason) == 0x4, + "AppletProcessLaunchReason is an invalid size"); + + AppletProcessLaunchReason reason{ + .flag = 0, + }; + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushRaw(reason); +} + +void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) { + const auto applet_id = system.GetAppletManager().GetCurrentAppletId(); + const auto applet_mode = Applets::LibraryAppletMode::AllForeground; + + LOG_WARNING(Service_AM, "(STUBBED) called with applet_id={:08X}, applet_mode={:08X}", applet_id, + applet_mode); + + const auto& applet_manager{system.GetAppletManager()}; + const auto applet = applet_manager.GetApplet(applet_id, applet_mode); + + if (applet == nullptr) { + LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/process_winding_controller.h b/src/core/hle/service/am/process_winding_controller.h new file mode 100644 index 000000000..9b9704201 --- /dev/null +++ b/src/core/hle/service/am/process_winding_controller.h @@ -0,0 +1,20 @@ +// 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 IProcessWindingController final : public ServiceFramework<IProcessWindingController> { +public: + explicit IProcessWindingController(Core::System& system_); + ~IProcessWindingController() override; + +private: + void GetLaunchReason(HLERequestContext& ctx); + void OpenCallingLibraryApplet(HLERequestContext& ctx); +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/self_controller.cpp b/src/core/hle/service/am/self_controller.cpp new file mode 100644 index 000000000..0f495c871 --- /dev/null +++ b/src/core/hle/service/am/self_controller.cpp @@ -0,0 +1,438 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/self_controller.h" +#include "core/hle/service/caps/caps_su.h" +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/nvnflinger/fb_share_buffer_manager.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_, Nvnflinger::Nvnflinger& nvnflinger_) + : ServiceFramework{system_, "ISelfController"}, nvnflinger{nvnflinger_}, + service_context{system, "ISelfController"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ISelfController::Exit, "Exit"}, + {1, &ISelfController::LockExit, "LockExit"}, + {2, &ISelfController::UnlockExit, "UnlockExit"}, + {3, &ISelfController::EnterFatalSection, "EnterFatalSection"}, + {4, &ISelfController::LeaveFatalSection, "LeaveFatalSection"}, + {9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"}, + {10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"}, + {11, &ISelfController::SetOperationModeChangedNotification, "SetOperationModeChangedNotification"}, + {12, &ISelfController::SetPerformanceModeChangedNotification, "SetPerformanceModeChangedNotification"}, + {13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"}, + {14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"}, + {15, nullptr, "SetScreenShotAppletIdentityInfo"}, + {16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"}, + {17, nullptr, "SetControllerFirmwareUpdateSection"}, + {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"}, + {19, &ISelfController::SetAlbumImageOrientation, "SetAlbumImageOrientation"}, + {20, nullptr, "SetDesirableKeyboardLayout"}, + {21, nullptr, "GetScreenShotProgramId"}, + {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"}, + {41, &ISelfController::IsSystemBufferSharingEnabled, "IsSystemBufferSharingEnabled"}, + {42, &ISelfController::GetSystemSharedLayerHandle, "GetSystemSharedLayerHandle"}, + {43, &ISelfController::GetSystemSharedBufferHandle, "GetSystemSharedBufferHandle"}, + {44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"}, + {45, nullptr, "SetManagedDisplayLayerSeparationMode"}, + {46, nullptr, "SetRecordingLayerCompositionEnabled"}, + {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"}, + {51, &ISelfController::ApproveToDisplay, "ApproveToDisplay"}, + {60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"}, + {61, nullptr, "SetMediaPlaybackState"}, + {62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"}, + {63, &ISelfController::GetIdleTimeDetectionExtension, "GetIdleTimeDetectionExtension"}, + {64, nullptr, "SetInputDetectionSourceSet"}, + {65, &ISelfController::ReportUserIsActive, "ReportUserIsActive"}, + {66, nullptr, "GetCurrentIlluminance"}, + {67, nullptr, "IsIlluminanceAvailable"}, + {68, &ISelfController::SetAutoSleepDisabled, "SetAutoSleepDisabled"}, + {69, &ISelfController::IsAutoSleepDisabled, "IsAutoSleepDisabled"}, + {70, nullptr, "ReportMultimediaError"}, + {71, nullptr, "GetCurrentIlluminanceEx"}, + {72, nullptr, "SetInputDetectionPolicy"}, + {80, nullptr, "SetWirelessPriorityMode"}, + {90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"}, + {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"}, + {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"}, + {110, nullptr, "SetApplicationAlbumUserData"}, + {120, &ISelfController::SaveCurrentScreenshot, "SaveCurrentScreenshot"}, + {130, &ISelfController::SetRecordVolumeMuted, "SetRecordVolumeMuted"}, + {1000, nullptr, "GetDebugStorageChannel"}, + }; + // clang-format on + + RegisterHandlers(functions); + + launchable_event = service_context.CreateEvent("ISelfController:LaunchableEvent"); + + // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is + // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple + // ISelfControllers. The event is signaled on creation, and on transition from suspended -> not + // suspended if the event has previously been created by a call to + // GetAccumulatedSuspendedTickChangedEvent. + + accumulated_suspended_tick_changed_event = + service_context.CreateEvent("ISelfController:AccumulatedSuspendedTickChangedEvent"); + accumulated_suspended_tick_changed_event->Signal(); +} + +ISelfController::~ISelfController() { + service_context.CloseEvent(launchable_event); + service_context.CloseEvent(accumulated_suspended_tick_changed_event); +} + +void ISelfController::Exit(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + + system.Exit(); +} + +void ISelfController::LockExit(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + system.SetExitLocked(true); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::UnlockExit(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + system.SetExitLocked(false); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + + if (system.GetExitRequested()) { + system.Exit(); + } +} + +void ISelfController::EnterFatalSection(HLERequestContext& ctx) { + ++num_fatal_sections_entered; + LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", num_fatal_sections_entered); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::LeaveFatalSection(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called."); + + // Entry and exit of fatal sections must be balanced. + if (num_fatal_sections_entered == 0) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(Result{ErrorModule::AM, 512}); + return; + } + + --num_fatal_sections_entered; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::GetLibraryAppletLaunchableEvent(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + launchable_event->Signal(); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(launchable_event->GetReadableEvent()); +} + +void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto permission = rp.PopEnum<ScreenshotPermission>(); + LOG_DEBUG(Service_AM, "called, permission={}", permission); + + screenshot_permission = permission; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + bool flag = rp.Pop<bool>(); + LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetPerformanceModeChangedNotification(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + bool flag = rp.Pop<bool>(); + LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetFocusHandlingMode(HLERequestContext& ctx) { + // Takes 3 input u8s with each field located immediately after the previous + // u8, these are bool flags. No output. + IPC::RequestParser rp{ctx}; + + struct FocusHandlingModeParams { + u8 unknown0; + u8 unknown1; + u8 unknown2; + }; + const auto flags = rp.PopRaw<FocusHandlingModeParams>(); + + LOG_WARNING(Service_AM, "(STUBBED) called. unknown0={}, unknown1={}, unknown2={}", + flags.unknown0, flags.unknown1, flags.unknown2); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetRestartMessageEnabled(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx) { + // Takes 3 input u8s with each field located immediately after the previous + // u8, these are bool flags. No output. + IPC::RequestParser rp{ctx}; + + bool enabled = rp.Pop<bool>(); + LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetAlbumImageOrientation(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + // TODO(Subv): Find out how AM determines the display to use, for now just + // create the layer in the Default display. + const auto display_id = nvnflinger.OpenDisplay("Default"); + const auto layer_id = nvnflinger.CreateLayer(*display_id); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(*layer_id); +} + +void ISelfController::IsSystemBufferSharingEnabled(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess())); +} + +void ISelfController::GetSystemSharedLayerHandle(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess())); + rb.Push<s64>(system_shared_buffer_id); + rb.Push<s64>(system_shared_layer_id); +} + +void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess())); + rb.Push<s64>(system_shared_buffer_id); +} + +Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) { + if (buffer_sharing_enabled) { + return ResultSuccess; + } + + if (system.GetAppletManager().GetCurrentAppletId() <= Applets::AppletId::Application) { + return VI::ResultOperationFailed; + } + + const auto display_id = nvnflinger.OpenDisplay("Default"); + const auto result = nvnflinger.GetSystemBufferManager().Initialize( + &system_shared_buffer_id, &system_shared_layer_id, *display_id); + + if (result.IsSuccess()) { + buffer_sharing_enabled = true; + } + + return result; +} + +void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + // TODO(Subv): Find out how AM determines the display to use, for now just + // create the layer in the Default display. + // This calls nn::vi::CreateRecordingLayer() which creates another layer. + // Currently we do not support more than 1 layer per display, output 1 layer id for now. + // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse + // side effects. + // TODO: Support multiple layers + const auto display_id = nvnflinger.OpenDisplay("Default"); + const auto layer_id = nvnflinger.CreateLayer(*display_id); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(*layer_id); +} + +void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::ApproveToDisplay(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + idle_time_detection_extension = rp.Pop<u32>(); + LOG_DEBUG(Service_AM, "(STUBBED) called idle_time_detection_extension={}", + idle_time_detection_extension); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::GetIdleTimeDetectionExtension(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u32>(idle_time_detection_extension); +} + +void ISelfController::ReportUserIsActive(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + is_auto_sleep_disabled = rp.Pop<bool>(); + + // 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(). + + LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", is_auto_sleep_disabled); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::IsAutoSleepDisabled(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called."); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(is_auto_sleep_disabled); +} + +void ISelfController::GetAccumulatedSuspendedTickValue(HLERequestContext& ctx) { + 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. + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(0); +} + +void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called."); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent()); +} + +void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + // 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. + const bool album_image_taken_notification_enabled = rp.Pop<bool>(); + + LOG_WARNING(Service_AM, "(STUBBED) called. album_image_taken_notification_enabled={}", + album_image_taken_notification_enabled); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto report_option = rp.PopEnum<Capture::AlbumReportOption>(); + + LOG_INFO(Service_AM, "called, report_option={}", report_option); + + const auto screenshot_service = + system.ServiceManager().GetService<Service::Capture::IScreenShotApplicationService>( + "caps:su"); + + if (screenshot_service) { + screenshot_service->CaptureAndSaveScreenshot(report_option); + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetRecordVolumeMuted(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto is_record_volume_muted = rp.Pop<bool>(); + + LOG_WARNING(Service_AM, "(STUBBED) called. is_record_volume_muted={}", is_record_volume_muted); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/self_controller.h b/src/core/hle/service/am/self_controller.h new file mode 100644 index 000000000..f157bb826 --- /dev/null +++ b/src/core/hle/service/am/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/kernel_helpers.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class ISelfController final : public ServiceFramework<ISelfController> { +public: + explicit ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_); + ~ISelfController() override; + +private: + void Exit(HLERequestContext& ctx); + void LockExit(HLERequestContext& ctx); + void UnlockExit(HLERequestContext& ctx); + void EnterFatalSection(HLERequestContext& ctx); + void LeaveFatalSection(HLERequestContext& ctx); + void GetLibraryAppletLaunchableEvent(HLERequestContext& ctx); + void SetScreenShotPermission(HLERequestContext& ctx); + void SetOperationModeChangedNotification(HLERequestContext& ctx); + void SetPerformanceModeChangedNotification(HLERequestContext& ctx); + void SetFocusHandlingMode(HLERequestContext& ctx); + void SetRestartMessageEnabled(HLERequestContext& ctx); + void SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx); + void SetAlbumImageOrientation(HLERequestContext& ctx); + void IsSystemBufferSharingEnabled(HLERequestContext& ctx); + void GetSystemSharedBufferHandle(HLERequestContext& ctx); + void GetSystemSharedLayerHandle(HLERequestContext& ctx); + void CreateManagedDisplayLayer(HLERequestContext& ctx); + void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx); + void SetHandlesRequestToDisplay(HLERequestContext& ctx); + void ApproveToDisplay(HLERequestContext& ctx); + void SetIdleTimeDetectionExtension(HLERequestContext& ctx); + void GetIdleTimeDetectionExtension(HLERequestContext& ctx); + void ReportUserIsActive(HLERequestContext& ctx); + void SetAutoSleepDisabled(HLERequestContext& ctx); + void IsAutoSleepDisabled(HLERequestContext& ctx); + void GetAccumulatedSuspendedTickValue(HLERequestContext& ctx); + void GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx); + void SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx); + void SaveCurrentScreenshot(HLERequestContext& ctx); + void SetRecordVolumeMuted(HLERequestContext& ctx); + + Result EnsureBufferSharingEnabled(Kernel::KProcess* process); + + enum class ScreenshotPermission : u32 { + Inherit = 0, + Enable = 1, + Disable = 2, + }; + + Nvnflinger::Nvnflinger& nvnflinger; + + KernelHelpers::ServiceContext service_context; + + Kernel::KEvent* launchable_event; + Kernel::KEvent* accumulated_suspended_tick_changed_event; + + u32 idle_time_detection_extension = 0; + u64 num_fatal_sections_entered = 0; + u64 system_shared_buffer_id = 0; + u64 system_shared_layer_id = 0; + bool is_auto_sleep_disabled = false; + bool buffer_sharing_enabled = false; + ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/storage.cpp b/src/core/hle/service/am/storage.cpp new file mode 100644 index 000000000..9a86c867a --- /dev/null +++ b/src/core/hle/service/am/storage.cpp @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/storage.h" +#include "core/hle/service/am/storage_accessor.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IStorageImpl::~IStorageImpl() = default; + +class StorageDataImpl final : public IStorageImpl { +public: + explicit StorageDataImpl(std::vector<u8>&& buffer_) : buffer{std::move(buffer_)} {} + + std::vector<u8>& GetData() override { + return buffer; + } + + const std::vector<u8>& GetData() const override { + return buffer; + } + + std::size_t GetSize() const override { + return buffer.size(); + } + +private: + std::vector<u8> buffer; +}; + +IStorage::IStorage(Core::System& system_, std::vector<u8>&& buffer) + : ServiceFramework{system_, "IStorage"}, + impl{std::make_shared<StorageDataImpl>(std::move(buffer))} { + Register(); +} + +void IStorage::Register() { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IStorage::Open, "Open"}, + {1, nullptr, "OpenTransferStorage"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IStorage::~IStorage() = default; + +void IStorage::Open(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + + rb.Push(ResultSuccess); + rb.PushIpcInterface<IStorageAccessor>(system, *this); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/storage.h b/src/core/hle/service/am/storage.h new file mode 100644 index 000000000..d47a8d89f --- /dev/null +++ b/src/core/hle/service/am/storage.h @@ -0,0 +1,42 @@ +// 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 IStorageImpl { +public: + virtual ~IStorageImpl(); + virtual std::vector<u8>& GetData() = 0; + virtual const std::vector<u8>& GetData() const = 0; + virtual std::size_t GetSize() const = 0; +}; + +class IStorage final : public ServiceFramework<IStorage> { +public: + explicit IStorage(Core::System& system_, std::vector<u8>&& buffer); + ~IStorage() override; + + std::vector<u8>& GetData() { + return impl->GetData(); + } + + const std::vector<u8>& GetData() const { + return impl->GetData(); + } + + std::size_t GetSize() const { + return impl->GetSize(); + } + +private: + void Register(); + void Open(HLERequestContext& ctx); + + std::shared_ptr<IStorageImpl> impl; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/storage_accessor.cpp b/src/core/hle/service/am/storage_accessor.cpp new file mode 100644 index 000000000..7d8c82de3 --- /dev/null +++ b/src/core/hle/service/am/storage_accessor.cpp @@ -0,0 +1,82 @@ +// 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/storage_accessor.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IStorageAccessor::IStorageAccessor(Core::System& system_, IStorage& backing_) + : ServiceFramework{system_, "IStorageAccessor"}, backing{backing_} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IStorageAccessor::GetSize, "GetSize"}, + {10, &IStorageAccessor::Write, "Write"}, + {11, &IStorageAccessor::Read, "Read"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IStorageAccessor::~IStorageAccessor() = default; + +void IStorageAccessor::GetSize(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 4}; + + rb.Push(ResultSuccess); + rb.Push(static_cast<u64>(backing.GetSize())); +} + +void IStorageAccessor::Write(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const u64 offset{rp.Pop<u64>()}; + const auto data{ctx.ReadBuffer()}; + const std::size_t size{std::min<u64>(data.size(), backing.GetSize() - offset)}; + + LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); + + if (offset > backing.GetSize()) { + LOG_ERROR(Service_AM, + "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", + backing.GetSize(), size, offset); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultInvalidOffset); + return; + } + + std::memcpy(backing.GetData().data() + offset, data.data(), size); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IStorageAccessor::Read(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const u64 offset{rp.Pop<u64>()}; + const std::size_t size{std::min<u64>(ctx.GetWriteBufferSize(), backing.GetSize() - offset)}; + + LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); + + if (offset > backing.GetSize()) { + LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", + backing.GetSize(), size, offset); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultInvalidOffset); + return; + } + + ctx.WriteBuffer(backing.GetData().data() + offset, size); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/storage_accessor.h b/src/core/hle/service/am/storage_accessor.h new file mode 100644 index 000000000..8648bfc13 --- /dev/null +++ b/src/core/hle/service/am/storage_accessor.h @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/am/storage.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { +public: + explicit IStorageAccessor(Core::System& system_, IStorage& backing_); + ~IStorageAccessor() override; + +private: + void GetSize(HLERequestContext& ctx); + void Write(HLERequestContext& ctx); + void Read(HLERequestContext& ctx); + + IStorage& backing; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/system_applet_proxy.cpp b/src/core/hle/service/am/system_applet_proxy.cpp new file mode 100644 index 000000000..d51a2c8db --- /dev/null +++ b/src/core/hle/service/am/system_applet_proxy.cpp @@ -0,0 +1,135 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applet_common_functions.h" +#include "core/hle/service/am/application_creator.h" +#include "core/hle/service/am/audio_controller.h" +#include "core/hle/service/am/common_state_getter.h" +#include "core/hle/service/am/debug_functions.h" +#include "core/hle/service/am/display_controller.h" +#include "core/hle/service/am/global_state_controller.h" +#include "core/hle/service/am/home_menu_functions.h" +#include "core/hle/service/am/library_applet_creator.h" +#include "core/hle/service/am/library_applet_self_accessor.h" +#include "core/hle/service/am/process_winding_controller.h" +#include "core/hle/service/am/self_controller.h" +#include "core/hle/service/am/system_applet_proxy.h" +#include "core/hle/service/am/window_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +ISystemAppletProxy::ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, + std::shared_ptr<AppletMessageQueue> msg_queue_, + Core::System& system_) + : ServiceFramework{system_, "ISystemAppletProxy"}, nvnflinger{nvnflinger_}, + msg_queue{std::move(msg_queue_)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, + {1, &ISystemAppletProxy::GetSelfController, "GetSelfController"}, + {2, &ISystemAppletProxy::GetWindowController, "GetWindowController"}, + {3, &ISystemAppletProxy::GetAudioController, "GetAudioController"}, + {4, &ISystemAppletProxy::GetDisplayController, "GetDisplayController"}, + {10, nullptr, "GetProcessWindingController"}, + {11, &ISystemAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, + {20, &ISystemAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"}, + {21, &ISystemAppletProxy::GetGlobalStateController, "GetGlobalStateController"}, + {22, &ISystemAppletProxy::GetApplicationCreator, "GetApplicationCreator"}, + {23, &ISystemAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"}, + {1000, &ISystemAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +void ISystemAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue); +} + +void ISystemAppletProxy::GetSelfController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ISelfController>(system, nvnflinger); +} + +void ISystemAppletProxy::GetWindowController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IWindowController>(system); +} + +void ISystemAppletProxy::GetAudioController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IAudioController>(system); +} + +void ISystemAppletProxy::GetDisplayController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IDisplayController>(system); +} + +void ISystemAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILibraryAppletCreator>(system); +} + +void ISystemAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IHomeMenuFunctions>(system); +} + +void ISystemAppletProxy::GetGlobalStateController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IGlobalStateController>(system); +} + +void ISystemAppletProxy::GetApplicationCreator(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IApplicationCreator>(system); +} + +void ISystemAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IAppletCommonFunctions>(system); +} + +void ISystemAppletProxy::GetDebugFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IDebugFunctions>(system); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/system_applet_proxy.h b/src/core/hle/service/am/system_applet_proxy.h new file mode 100644 index 000000000..b8855b1d6 --- /dev/null +++ b/src/core/hle/service/am/system_applet_proxy.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/am/applet_message_queue.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { +public: + explicit ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, + std::shared_ptr<AppletMessageQueue> msg_queue_, + Core::System& system_); + +private: + void GetCommonStateGetter(HLERequestContext& ctx); + void GetSelfController(HLERequestContext& ctx); + void GetWindowController(HLERequestContext& ctx); + void GetAudioController(HLERequestContext& ctx); + void GetDisplayController(HLERequestContext& ctx); + void GetLibraryAppletCreator(HLERequestContext& ctx); + void GetHomeMenuFunctions(HLERequestContext& ctx); + void GetGlobalStateController(HLERequestContext& ctx); + void GetApplicationCreator(HLERequestContext& ctx); + void GetAppletCommonFunctions(HLERequestContext& ctx); + void GetDebugFunctions(HLERequestContext& ctx); + + Nvnflinger::Nvnflinger& nvnflinger; + std::shared_ptr<AppletMessageQueue> msg_queue; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/window_controller.cpp b/src/core/hle/service/am/window_controller.cpp new file mode 100644 index 000000000..f2ba3c134 --- /dev/null +++ b/src/core/hle/service/am/window_controller.cpp @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/window_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IWindowController::IWindowController(Core::System& system_) + : ServiceFramework{system_, "IWindowController"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "CreateWindow"}, + {1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"}, + {2, &IWindowController::GetAppletResourceUserIdOfCallerApplet, "GetAppletResourceUserIdOfCallerApplet"}, + {10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"}, + {11, nullptr, "ReleaseForegroundRights"}, + {12, nullptr, "RejectToChangeIntoBackground"}, + {20, nullptr, "SetAppletWindowVisibility"}, + {21, nullptr, "SetAppletGpuTimeSlice"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IWindowController::~IWindowController() = default; + +void IWindowController::GetAppletResourceUserId(HLERequestContext& ctx) { + const u64 process_id = system.ApplicationProcess()->GetProcessId(); + + LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(process_id); +} + +void IWindowController::GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx) { + const u64 process_id = 0; + + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(process_id); +} + +void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/window_controller.h b/src/core/hle/service/am/window_controller.h new file mode 100644 index 000000000..07b0e0e17 --- /dev/null +++ b/src/core/hle/service/am/window_controller.h @@ -0,0 +1,21 @@ +// 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 IWindowController final : public ServiceFramework<IWindowController> { +public: + explicit IWindowController(Core::System& system_); + ~IWindowController() override; + +private: + void GetAppletResourceUserId(HLERequestContext& ctx); + void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx); + void AcquireForegroundRights(HLERequestContext& ctx); +}; + +} // namespace Service::AM diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 49ec52546..718534ba1 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -9,6 +9,7 @@ #include "core/core.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" +#include "core/hle/service/am/applet_message_queue.h" #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/sm/sm.h" #include "hid_core/frontend/emulated_controller.h" diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 782bcbb61..f51fd3fa3 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -44,6 +44,7 @@ #include "core/frontend/applets/software_keyboard.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/applet_ae.h" +#include "core/hle/service/am/applet_message_queue.h" #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/am/applets/applets.h" #include "core/hle/service/set/system_settings_server.h" |