diff options
19 files changed, 1496 insertions, 1 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 3a2ba9ed4..049946426 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -393,8 +393,13 @@ add_library(core STATIC | |||
| 393 | hle/service/am/am.cpp | 393 | hle/service/am/am.cpp |
| 394 | hle/service/am/am.h | 394 | hle/service/am/am.h |
| 395 | hle/service/am/am_results.h | 395 | hle/service/am/am_results.h |
| 396 | hle/service/am/am_types.h | ||
| 397 | hle/service/am/applet.cpp | ||
| 398 | hle/service/am/applet.h | ||
| 396 | hle/service/am/applet_ae.cpp | 399 | hle/service/am/applet_ae.cpp |
| 397 | hle/service/am/applet_ae.h | 400 | hle/service/am/applet_ae.h |
| 401 | hle/service/am/applet_manager.cpp | ||
| 402 | hle/service/am/applet_manager.h | ||
| 398 | hle/service/am/applet_oe.cpp | 403 | hle/service/am/applet_oe.cpp |
| 399 | hle/service/am/applet_oe.h | 404 | hle/service/am/applet_oe.h |
| 400 | hle/service/am/applets/applet_cabinet.cpp | 405 | hle/service/am/applets/applet_cabinet.cpp |
| @@ -438,6 +443,8 @@ add_library(core STATIC | |||
| 438 | hle/service/am/display_controller.h | 443 | hle/service/am/display_controller.h |
| 439 | hle/service/am/global_state_controller.cpp | 444 | hle/service/am/global_state_controller.cpp |
| 440 | hle/service/am/global_state_controller.h | 445 | hle/service/am/global_state_controller.h |
| 446 | hle/service/am/hid_registration.cpp | ||
| 447 | hle/service/am/hid_registration.h | ||
| 441 | hle/service/am/home_menu_functions.cpp | 448 | hle/service/am/home_menu_functions.cpp |
| 442 | hle/service/am/home_menu_functions.h | 449 | hle/service/am/home_menu_functions.h |
| 443 | hle/service/am/idle.cpp | 450 | hle/service/am/idle.cpp |
| @@ -450,16 +457,24 @@ add_library(core STATIC | |||
| 450 | hle/service/am/library_applet_proxy.h | 457 | hle/service/am/library_applet_proxy.h |
| 451 | hle/service/am/library_applet_self_accessor.cpp | 458 | hle/service/am/library_applet_self_accessor.cpp |
| 452 | hle/service/am/library_applet_self_accessor.h | 459 | hle/service/am/library_applet_self_accessor.h |
| 460 | hle/service/am/library_applet_storage.cpp | ||
| 461 | hle/service/am/library_applet_storage.h | ||
| 453 | hle/service/am/lock_accessor.cpp | 462 | hle/service/am/lock_accessor.cpp |
| 454 | hle/service/am/lock_accessor.h | 463 | hle/service/am/lock_accessor.h |
| 464 | hle/service/am/managed_layer_holder.cpp | ||
| 465 | hle/service/am/managed_layer_holder.h | ||
| 455 | hle/service/am/omm.cpp | 466 | hle/service/am/omm.cpp |
| 456 | hle/service/am/omm.h | 467 | hle/service/am/omm.h |
| 457 | hle/service/am/process_winding_controller.cpp | 468 | hle/service/am/process_winding_controller.cpp |
| 458 | hle/service/am/process_winding_controller.h | 469 | hle/service/am/process_winding_controller.h |
| 470 | hle/service/am/process.cpp | ||
| 471 | hle/service/am/process.h | ||
| 459 | hle/service/am/self_controller.cpp | 472 | hle/service/am/self_controller.cpp |
| 460 | hle/service/am/self_controller.h | 473 | hle/service/am/self_controller.h |
| 461 | hle/service/am/system_applet_proxy.cpp | 474 | hle/service/am/system_applet_proxy.cpp |
| 462 | hle/service/am/system_applet_proxy.h | 475 | hle/service/am/system_applet_proxy.h |
| 476 | hle/service/am/system_buffer_manager.cpp | ||
| 477 | hle/service/am/system_buffer_manager.h | ||
| 463 | hle/service/am/spsm.cpp | 478 | hle/service/am/spsm.cpp |
| 464 | hle/service/am/spsm.h | 479 | hle/service/am/spsm.h |
| 465 | hle/service/am/storage_accessor.cpp | 480 | hle/service/am/storage_accessor.cpp |
| @@ -531,6 +546,8 @@ add_library(core STATIC | |||
| 531 | hle/service/es/es.h | 546 | hle/service/es/es.h |
| 532 | hle/service/eupld/eupld.cpp | 547 | hle/service/eupld/eupld.cpp |
| 533 | hle/service/eupld/eupld.h | 548 | hle/service/eupld/eupld.h |
| 549 | hle/service/event.cpp | ||
| 550 | hle/service/event.h | ||
| 534 | hle/service/fatal/fatal.cpp | 551 | hle/service/fatal/fatal.cpp |
| 535 | hle/service/fatal/fatal.h | 552 | hle/service/fatal/fatal.h |
| 536 | hle/service/fatal/fatal_p.cpp | 553 | hle/service/fatal/fatal_p.cpp |
diff --git a/src/core/hle/service/am/am_types.h b/src/core/hle/service/am/am_types.h new file mode 100644 index 000000000..d0a237a7e --- /dev/null +++ b/src/core/hle/service/am/am_types.h | |||
| @@ -0,0 +1,171 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_funcs.h" | ||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | namespace Service::AM { | ||
| 10 | |||
| 11 | namespace Frontend { | ||
| 12 | class FrontendApplet; | ||
| 13 | } | ||
| 14 | |||
| 15 | enum class AppletType { | ||
| 16 | Application, | ||
| 17 | LibraryApplet, | ||
| 18 | SystemApplet, | ||
| 19 | }; | ||
| 20 | |||
| 21 | enum class GameplayRecordingState : u32 { | ||
| 22 | Disabled, | ||
| 23 | Enabled, | ||
| 24 | }; | ||
| 25 | |||
| 26 | // This is nn::oe::FocusState | ||
| 27 | enum class FocusState : u8 { | ||
| 28 | InFocus = 1, | ||
| 29 | NotInFocus = 2, | ||
| 30 | Background = 3, | ||
| 31 | }; | ||
| 32 | |||
| 33 | // This is nn::oe::OperationMode | ||
| 34 | enum class OperationMode : u8 { | ||
| 35 | Handheld = 0, | ||
| 36 | Docked = 1, | ||
| 37 | }; | ||
| 38 | |||
| 39 | // This is nn::am::service::SystemButtonType | ||
| 40 | enum class SystemButtonType { | ||
| 41 | None, | ||
| 42 | HomeButtonShortPressing, | ||
| 43 | HomeButtonLongPressing, | ||
| 44 | PowerButtonShortPressing, | ||
| 45 | PowerButtonLongPressing, | ||
| 46 | ShutdownSystem, | ||
| 47 | CaptureButtonShortPressing, | ||
| 48 | CaptureButtonLongPressing, | ||
| 49 | }; | ||
| 50 | |||
| 51 | enum class SysPlatformRegion : s32 { | ||
| 52 | Global = 1, | ||
| 53 | Terra = 2, | ||
| 54 | }; | ||
| 55 | |||
| 56 | struct AppletProcessLaunchReason { | ||
| 57 | u8 flag; | ||
| 58 | INSERT_PADDING_BYTES(3); | ||
| 59 | }; | ||
| 60 | static_assert(sizeof(AppletProcessLaunchReason) == 0x4, | ||
| 61 | "AppletProcessLaunchReason is an invalid size"); | ||
| 62 | |||
| 63 | enum class ScreenshotPermission : u32 { | ||
| 64 | Inherit = 0, | ||
| 65 | Enable = 1, | ||
| 66 | Disable = 2, | ||
| 67 | }; | ||
| 68 | |||
| 69 | struct FocusHandlingMode { | ||
| 70 | bool unknown0; | ||
| 71 | bool unknown1; | ||
| 72 | bool unknown2; | ||
| 73 | bool unknown3; | ||
| 74 | }; | ||
| 75 | |||
| 76 | enum class IdleTimeDetectionExtension : u32 { | ||
| 77 | Disabled = 0, | ||
| 78 | Extended = 1, | ||
| 79 | ExtendedUnsafe = 2, | ||
| 80 | }; | ||
| 81 | |||
| 82 | enum class AppletId : u32 { | ||
| 83 | None = 0x00, | ||
| 84 | Application = 0x01, | ||
| 85 | OverlayDisplay = 0x02, | ||
| 86 | QLaunch = 0x03, | ||
| 87 | Starter = 0x04, | ||
| 88 | Auth = 0x0A, | ||
| 89 | Cabinet = 0x0B, | ||
| 90 | Controller = 0x0C, | ||
| 91 | DataErase = 0x0D, | ||
| 92 | Error = 0x0E, | ||
| 93 | NetConnect = 0x0F, | ||
| 94 | ProfileSelect = 0x10, | ||
| 95 | SoftwareKeyboard = 0x11, | ||
| 96 | MiiEdit = 0x12, | ||
| 97 | Web = 0x13, | ||
| 98 | Shop = 0x14, | ||
| 99 | PhotoViewer = 0x15, | ||
| 100 | Settings = 0x16, | ||
| 101 | OfflineWeb = 0x17, | ||
| 102 | LoginShare = 0x18, | ||
| 103 | WebAuth = 0x19, | ||
| 104 | MyPage = 0x1A, | ||
| 105 | }; | ||
| 106 | |||
| 107 | enum class AppletProgramId : u64 { | ||
| 108 | QLaunch = 0x0100000000001000ull, | ||
| 109 | Auth = 0x0100000000001001ull, | ||
| 110 | Cabinet = 0x0100000000001002ull, | ||
| 111 | Controller = 0x0100000000001003ull, | ||
| 112 | DataErase = 0x0100000000001004ull, | ||
| 113 | Error = 0x0100000000001005ull, | ||
| 114 | NetConnect = 0x0100000000001006ull, | ||
| 115 | ProfileSelect = 0x0100000000001007ull, | ||
| 116 | SoftwareKeyboard = 0x0100000000001008ull, | ||
| 117 | MiiEdit = 0x0100000000001009ull, | ||
| 118 | Web = 0x010000000000100Aull, | ||
| 119 | Shop = 0x010000000000100Bull, | ||
| 120 | OverlayDisplay = 0x010000000000100Cull, | ||
| 121 | PhotoViewer = 0x010000000000100Dull, | ||
| 122 | Settings = 0x010000000000100Eull, | ||
| 123 | OfflineWeb = 0x010000000000100Full, | ||
| 124 | LoginShare = 0x0100000000001010ull, | ||
| 125 | WebAuth = 0x0100000000001011ull, | ||
| 126 | Starter = 0x0100000000001012ull, | ||
| 127 | MyPage = 0x0100000000001013ull, | ||
| 128 | MaxProgramId = 0x0100000000001FFFull, | ||
| 129 | }; | ||
| 130 | |||
| 131 | enum class LibraryAppletMode : u32 { | ||
| 132 | AllForeground = 0, | ||
| 133 | Background = 1, | ||
| 134 | NoUI = 2, | ||
| 135 | BackgroundIndirectDisplay = 3, | ||
| 136 | AllForegroundInitiallyHidden = 4, | ||
| 137 | }; | ||
| 138 | |||
| 139 | enum class CommonArgumentVersion : u32 { | ||
| 140 | Version0, | ||
| 141 | Version1, | ||
| 142 | Version2, | ||
| 143 | Version3, | ||
| 144 | }; | ||
| 145 | |||
| 146 | enum class CommonArgumentSize : u32 { | ||
| 147 | Version3 = 0x20, | ||
| 148 | }; | ||
| 149 | |||
| 150 | enum class ThemeColor : u32 { | ||
| 151 | BasicWhite = 0, | ||
| 152 | BasicBlack = 3, | ||
| 153 | }; | ||
| 154 | |||
| 155 | struct CommonArguments { | ||
| 156 | CommonArgumentVersion arguments_version; | ||
| 157 | CommonArgumentSize size; | ||
| 158 | u32 library_version; | ||
| 159 | ThemeColor theme_color; | ||
| 160 | bool play_startup_sound; | ||
| 161 | u64 system_tick; | ||
| 162 | }; | ||
| 163 | static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size."); | ||
| 164 | |||
| 165 | using AppletResourceUserId = u64; | ||
| 166 | using ProgramId = u64; | ||
| 167 | |||
| 168 | struct Applet; | ||
| 169 | struct AppletStorageHolder; | ||
| 170 | |||
| 171 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/applet.cpp b/src/core/hle/service/am/applet.cpp new file mode 100644 index 000000000..8f44fab33 --- /dev/null +++ b/src/core/hle/service/am/applet.cpp | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/scope_exit.h" | ||
| 5 | |||
| 6 | #include "core/hle/service/am/am_results.h" | ||
| 7 | #include "core/hle/service/am/applet.h" | ||
| 8 | |||
| 9 | namespace Service::AM { | ||
| 10 | |||
| 11 | AppletStorageChannel::AppletStorageChannel(KernelHelpers::ServiceContext& context) | ||
| 12 | : m_event(context) {} | ||
| 13 | AppletStorageChannel::~AppletStorageChannel() = default; | ||
| 14 | |||
| 15 | void AppletStorageChannel::PushData(std::shared_ptr<IStorage> storage) { | ||
| 16 | std::scoped_lock lk{m_lock}; | ||
| 17 | |||
| 18 | m_data.emplace_back(std::move(storage)); | ||
| 19 | m_event.Signal(); | ||
| 20 | } | ||
| 21 | |||
| 22 | Result AppletStorageChannel::PopData(std::shared_ptr<IStorage>* out_storage) { | ||
| 23 | std::scoped_lock lk{m_lock}; | ||
| 24 | |||
| 25 | SCOPE_EXIT({ | ||
| 26 | if (m_data.empty()) { | ||
| 27 | m_event.Clear(); | ||
| 28 | } | ||
| 29 | }); | ||
| 30 | |||
| 31 | R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel); | ||
| 32 | |||
| 33 | *out_storage = std::move(m_data.front()); | ||
| 34 | m_data.pop_front(); | ||
| 35 | |||
| 36 | R_SUCCEED(); | ||
| 37 | } | ||
| 38 | |||
| 39 | Kernel::KReadableEvent* AppletStorageChannel::GetEvent() { | ||
| 40 | return m_event.GetHandle(); | ||
| 41 | } | ||
| 42 | |||
| 43 | AppletStorageHolder::AppletStorageHolder(Core::System& system) | ||
| 44 | : context(system, "AppletStorageHolder"), in_data(context), interactive_in_data(context), | ||
| 45 | out_data(context), interactive_out_data(context), state_changed_event(context) {} | ||
| 46 | |||
| 47 | AppletStorageHolder::~AppletStorageHolder() = default; | ||
| 48 | |||
| 49 | Applet::Applet(Core::System& system, std::unique_ptr<Process> process_) | ||
| 50 | : context(system, "Applet"), message_queue(system), process(std::move(process_)), | ||
| 51 | hid_registration(system, *process), gpu_error_detected_event(context), | ||
| 52 | friend_invitation_storage_channel_event(context), notification_storage_channel_event(context), | ||
| 53 | health_warning_disappeared_system_event(context), acquired_sleep_lock_event(context), | ||
| 54 | pop_from_general_channel_event(context), library_applet_launchable_event(context), | ||
| 55 | accumulated_suspended_tick_changed_event(context), sleep_lock_event(context) { | ||
| 56 | |||
| 57 | aruid = process->GetProcessId(); | ||
| 58 | program_id = process->GetProgramId(); | ||
| 59 | } | ||
| 60 | |||
| 61 | Applet::~Applet() = default; | ||
| 62 | |||
| 63 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/applet.h b/src/core/hle/service/am/applet.h new file mode 100644 index 000000000..9650a2615 --- /dev/null +++ b/src/core/hle/service/am/applet.h | |||
| @@ -0,0 +1,164 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <list> | ||
| 7 | #include <mutex> | ||
| 8 | |||
| 9 | #include "common/math_util.h" | ||
| 10 | #include "core/hle/service/apm/apm_controller.h" | ||
| 11 | #include "core/hle/service/caps/caps_types.h" | ||
| 12 | #include "core/hle/service/event.h" | ||
| 13 | #include "core/hle/service/kernel_helpers.h" | ||
| 14 | #include "core/hle/service/service.h" | ||
| 15 | |||
| 16 | #include "core/hle/service/am/am_types.h" | ||
| 17 | #include "core/hle/service/am/applet_message_queue.h" | ||
| 18 | #include "core/hle/service/am/hid_registration.h" | ||
| 19 | #include "core/hle/service/am/managed_layer_holder.h" | ||
| 20 | #include "core/hle/service/am/process.h" | ||
| 21 | #include "core/hle/service/am/storage.h" | ||
| 22 | #include "core/hle/service/am/system_buffer_manager.h" | ||
| 23 | |||
| 24 | namespace Service::Nvnflinger { | ||
| 25 | class FbShareBufferManager; | ||
| 26 | class Nvnflinger; | ||
| 27 | } // namespace Service::Nvnflinger | ||
| 28 | |||
| 29 | namespace Service::AM { | ||
| 30 | |||
| 31 | class AppletStorageChannel { | ||
| 32 | public: | ||
| 33 | explicit AppletStorageChannel(KernelHelpers::ServiceContext& ctx); | ||
| 34 | ~AppletStorageChannel(); | ||
| 35 | |||
| 36 | void PushData(std::shared_ptr<IStorage> storage); | ||
| 37 | Result PopData(std::shared_ptr<IStorage>* out_storage); | ||
| 38 | Kernel::KReadableEvent* GetEvent(); | ||
| 39 | |||
| 40 | private: | ||
| 41 | std::mutex m_lock{}; | ||
| 42 | std::deque<std::shared_ptr<IStorage>> m_data{}; | ||
| 43 | Event m_event; | ||
| 44 | }; | ||
| 45 | |||
| 46 | struct AppletStorageHolder { | ||
| 47 | explicit AppletStorageHolder(Core::System& system); | ||
| 48 | ~AppletStorageHolder(); | ||
| 49 | |||
| 50 | KernelHelpers::ServiceContext context; | ||
| 51 | |||
| 52 | AppletStorageChannel in_data; | ||
| 53 | AppletStorageChannel interactive_in_data; | ||
| 54 | AppletStorageChannel out_data; | ||
| 55 | AppletStorageChannel interactive_out_data; | ||
| 56 | Event state_changed_event; | ||
| 57 | }; | ||
| 58 | |||
| 59 | struct Applet { | ||
| 60 | explicit Applet(Core::System& system, std::unique_ptr<Process> process_); | ||
| 61 | ~Applet(); | ||
| 62 | |||
| 63 | // Lock | ||
| 64 | std::mutex lock{}; | ||
| 65 | |||
| 66 | // Event creation helper | ||
| 67 | KernelHelpers::ServiceContext context; | ||
| 68 | |||
| 69 | // Applet message queue | ||
| 70 | AppletMessageQueue message_queue; | ||
| 71 | |||
| 72 | // Process | ||
| 73 | std::unique_ptr<Process> process; | ||
| 74 | |||
| 75 | // Creation state | ||
| 76 | AppletId applet_id{}; | ||
| 77 | AppletResourceUserId aruid{}; | ||
| 78 | AppletProcessLaunchReason launch_reason{}; | ||
| 79 | AppletType type{}; | ||
| 80 | ProgramId program_id{}; | ||
| 81 | LibraryAppletMode library_applet_mode{}; | ||
| 82 | s32 previous_program_index{-1}; | ||
| 83 | ScreenshotPermission previous_screenshot_permission{ScreenshotPermission::Enable}; | ||
| 84 | |||
| 85 | // hid state | ||
| 86 | HidRegistration hid_registration; | ||
| 87 | |||
| 88 | // vi state | ||
| 89 | SystemBufferManager system_buffer_manager{}; | ||
| 90 | ManagedLayerHolder managed_layer_holder{}; | ||
| 91 | |||
| 92 | // Applet common functions | ||
| 93 | Result terminate_result{}; | ||
| 94 | s32 display_logical_width{}; | ||
| 95 | s32 display_logical_height{}; | ||
| 96 | Common::Rectangle<f32> display_magnification{0, 0, 1, 1}; | ||
| 97 | bool home_button_double_click_enabled{}; | ||
| 98 | bool home_button_short_pressed_blocked{}; | ||
| 99 | bool home_button_long_pressed_blocked{}; | ||
| 100 | bool vr_mode_curtain_required{}; | ||
| 101 | bool sleep_required_by_high_temperature{}; | ||
| 102 | bool sleep_required_by_low_battery{}; | ||
| 103 | s32 cpu_boost_request_priority{-1}; | ||
| 104 | bool handling_capture_button_short_pressed_message_enabled_for_applet{}; | ||
| 105 | bool handling_capture_button_long_pressed_message_enabled_for_applet{}; | ||
| 106 | u32 application_core_usage_mode{}; | ||
| 107 | |||
| 108 | // Application functions | ||
| 109 | bool gameplay_recording_supported{}; | ||
| 110 | GameplayRecordingState gameplay_recording_state{GameplayRecordingState::Disabled}; | ||
| 111 | bool jit_service_launched{}; | ||
| 112 | bool is_running{}; | ||
| 113 | bool application_crash_report_enabled{}; | ||
| 114 | |||
| 115 | // Common state | ||
| 116 | FocusState focus_state{}; | ||
| 117 | bool sleep_lock_enabled{}; | ||
| 118 | bool vr_mode_enabled{}; | ||
| 119 | bool lcd_backlight_off_enabled{}; | ||
| 120 | APM::CpuBoostMode boost_mode{}; | ||
| 121 | bool request_exit_to_library_applet_at_execute_next_program_enabled{}; | ||
| 122 | |||
| 123 | // Channels | ||
| 124 | std::deque<std::vector<u8>> user_channel_launch_parameter{}; | ||
| 125 | std::deque<std::vector<u8>> preselected_user_launch_parameter{}; | ||
| 126 | |||
| 127 | // Caller applet | ||
| 128 | std::weak_ptr<Applet> caller_applet{}; | ||
| 129 | std::shared_ptr<AppletStorageHolder> caller_applet_storage{}; | ||
| 130 | bool is_completed{}; | ||
| 131 | |||
| 132 | // Self state | ||
| 133 | bool exit_locked{}; | ||
| 134 | s32 fatal_section_count{}; | ||
| 135 | bool operation_mode_changed_notification_enabled{true}; | ||
| 136 | bool performance_mode_changed_notification_enabled{true}; | ||
| 137 | FocusHandlingMode focus_handling_mode{}; | ||
| 138 | bool restart_message_enabled{}; | ||
| 139 | bool out_of_focus_suspension_enabled{true}; | ||
| 140 | Capture::AlbumImageOrientation album_image_orientation{}; | ||
| 141 | bool handles_request_to_display{}; | ||
| 142 | ScreenshotPermission screenshot_permission{}; | ||
| 143 | IdleTimeDetectionExtension idle_time_detection_extension{}; | ||
| 144 | bool auto_sleep_disabled{}; | ||
| 145 | u64 suspended_ticks{}; | ||
| 146 | bool album_image_taken_notification_enabled{}; | ||
| 147 | bool record_volume_muted{}; | ||
| 148 | |||
| 149 | // Events | ||
| 150 | Event gpu_error_detected_event; | ||
| 151 | Event friend_invitation_storage_channel_event; | ||
| 152 | Event notification_storage_channel_event; | ||
| 153 | Event health_warning_disappeared_system_event; | ||
| 154 | Event acquired_sleep_lock_event; | ||
| 155 | Event pop_from_general_channel_event; | ||
| 156 | Event library_applet_launchable_event; | ||
| 157 | Event accumulated_suspended_tick_changed_event; | ||
| 158 | Event sleep_lock_event; | ||
| 159 | |||
| 160 | // Frontend state | ||
| 161 | std::shared_ptr<Frontend::FrontendApplet> frontend{}; | ||
| 162 | }; | ||
| 163 | |||
| 164 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/applet_manager.cpp b/src/core/hle/service/am/applet_manager.cpp new file mode 100644 index 000000000..9f7ccfbf2 --- /dev/null +++ b/src/core/hle/service/am/applet_manager.cpp | |||
| @@ -0,0 +1,352 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/settings.h" | ||
| 5 | #include "common/uuid.h" | ||
| 6 | #include "core/core.h" | ||
| 7 | #include "core/core_timing.h" | ||
| 8 | #include "core/hle/service/acc/profile_manager.h" | ||
| 9 | #include "core/hle/service/am/applet_manager.h" | ||
| 10 | #include "core/hle/service/am/applets/applet_cabinet.h" | ||
| 11 | #include "core/hle/service/am/applets/applet_controller.h" | ||
| 12 | #include "core/hle/service/am/applets/applet_mii_edit_types.h" | ||
| 13 | #include "core/hle/service/am/applets/applet_software_keyboard_types.h" | ||
| 14 | #include "hid_core/hid_types.h" | ||
| 15 | |||
| 16 | namespace Service::AM { | ||
| 17 | |||
| 18 | namespace { | ||
| 19 | |||
| 20 | constexpr u32 LaunchParameterAccountPreselectedUserMagic = 0xC79497CA; | ||
| 21 | |||
| 22 | struct LaunchParameterAccountPreselectedUser { | ||
| 23 | u32 magic; | ||
| 24 | u32 is_account_selected; | ||
| 25 | Common::UUID current_user; | ||
| 26 | INSERT_PADDING_BYTES(0x70); | ||
| 27 | }; | ||
| 28 | static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); | ||
| 29 | |||
| 30 | AppletStorageChannel& InitializeFakeCallerApplet(Core::System& system, | ||
| 31 | std::shared_ptr<Applet>& applet) { | ||
| 32 | applet->caller_applet_storage = std::make_shared<AppletStorageHolder>(system); | ||
| 33 | return applet->caller_applet_storage->in_data; | ||
| 34 | } | ||
| 35 | |||
| 36 | void PushInShowAlbum(Core::System& system, AppletStorageChannel& channel) { | ||
| 37 | const CommonArguments arguments{ | ||
| 38 | .arguments_version = CommonArgumentVersion::Version3, | ||
| 39 | .size = CommonArgumentSize::Version3, | ||
| 40 | .library_version = 1, | ||
| 41 | .theme_color = ThemeColor::BasicBlack, | ||
| 42 | .play_startup_sound = true, | ||
| 43 | .system_tick = system.CoreTiming().GetClockTicks(), | ||
| 44 | }; | ||
| 45 | |||
| 46 | std::vector<u8> argument_data(sizeof(arguments)); | ||
| 47 | std::vector<u8> settings_data{2}; | ||
| 48 | std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); | ||
| 49 | channel.PushData(std::make_shared<IStorage>(system, std::move(argument_data))); | ||
| 50 | channel.PushData(std::make_shared<IStorage>(system, std::move(settings_data))); | ||
| 51 | } | ||
| 52 | |||
| 53 | void PushInShowController(Core::System& system, AppletStorageChannel& channel) { | ||
| 54 | const CommonArguments common_args = { | ||
| 55 | .arguments_version = CommonArgumentVersion::Version3, | ||
| 56 | .size = CommonArgumentSize::Version3, | ||
| 57 | .library_version = static_cast<u32>(Applets::ControllerAppletVersion::Version8), | ||
| 58 | .theme_color = ThemeColor::BasicBlack, | ||
| 59 | .play_startup_sound = true, | ||
| 60 | .system_tick = system.CoreTiming().GetClockTicks(), | ||
| 61 | }; | ||
| 62 | |||
| 63 | Applets::ControllerSupportArgNew user_args = { | ||
| 64 | .header = {.player_count_min = 1, | ||
| 65 | .player_count_max = 4, | ||
| 66 | .enable_take_over_connection = true, | ||
| 67 | .enable_left_justify = false, | ||
| 68 | .enable_permit_joy_dual = true, | ||
| 69 | .enable_single_mode = false, | ||
| 70 | .enable_identification_color = false}, | ||
| 71 | .identification_colors = {}, | ||
| 72 | .enable_explain_text = false, | ||
| 73 | .explain_text = {}, | ||
| 74 | }; | ||
| 75 | |||
| 76 | Applets::ControllerSupportArgPrivate private_args = { | ||
| 77 | .arg_private_size = sizeof(Applets::ControllerSupportArgPrivate), | ||
| 78 | .arg_size = sizeof(Applets::ControllerSupportArgNew), | ||
| 79 | .is_home_menu = true, | ||
| 80 | .flag_1 = true, | ||
| 81 | .mode = Applets::ControllerSupportMode::ShowControllerSupport, | ||
| 82 | .caller = Applets::ControllerSupportCaller:: | ||
| 83 | Application, // switchbrew: Always zero except with | ||
| 84 | // ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem, | ||
| 85 | // which sets this to the input param | ||
| 86 | .style_set = Core::HID::NpadStyleSet::None, | ||
| 87 | .joy_hold_type = 0, | ||
| 88 | }; | ||
| 89 | std::vector<u8> common_args_data(sizeof(common_args)); | ||
| 90 | std::vector<u8> private_args_data(sizeof(private_args)); | ||
| 91 | std::vector<u8> user_args_data(sizeof(user_args)); | ||
| 92 | |||
| 93 | std::memcpy(common_args_data.data(), &common_args, sizeof(common_args)); | ||
| 94 | std::memcpy(private_args_data.data(), &private_args, sizeof(private_args)); | ||
| 95 | std::memcpy(user_args_data.data(), &user_args, sizeof(user_args)); | ||
| 96 | |||
| 97 | channel.PushData(std::make_shared<IStorage>(system, std::move(common_args_data))); | ||
| 98 | channel.PushData(std::make_shared<IStorage>(system, std::move(private_args_data))); | ||
| 99 | channel.PushData(std::make_shared<IStorage>(system, std::move(user_args_data))); | ||
| 100 | } | ||
| 101 | |||
| 102 | void PushInShowCabinetData(Core::System& system, AppletStorageChannel& channel) { | ||
| 103 | const CommonArguments arguments{ | ||
| 104 | .arguments_version = CommonArgumentVersion::Version3, | ||
| 105 | .size = CommonArgumentSize::Version3, | ||
| 106 | .library_version = static_cast<u32>(Applets::CabinetAppletVersion::Version1), | ||
| 107 | .theme_color = ThemeColor::BasicBlack, | ||
| 108 | .play_startup_sound = true, | ||
| 109 | .system_tick = system.CoreTiming().GetClockTicks(), | ||
| 110 | }; | ||
| 111 | |||
| 112 | const Applets::StartParamForAmiiboSettings amiibo_settings{ | ||
| 113 | .param_1 = 0, | ||
| 114 | .applet_mode = system.GetAppletManager().GetCabinetMode(), | ||
| 115 | .flags = Applets::CabinetFlags::None, | ||
| 116 | .amiibo_settings_1 = 0, | ||
| 117 | .device_handle = 0, | ||
| 118 | .tag_info{}, | ||
| 119 | .register_info{}, | ||
| 120 | .amiibo_settings_3{}, | ||
| 121 | }; | ||
| 122 | |||
| 123 | std::vector<u8> argument_data(sizeof(arguments)); | ||
| 124 | std::vector<u8> settings_data(sizeof(amiibo_settings)); | ||
| 125 | std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); | ||
| 126 | std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings)); | ||
| 127 | channel.PushData(std::make_shared<IStorage>(system, std::move(argument_data))); | ||
| 128 | channel.PushData(std::make_shared<IStorage>(system, std::move(settings_data))); | ||
| 129 | } | ||
| 130 | |||
| 131 | void PushInShowMiiEditData(Core::System& system, AppletStorageChannel& channel) { | ||
| 132 | struct MiiEditV3 { | ||
| 133 | Applets::MiiEditAppletInputCommon common; | ||
| 134 | Applets::MiiEditAppletInputV3 input; | ||
| 135 | }; | ||
| 136 | static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size."); | ||
| 137 | |||
| 138 | MiiEditV3 mii_arguments{ | ||
| 139 | .common = | ||
| 140 | { | ||
| 141 | .version = Applets::MiiEditAppletVersion::Version3, | ||
| 142 | .applet_mode = Applets::MiiEditAppletMode::ShowMiiEdit, | ||
| 143 | }, | ||
| 144 | .input{}, | ||
| 145 | }; | ||
| 146 | |||
| 147 | std::vector<u8> argument_data(sizeof(mii_arguments)); | ||
| 148 | std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments)); | ||
| 149 | |||
| 150 | channel.PushData(std::make_shared<IStorage>(system, std::move(argument_data))); | ||
| 151 | } | ||
| 152 | |||
| 153 | void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& channel) { | ||
| 154 | const CommonArguments arguments{ | ||
| 155 | .arguments_version = CommonArgumentVersion::Version3, | ||
| 156 | .size = CommonArgumentSize::Version3, | ||
| 157 | .library_version = static_cast<u32>(Applets::SwkbdAppletVersion::Version524301), | ||
| 158 | .theme_color = ThemeColor::BasicBlack, | ||
| 159 | .play_startup_sound = true, | ||
| 160 | .system_tick = system.CoreTiming().GetClockTicks(), | ||
| 161 | }; | ||
| 162 | |||
| 163 | std::vector<char16_t> initial_string(0); | ||
| 164 | |||
| 165 | const Applets::SwkbdConfigCommon swkbd_config{ | ||
| 166 | .type = Applets::SwkbdType::Qwerty, | ||
| 167 | .ok_text{}, | ||
| 168 | .left_optional_symbol_key{}, | ||
| 169 | .right_optional_symbol_key{}, | ||
| 170 | .use_prediction = false, | ||
| 171 | .key_disable_flags{}, | ||
| 172 | .initial_cursor_position = Applets::SwkbdInitialCursorPosition::Start, | ||
| 173 | .header_text{}, | ||
| 174 | .sub_text{}, | ||
| 175 | .guide_text{}, | ||
| 176 | .max_text_length = 500, | ||
| 177 | .min_text_length = 0, | ||
| 178 | .password_mode = Applets::SwkbdPasswordMode::Disabled, | ||
| 179 | .text_draw_type = Applets::SwkbdTextDrawType::Box, | ||
| 180 | .enable_return_button = true, | ||
| 181 | .use_utf8 = false, | ||
| 182 | .use_blur_background = true, | ||
| 183 | .initial_string_offset{}, | ||
| 184 | .initial_string_length = static_cast<u32>(initial_string.size()), | ||
| 185 | .user_dictionary_offset{}, | ||
| 186 | .user_dictionary_entries{}, | ||
| 187 | .use_text_check = false, | ||
| 188 | }; | ||
| 189 | |||
| 190 | Applets::SwkbdConfigNew swkbd_config_new{}; | ||
| 191 | |||
| 192 | std::vector<u8> argument_data(sizeof(arguments)); | ||
| 193 | std::vector<u8> swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new)); | ||
| 194 | std::vector<u8> work_buffer(swkbd_config.initial_string_length * sizeof(char16_t)); | ||
| 195 | |||
| 196 | std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); | ||
| 197 | std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config)); | ||
| 198 | std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new, | ||
| 199 | sizeof(Applets::SwkbdConfigNew)); | ||
| 200 | std::memcpy(work_buffer.data(), initial_string.data(), | ||
| 201 | swkbd_config.initial_string_length * sizeof(char16_t)); | ||
| 202 | |||
| 203 | channel.PushData(std::make_shared<IStorage>(system, std::move(argument_data))); | ||
| 204 | channel.PushData(std::make_shared<IStorage>(system, std::move(swkbd_data))); | ||
| 205 | channel.PushData(std::make_shared<IStorage>(system, std::move(work_buffer))); | ||
| 206 | } | ||
| 207 | |||
| 208 | } // namespace | ||
| 209 | |||
| 210 | AppletManager::AppletManager(Core::System& system) : m_system(system) {} | ||
| 211 | AppletManager::~AppletManager() { | ||
| 212 | this->Reset(); | ||
| 213 | } | ||
| 214 | |||
| 215 | void AppletManager::InsertApplet(std::shared_ptr<Applet> applet) { | ||
| 216 | std::scoped_lock lk{m_lock}; | ||
| 217 | |||
| 218 | m_applets.emplace(applet->aruid, std::move(applet)); | ||
| 219 | } | ||
| 220 | |||
| 221 | void AppletManager::TerminateAndRemoveApplet(AppletResourceUserId aruid) { | ||
| 222 | std::shared_ptr<Applet> applet; | ||
| 223 | { | ||
| 224 | std::scoped_lock lk{m_lock}; | ||
| 225 | |||
| 226 | const auto it = m_applets.find(aruid); | ||
| 227 | if (it == m_applets.end()) { | ||
| 228 | return; | ||
| 229 | } | ||
| 230 | |||
| 231 | applet = it->second; | ||
| 232 | m_applets.erase(it); | ||
| 233 | } | ||
| 234 | |||
| 235 | // Terminate process. | ||
| 236 | applet->process->Terminate(); | ||
| 237 | } | ||
| 238 | |||
| 239 | void AppletManager::CreateAndInsertByFrontendAppletParameters( | ||
| 240 | AppletResourceUserId aruid, const FrontendAppletParameters& params) { | ||
| 241 | // TODO: this should be run inside AM so that the events will have a parent process | ||
| 242 | // TODO: have am create the guest process | ||
| 243 | auto applet = std::make_shared<Applet>(m_system, std::make_unique<Process>(m_system)); | ||
| 244 | |||
| 245 | applet->aruid = aruid; | ||
| 246 | applet->program_id = params.program_id; | ||
| 247 | applet->applet_id = params.applet_id; | ||
| 248 | applet->type = params.applet_type; | ||
| 249 | applet->previous_program_index = params.previous_program_index; | ||
| 250 | |||
| 251 | // Push UserChannel data from previous application | ||
| 252 | if (params.launch_type == LaunchType::ApplicationInitiated) { | ||
| 253 | applet->user_channel_launch_parameter.swap(m_system.GetUserChannel()); | ||
| 254 | } | ||
| 255 | |||
| 256 | // TODO: Read whether we need a preselected user from NACP? | ||
| 257 | // TODO: This can be done quite easily from loader | ||
| 258 | { | ||
| 259 | LaunchParameterAccountPreselectedUser lp{}; | ||
| 260 | |||
| 261 | lp.magic = LaunchParameterAccountPreselectedUserMagic; | ||
| 262 | lp.is_account_selected = 1; | ||
| 263 | |||
| 264 | Account::ProfileManager profile_manager{}; | ||
| 265 | const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user)); | ||
| 266 | ASSERT(uuid.has_value() && uuid->IsValid()); | ||
| 267 | lp.current_user = *uuid; | ||
| 268 | |||
| 269 | std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); | ||
| 270 | std::memcpy(buffer.data(), &lp, buffer.size()); | ||
| 271 | |||
| 272 | applet->preselected_user_launch_parameter.push_back(std::move(buffer)); | ||
| 273 | } | ||
| 274 | |||
| 275 | // Starting from frontend, some applets require input data. | ||
| 276 | switch (applet->applet_id) { | ||
| 277 | case AppletId::Cabinet: | ||
| 278 | PushInShowCabinetData(m_system, InitializeFakeCallerApplet(m_system, applet)); | ||
| 279 | break; | ||
| 280 | case AppletId::MiiEdit: | ||
| 281 | PushInShowMiiEditData(m_system, InitializeFakeCallerApplet(m_system, applet)); | ||
| 282 | break; | ||
| 283 | case AppletId::PhotoViewer: | ||
| 284 | PushInShowAlbum(m_system, InitializeFakeCallerApplet(m_system, applet)); | ||
| 285 | break; | ||
| 286 | case AppletId::SoftwareKeyboard: | ||
| 287 | PushInShowSoftwareKeyboard(m_system, InitializeFakeCallerApplet(m_system, applet)); | ||
| 288 | break; | ||
| 289 | case AppletId::Controller: | ||
| 290 | PushInShowController(m_system, InitializeFakeCallerApplet(m_system, applet)); | ||
| 291 | break; | ||
| 292 | default: | ||
| 293 | break; | ||
| 294 | } | ||
| 295 | |||
| 296 | // Applet was started by frontend, so it is foreground. | ||
| 297 | applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); | ||
| 298 | applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); | ||
| 299 | applet->focus_state = FocusState::InFocus; | ||
| 300 | |||
| 301 | this->InsertApplet(std::move(applet)); | ||
| 302 | } | ||
| 303 | |||
| 304 | std::shared_ptr<Applet> AppletManager::GetByAppletResourceUserId(AppletResourceUserId aruid) const { | ||
| 305 | std::scoped_lock lk{m_lock}; | ||
| 306 | |||
| 307 | if (const auto it = m_applets.find(aruid); it != m_applets.end()) { | ||
| 308 | return it->second; | ||
| 309 | } | ||
| 310 | |||
| 311 | return {}; | ||
| 312 | } | ||
| 313 | |||
| 314 | void AppletManager::Reset() { | ||
| 315 | std::scoped_lock lk{m_lock}; | ||
| 316 | |||
| 317 | m_applets.clear(); | ||
| 318 | } | ||
| 319 | |||
| 320 | void AppletManager::RequestExit() { | ||
| 321 | std::scoped_lock lk{m_lock}; | ||
| 322 | |||
| 323 | for (const auto& [aruid, applet] : m_applets) { | ||
| 324 | applet->message_queue.RequestExit(); | ||
| 325 | } | ||
| 326 | } | ||
| 327 | |||
| 328 | void AppletManager::RequestResume() { | ||
| 329 | std::scoped_lock lk{m_lock}; | ||
| 330 | |||
| 331 | for (const auto& [aruid, applet] : m_applets) { | ||
| 332 | applet->message_queue.RequestResume(); | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | void AppletManager::OperationModeChanged() { | ||
| 337 | std::scoped_lock lk{m_lock}; | ||
| 338 | |||
| 339 | for (const auto& [aruid, applet] : m_applets) { | ||
| 340 | applet->message_queue.OperationModeChanged(); | ||
| 341 | } | ||
| 342 | } | ||
| 343 | |||
| 344 | void AppletManager::FocusStateChanged() { | ||
| 345 | std::scoped_lock lk{m_lock}; | ||
| 346 | |||
| 347 | for (const auto& [aruid, applet] : m_applets) { | ||
| 348 | applet->message_queue.FocusStateChanged(); | ||
| 349 | } | ||
| 350 | } | ||
| 351 | |||
| 352 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/applet_manager.h b/src/core/hle/service/am/applet_manager.h new file mode 100644 index 000000000..4875de309 --- /dev/null +++ b/src/core/hle/service/am/applet_manager.h | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <map> | ||
| 7 | #include <mutex> | ||
| 8 | |||
| 9 | #include "core/hle/service/am/applet.h" | ||
| 10 | |||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::AM { | ||
| 16 | |||
| 17 | enum class LaunchType { | ||
| 18 | FrontendInitiated, | ||
| 19 | ApplicationInitiated, | ||
| 20 | }; | ||
| 21 | |||
| 22 | struct FrontendAppletParameters { | ||
| 23 | ProgramId program_id{}; | ||
| 24 | AppletId applet_id{}; | ||
| 25 | AppletType applet_type{}; | ||
| 26 | LaunchType launch_type{}; | ||
| 27 | s32 program_index{}; | ||
| 28 | s32 previous_program_index{-1}; | ||
| 29 | }; | ||
| 30 | |||
| 31 | class AppletManager { | ||
| 32 | public: | ||
| 33 | explicit AppletManager(Core::System& system); | ||
| 34 | ~AppletManager(); | ||
| 35 | |||
| 36 | void InsertApplet(std::shared_ptr<Applet> applet); | ||
| 37 | void TerminateAndRemoveApplet(AppletResourceUserId aruid); | ||
| 38 | |||
| 39 | void CreateAndInsertByFrontendAppletParameters(AppletResourceUserId aruid, | ||
| 40 | const FrontendAppletParameters& params); | ||
| 41 | std::shared_ptr<Applet> GetByAppletResourceUserId(AppletResourceUserId aruid) const; | ||
| 42 | |||
| 43 | void Reset(); | ||
| 44 | |||
| 45 | void RequestExit(); | ||
| 46 | void RequestResume(); | ||
| 47 | void OperationModeChanged(); | ||
| 48 | void FocusStateChanged(); | ||
| 49 | |||
| 50 | private: | ||
| 51 | Core::System& m_system; | ||
| 52 | |||
| 53 | mutable std::mutex m_lock{}; | ||
| 54 | std::map<AppletResourceUserId, std::shared_ptr<Applet>> m_applets{}; | ||
| 55 | |||
| 56 | // AudioController state goes here | ||
| 57 | }; | ||
| 58 | |||
| 59 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/hid_registration.cpp b/src/core/hle/service/am/hid_registration.cpp new file mode 100644 index 000000000..b9426f7b6 --- /dev/null +++ b/src/core/hle/service/am/hid_registration.cpp | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/hle/service/am/hid_registration.h" | ||
| 6 | #include "core/hle/service/am/process.h" | ||
| 7 | #include "core/hle/service/hid/hid_server.h" | ||
| 8 | #include "core/hle/service/sm/sm.h" | ||
| 9 | #include "hid_core/resource_manager.h" | ||
| 10 | |||
| 11 | namespace Service::AM { | ||
| 12 | |||
| 13 | HidRegistration::HidRegistration(Core::System& system, Process& process) : m_process(process) { | ||
| 14 | m_hid_server = system.ServiceManager().GetService<HID::IHidServer>("hid"); | ||
| 15 | |||
| 16 | if (m_process.IsInitialized()) { | ||
| 17 | m_hid_server->GetResourceManager()->RegisterAppletResourceUserId(m_process.GetProcessId(), | ||
| 18 | true); | ||
| 19 | } | ||
| 20 | } | ||
| 21 | |||
| 22 | HidRegistration::~HidRegistration() { | ||
| 23 | if (m_process.IsInitialized()) { | ||
| 24 | m_hid_server->GetResourceManager()->UnregisterAppletResourceUserId( | ||
| 25 | m_process.GetProcessId()); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/hid_registration.h b/src/core/hle/service/am/hid_registration.h new file mode 100644 index 000000000..8a732349c --- /dev/null +++ b/src/core/hle/service/am/hid_registration.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | |||
| 8 | namespace Core { | ||
| 9 | class System; | ||
| 10 | } | ||
| 11 | |||
| 12 | namespace Service::HID { | ||
| 13 | class IHidServer; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service::AM { | ||
| 17 | |||
| 18 | class Process; | ||
| 19 | |||
| 20 | class HidRegistration { | ||
| 21 | public: | ||
| 22 | explicit HidRegistration(Core::System& system, Process& process); | ||
| 23 | ~HidRegistration(); | ||
| 24 | |||
| 25 | private: | ||
| 26 | Process& m_process; | ||
| 27 | std::shared_ptr<Service::HID::IHidServer> m_hid_server; | ||
| 28 | }; | ||
| 29 | |||
| 30 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/library_applet_storage.cpp b/src/core/hle/service/am/library_applet_storage.cpp new file mode 100644 index 000000000..46e6c0111 --- /dev/null +++ b/src/core/hle/service/am/library_applet_storage.cpp | |||
| @@ -0,0 +1,140 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/kernel/k_transfer_memory.h" | ||
| 5 | #include "core/hle/service/am/am_results.h" | ||
| 6 | #include "core/hle/service/am/library_applet_storage.h" | ||
| 7 | #include "core/memory.h" | ||
| 8 | |||
| 9 | namespace Service::AM { | ||
| 10 | |||
| 11 | namespace { | ||
| 12 | |||
| 13 | Result ValidateOffset(s64 offset, size_t size, size_t data_size) { | ||
| 14 | R_UNLESS(offset >= 0, AM::ResultInvalidOffset); | ||
| 15 | |||
| 16 | const size_t begin = offset; | ||
| 17 | const size_t end = begin + size; | ||
| 18 | |||
| 19 | R_UNLESS(begin <= end && end <= data_size, AM::ResultInvalidOffset); | ||
| 20 | R_SUCCEED(); | ||
| 21 | } | ||
| 22 | |||
| 23 | class BufferLibraryAppletStorage final : public LibraryAppletStorage { | ||
| 24 | public: | ||
| 25 | explicit BufferLibraryAppletStorage(std::vector<u8>&& data) : m_data(std::move(data)) {} | ||
| 26 | ~BufferLibraryAppletStorage() = default; | ||
| 27 | |||
| 28 | Result Read(s64 offset, void* buffer, size_t size) override { | ||
| 29 | R_TRY(ValidateOffset(offset, size, m_data.size())); | ||
| 30 | |||
| 31 | std::memcpy(buffer, m_data.data() + offset, size); | ||
| 32 | |||
| 33 | R_SUCCEED(); | ||
| 34 | } | ||
| 35 | |||
| 36 | Result Write(s64 offset, const void* buffer, size_t size) override { | ||
| 37 | R_TRY(ValidateOffset(offset, size, m_data.size())); | ||
| 38 | |||
| 39 | std::memcpy(m_data.data() + offset, buffer, size); | ||
| 40 | |||
| 41 | R_SUCCEED(); | ||
| 42 | } | ||
| 43 | |||
| 44 | s64 GetSize() override { | ||
| 45 | return m_data.size(); | ||
| 46 | } | ||
| 47 | |||
| 48 | Kernel::KTransferMemory* GetHandle() override { | ||
| 49 | return nullptr; | ||
| 50 | } | ||
| 51 | |||
| 52 | private: | ||
| 53 | std::vector<u8> m_data; | ||
| 54 | }; | ||
| 55 | |||
| 56 | class TransferMemoryLibraryAppletStorage : public LibraryAppletStorage { | ||
| 57 | public: | ||
| 58 | explicit TransferMemoryLibraryAppletStorage(Core::Memory::Memory& memory, | ||
| 59 | Kernel::KTransferMemory* trmem, bool is_writable, | ||
| 60 | s64 size) | ||
| 61 | : m_memory(memory), m_trmem(trmem), m_is_writable(is_writable), m_size(size) { | ||
| 62 | m_trmem->Open(); | ||
| 63 | } | ||
| 64 | |||
| 65 | ~TransferMemoryLibraryAppletStorage() { | ||
| 66 | m_trmem->Close(); | ||
| 67 | m_trmem = nullptr; | ||
| 68 | } | ||
| 69 | |||
| 70 | Result Read(s64 offset, void* buffer, size_t size) override { | ||
| 71 | R_TRY(ValidateOffset(offset, size, m_size)); | ||
| 72 | |||
| 73 | m_memory.ReadBlock(m_trmem->GetSourceAddress(), buffer, size); | ||
| 74 | |||
| 75 | R_SUCCEED(); | ||
| 76 | } | ||
| 77 | |||
| 78 | Result Write(s64 offset, const void* buffer, size_t size) override { | ||
| 79 | R_UNLESS(m_is_writable, ResultUnknown); | ||
| 80 | R_TRY(ValidateOffset(offset, size, m_size)); | ||
| 81 | |||
| 82 | m_memory.WriteBlock(m_trmem->GetSourceAddress(), buffer, size); | ||
| 83 | |||
| 84 | R_SUCCEED(); | ||
| 85 | } | ||
| 86 | |||
| 87 | s64 GetSize() override { | ||
| 88 | return m_size; | ||
| 89 | } | ||
| 90 | |||
| 91 | Kernel::KTransferMemory* GetHandle() override { | ||
| 92 | return nullptr; | ||
| 93 | } | ||
| 94 | |||
| 95 | protected: | ||
| 96 | Core::Memory::Memory& m_memory; | ||
| 97 | Kernel::KTransferMemory* m_trmem; | ||
| 98 | bool m_is_writable; | ||
| 99 | s64 m_size; | ||
| 100 | }; | ||
| 101 | |||
| 102 | class HandleLibraryAppletStorage : public TransferMemoryLibraryAppletStorage { | ||
| 103 | public: | ||
| 104 | explicit HandleLibraryAppletStorage(Core::Memory::Memory& memory, | ||
| 105 | Kernel::KTransferMemory* trmem, s64 size) | ||
| 106 | : TransferMemoryLibraryAppletStorage(memory, trmem, true, size) {} | ||
| 107 | ~HandleLibraryAppletStorage() = default; | ||
| 108 | |||
| 109 | Kernel::KTransferMemory* GetHandle() override { | ||
| 110 | return m_trmem; | ||
| 111 | } | ||
| 112 | }; | ||
| 113 | |||
| 114 | } // namespace | ||
| 115 | |||
| 116 | LibraryAppletStorage::~LibraryAppletStorage() = default; | ||
| 117 | |||
| 118 | std::vector<u8> LibraryAppletStorage::GetData() { | ||
| 119 | std::vector<u8> data(this->GetSize()); | ||
| 120 | this->Read(0, data.data(), data.size()); | ||
| 121 | return data; | ||
| 122 | } | ||
| 123 | |||
| 124 | std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data) { | ||
| 125 | return std::make_shared<BufferLibraryAppletStorage>(std::move(data)); | ||
| 126 | } | ||
| 127 | |||
| 128 | std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory, | ||
| 129 | Kernel::KTransferMemory* trmem, | ||
| 130 | bool is_writable, s64 size) { | ||
| 131 | return std::make_shared<TransferMemoryLibraryAppletStorage>(memory, trmem, is_writable, size); | ||
| 132 | } | ||
| 133 | |||
| 134 | std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory, | ||
| 135 | Kernel::KTransferMemory* trmem, | ||
| 136 | s64 size) { | ||
| 137 | return std::make_shared<HandleLibraryAppletStorage>(memory, trmem, size); | ||
| 138 | } | ||
| 139 | |||
| 140 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/library_applet_storage.h b/src/core/hle/service/am/library_applet_storage.h new file mode 100644 index 000000000..7f53f3a9c --- /dev/null +++ b/src/core/hle/service/am/library_applet_storage.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/service.h" | ||
| 7 | |||
| 8 | namespace Core::Memory { | ||
| 9 | class Memory; | ||
| 10 | } | ||
| 11 | |||
| 12 | namespace Kernel { | ||
| 13 | class KTransferMemory; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service::AM { | ||
| 17 | |||
| 18 | class LibraryAppletStorage { | ||
| 19 | public: | ||
| 20 | virtual ~LibraryAppletStorage(); | ||
| 21 | virtual Result Read(s64 offset, void* buffer, size_t size) = 0; | ||
| 22 | virtual Result Write(s64 offset, const void* buffer, size_t size) = 0; | ||
| 23 | virtual s64 GetSize() = 0; | ||
| 24 | virtual Kernel::KTransferMemory* GetHandle() = 0; | ||
| 25 | |||
| 26 | std::vector<u8> GetData(); | ||
| 27 | }; | ||
| 28 | |||
| 29 | std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data); | ||
| 30 | std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory, | ||
| 31 | Kernel::KTransferMemory* trmem, | ||
| 32 | bool is_writable, s64 size); | ||
| 33 | std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory, | ||
| 34 | Kernel::KTransferMemory* trmem, s64 size); | ||
| 35 | |||
| 36 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/managed_layer_holder.cpp b/src/core/hle/service/am/managed_layer_holder.cpp new file mode 100644 index 000000000..61eb8641a --- /dev/null +++ b/src/core/hle/service/am/managed_layer_holder.cpp | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/am/managed_layer_holder.h" | ||
| 5 | #include "core/hle/service/nvnflinger/nvnflinger.h" | ||
| 6 | |||
| 7 | namespace Service::AM { | ||
| 8 | |||
| 9 | ManagedLayerHolder::ManagedLayerHolder() = default; | ||
| 10 | ManagedLayerHolder::~ManagedLayerHolder() { | ||
| 11 | if (!m_nvnflinger) { | ||
| 12 | return; | ||
| 13 | } | ||
| 14 | |||
| 15 | for (const auto& layer : m_managed_display_layers) { | ||
| 16 | m_nvnflinger->DestroyLayer(layer); | ||
| 17 | } | ||
| 18 | |||
| 19 | for (const auto& layer : m_managed_display_recording_layers) { | ||
| 20 | m_nvnflinger->DestroyLayer(layer); | ||
| 21 | } | ||
| 22 | |||
| 23 | m_nvnflinger = nullptr; | ||
| 24 | } | ||
| 25 | |||
| 26 | void ManagedLayerHolder::Initialize(Nvnflinger::Nvnflinger* nvnflinger) { | ||
| 27 | m_nvnflinger = nvnflinger; | ||
| 28 | } | ||
| 29 | |||
| 30 | void ManagedLayerHolder::CreateManagedDisplayLayer(u64* out_layer) { | ||
| 31 | // TODO(Subv): Find out how AM determines the display to use, for now just | ||
| 32 | // create the layer in the Default display. | ||
| 33 | const auto display_id = m_nvnflinger->OpenDisplay("Default"); | ||
| 34 | const auto layer_id = m_nvnflinger->CreateLayer(*display_id); | ||
| 35 | |||
| 36 | m_managed_display_layers.emplace(*layer_id); | ||
| 37 | |||
| 38 | *out_layer = *layer_id; | ||
| 39 | } | ||
| 40 | |||
| 41 | void ManagedLayerHolder::CreateManagedDisplaySeparableLayer(u64* out_layer, | ||
| 42 | u64* out_recording_layer) { | ||
| 43 | // TODO(Subv): Find out how AM determines the display to use, for now just | ||
| 44 | // create the layer in the Default display. | ||
| 45 | // This calls nn::vi::CreateRecordingLayer() which creates another layer. | ||
| 46 | // Currently we do not support more than 1 layer per display, output 1 layer id for now. | ||
| 47 | // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse | ||
| 48 | // side effects. | ||
| 49 | // TODO: Support multiple layers | ||
| 50 | const auto display_id = m_nvnflinger->OpenDisplay("Default"); | ||
| 51 | const auto layer_id = m_nvnflinger->CreateLayer(*display_id); | ||
| 52 | |||
| 53 | m_managed_display_layers.emplace(*layer_id); | ||
| 54 | |||
| 55 | *out_layer = *layer_id; | ||
| 56 | *out_recording_layer = 0; | ||
| 57 | } | ||
| 58 | |||
| 59 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/managed_layer_holder.h b/src/core/hle/service/am/managed_layer_holder.h new file mode 100644 index 000000000..f7fe03f24 --- /dev/null +++ b/src/core/hle/service/am/managed_layer_holder.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <set> | ||
| 7 | |||
| 8 | #include "common/common_funcs.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | namespace Service::Nvnflinger { | ||
| 12 | class Nvnflinger; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::AM { | ||
| 16 | |||
| 17 | class ManagedLayerHolder { | ||
| 18 | public: | ||
| 19 | ManagedLayerHolder(); | ||
| 20 | ~ManagedLayerHolder(); | ||
| 21 | |||
| 22 | void Initialize(Nvnflinger::Nvnflinger* nvnflinger); | ||
| 23 | void CreateManagedDisplayLayer(u64* out_layer); | ||
| 24 | void CreateManagedDisplaySeparableLayer(u64* out_layer, u64* out_recording_layer); | ||
| 25 | |||
| 26 | private: | ||
| 27 | Nvnflinger::Nvnflinger* m_nvnflinger{}; | ||
| 28 | std::set<u64> m_managed_display_layers{}; | ||
| 29 | std::set<u64> m_managed_display_recording_layers{}; | ||
| 30 | }; | ||
| 31 | |||
| 32 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/process.cpp b/src/core/hle/service/am/process.cpp new file mode 100644 index 000000000..16b685f86 --- /dev/null +++ b/src/core/hle/service/am/process.cpp | |||
| @@ -0,0 +1,138 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/scope_exit.h" | ||
| 5 | |||
| 6 | #include "core/file_sys/nca_metadata.h" | ||
| 7 | #include "core/file_sys/registered_cache.h" | ||
| 8 | #include "core/hle/kernel/k_process.h" | ||
| 9 | #include "core/hle/service/am/process.h" | ||
| 10 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 11 | #include "core/loader/loader.h" | ||
| 12 | |||
| 13 | namespace Service::AM { | ||
| 14 | |||
| 15 | Process::Process(Core::System& system) | ||
| 16 | : m_system(system), m_process(), m_main_thread_priority(), m_main_thread_stack_size(), | ||
| 17 | m_program_id(), m_process_started() {} | ||
| 18 | |||
| 19 | Process::~Process() { | ||
| 20 | this->Finalize(); | ||
| 21 | } | ||
| 22 | |||
| 23 | bool Process::Initialize(u64 program_id) { | ||
| 24 | // First, ensure we are not holding another process. | ||
| 25 | this->Finalize(); | ||
| 26 | |||
| 27 | // Get the filesystem controller. | ||
| 28 | auto& fsc = m_system.GetFileSystemController(); | ||
| 29 | |||
| 30 | // Attempt to load program NCA. | ||
| 31 | const FileSys::RegisteredCache* bis_system{}; | ||
| 32 | FileSys::VirtualFile nca{}; | ||
| 33 | |||
| 34 | // Get the program NCA from built-in storage. | ||
| 35 | bis_system = fsc.GetSystemNANDContents(); | ||
| 36 | if (bis_system) { | ||
| 37 | nca = bis_system->GetEntryRaw(program_id, FileSys::ContentRecordType::Program); | ||
| 38 | } | ||
| 39 | |||
| 40 | // Ensure we retrieved a program NCA. | ||
| 41 | if (!nca) { | ||
| 42 | return false; | ||
| 43 | } | ||
| 44 | |||
| 45 | // Get the appropriate loader to parse this NCA. | ||
| 46 | auto app_loader = Loader::GetLoader(m_system, nca, program_id, 0); | ||
| 47 | |||
| 48 | // Ensure we have a loader which can parse the NCA. | ||
| 49 | if (!app_loader) { | ||
| 50 | return false; | ||
| 51 | } | ||
| 52 | |||
| 53 | // Create the process. | ||
| 54 | auto* const process = Kernel::KProcess::Create(m_system.Kernel()); | ||
| 55 | Kernel::KProcess::Register(m_system.Kernel(), process); | ||
| 56 | |||
| 57 | // On exit, ensure we free the additional reference to the process. | ||
| 58 | SCOPE_EXIT({ process->Close(); }); | ||
| 59 | |||
| 60 | // Insert process modules into memory. | ||
| 61 | const auto [load_result, load_parameters] = app_loader->Load(*process, m_system); | ||
| 62 | |||
| 63 | // Ensure loading was successful. | ||
| 64 | if (load_result != Loader::ResultStatus::Success) { | ||
| 65 | return false; | ||
| 66 | } | ||
| 67 | |||
| 68 | // TODO: remove this, kernel already tracks this | ||
| 69 | m_system.Kernel().AppendNewProcess(process); | ||
| 70 | |||
| 71 | // Note the load parameters from NPDM. | ||
| 72 | m_main_thread_priority = load_parameters->main_thread_priority; | ||
| 73 | m_main_thread_stack_size = load_parameters->main_thread_stack_size; | ||
| 74 | |||
| 75 | // This process has not started yet. | ||
| 76 | m_process_started = false; | ||
| 77 | |||
| 78 | // Take ownership of the process object. | ||
| 79 | m_process = process; | ||
| 80 | m_process->Open(); | ||
| 81 | |||
| 82 | // We succeeded. | ||
| 83 | return true; | ||
| 84 | } | ||
| 85 | |||
| 86 | void Process::Finalize() { | ||
| 87 | // Terminate, if we are currently holding a process. | ||
| 88 | this->Terminate(); | ||
| 89 | |||
| 90 | // Close the process. | ||
| 91 | if (m_process) { | ||
| 92 | m_process->Close(); | ||
| 93 | |||
| 94 | // TODO: remove this, kernel already tracks this | ||
| 95 | m_system.Kernel().RemoveProcess(m_process); | ||
| 96 | } | ||
| 97 | |||
| 98 | // Clean up. | ||
| 99 | m_process = nullptr; | ||
| 100 | m_main_thread_priority = 0; | ||
| 101 | m_main_thread_stack_size = 0; | ||
| 102 | m_program_id = 0; | ||
| 103 | m_process_started = false; | ||
| 104 | } | ||
| 105 | |||
| 106 | bool Process::Run() { | ||
| 107 | // If we already started the process, don't start again. | ||
| 108 | if (m_process_started) { | ||
| 109 | return false; | ||
| 110 | } | ||
| 111 | |||
| 112 | // Start. | ||
| 113 | if (m_process) { | ||
| 114 | m_process->Run(m_main_thread_priority, m_main_thread_stack_size); | ||
| 115 | } | ||
| 116 | |||
| 117 | // Mark as started. | ||
| 118 | m_process_started = true; | ||
| 119 | |||
| 120 | // We succeeded. | ||
| 121 | return true; | ||
| 122 | } | ||
| 123 | |||
| 124 | void Process::Terminate() { | ||
| 125 | if (m_process) { | ||
| 126 | m_process->Terminate(); | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | u64 Process::GetProcessId() const { | ||
| 131 | if (m_process) { | ||
| 132 | return m_process->GetProcessId(); | ||
| 133 | } | ||
| 134 | |||
| 135 | return 0; | ||
| 136 | } | ||
| 137 | |||
| 138 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/process.h b/src/core/hle/service/am/process.h new file mode 100644 index 000000000..4b908ade4 --- /dev/null +++ b/src/core/hle/service/am/process.h | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_funcs.h" | ||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | class KProcess; | ||
| 11 | } | ||
| 12 | |||
| 13 | namespace Core { | ||
| 14 | class System; | ||
| 15 | } | ||
| 16 | |||
| 17 | namespace Service::AM { | ||
| 18 | |||
| 19 | class Process { | ||
| 20 | public: | ||
| 21 | explicit Process(Core::System& system); | ||
| 22 | ~Process(); | ||
| 23 | |||
| 24 | bool Initialize(u64 program_id); | ||
| 25 | void Finalize(); | ||
| 26 | |||
| 27 | bool Run(); | ||
| 28 | void Terminate(); | ||
| 29 | |||
| 30 | bool IsInitialized() const { | ||
| 31 | return m_process != nullptr; | ||
| 32 | } | ||
| 33 | u64 GetProcessId() const; | ||
| 34 | u64 GetProgramId() const { | ||
| 35 | return m_program_id; | ||
| 36 | } | ||
| 37 | Kernel::KProcess* GetProcess() const { | ||
| 38 | return m_process; | ||
| 39 | } | ||
| 40 | |||
| 41 | private: | ||
| 42 | Core::System& m_system; | ||
| 43 | Kernel::KProcess* m_process{}; | ||
| 44 | s32 m_main_thread_priority{}; | ||
| 45 | u64 m_main_thread_stack_size{}; | ||
| 46 | u64 m_program_id{}; | ||
| 47 | bool m_process_started{}; | ||
| 48 | }; | ||
| 49 | |||
| 50 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/system_buffer_manager.cpp b/src/core/hle/service/am/system_buffer_manager.cpp new file mode 100644 index 000000000..7211ef488 --- /dev/null +++ b/src/core/hle/service/am/system_buffer_manager.cpp | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/am/system_buffer_manager.h" | ||
| 5 | #include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" | ||
| 6 | #include "core/hle/service/nvnflinger/nvnflinger.h" | ||
| 7 | |||
| 8 | namespace Service::AM { | ||
| 9 | |||
| 10 | SystemBufferManager::SystemBufferManager() = default; | ||
| 11 | |||
| 12 | SystemBufferManager::~SystemBufferManager() { | ||
| 13 | if (!m_nvnflinger) { | ||
| 14 | return; | ||
| 15 | } | ||
| 16 | |||
| 17 | // Clean up shared layers. | ||
| 18 | if (m_buffer_sharing_enabled) { | ||
| 19 | } | ||
| 20 | } | ||
| 21 | |||
| 22 | bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process, | ||
| 23 | AppletId applet_id) { | ||
| 24 | if (m_nvnflinger) { | ||
| 25 | return m_buffer_sharing_enabled; | ||
| 26 | } | ||
| 27 | |||
| 28 | m_process = process; | ||
| 29 | m_nvnflinger = nvnflinger; | ||
| 30 | m_buffer_sharing_enabled = false; | ||
| 31 | m_system_shared_buffer_id = 0; | ||
| 32 | m_system_shared_layer_id = 0; | ||
| 33 | |||
| 34 | if (applet_id <= AppletId::Application) { | ||
| 35 | return false; | ||
| 36 | } | ||
| 37 | |||
| 38 | const auto display_id = m_nvnflinger->OpenDisplay("Default").value(); | ||
| 39 | const auto res = m_nvnflinger->GetSystemBufferManager().Initialize( | ||
| 40 | &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id); | ||
| 41 | |||
| 42 | if (res.IsSuccess()) { | ||
| 43 | m_buffer_sharing_enabled = true; | ||
| 44 | } | ||
| 45 | |||
| 46 | return m_buffer_sharing_enabled; | ||
| 47 | } | ||
| 48 | |||
| 49 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/system_buffer_manager.h b/src/core/hle/service/am/system_buffer_manager.h new file mode 100644 index 000000000..c60d73416 --- /dev/null +++ b/src/core/hle/service/am/system_buffer_manager.h | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <set> | ||
| 7 | |||
| 8 | #include "common/common_funcs.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | #include "core/hle/service/am/am_types.h" | ||
| 12 | |||
| 13 | namespace Kernel { | ||
| 14 | class KProcess; | ||
| 15 | } | ||
| 16 | |||
| 17 | namespace Service::Nvnflinger { | ||
| 18 | class Nvnflinger; | ||
| 19 | } | ||
| 20 | |||
| 21 | namespace Service::AM { | ||
| 22 | |||
| 23 | class SystemBufferManager { | ||
| 24 | public: | ||
| 25 | SystemBufferManager(); | ||
| 26 | ~SystemBufferManager(); | ||
| 27 | |||
| 28 | bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id); | ||
| 29 | |||
| 30 | void GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id, | ||
| 31 | u64* out_system_shared_layer_id) { | ||
| 32 | *out_system_shared_buffer_id = m_system_shared_buffer_id; | ||
| 33 | *out_system_shared_layer_id = m_system_shared_layer_id; | ||
| 34 | } | ||
| 35 | |||
| 36 | private: | ||
| 37 | Kernel::KProcess* m_process{}; | ||
| 38 | Nvnflinger::Nvnflinger* m_nvnflinger{}; | ||
| 39 | bool m_buffer_sharing_enabled{}; | ||
| 40 | u64 m_system_shared_buffer_id{}; | ||
| 41 | u64 m_system_shared_layer_id{}; | ||
| 42 | }; | ||
| 43 | |||
| 44 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/event.cpp b/src/core/hle/service/event.cpp new file mode 100644 index 000000000..375660d72 --- /dev/null +++ b/src/core/hle/service/event.cpp | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/kernel/k_event.h" | ||
| 5 | #include "core/hle/service/event.h" | ||
| 6 | #include "core/hle/service/kernel_helpers.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | |||
| 10 | Event::Event(KernelHelpers::ServiceContext& ctx) { | ||
| 11 | m_event = ctx.CreateEvent("Event"); | ||
| 12 | } | ||
| 13 | |||
| 14 | Event::~Event() { | ||
| 15 | m_event->GetReadableEvent().Close(); | ||
| 16 | m_event->Close(); | ||
| 17 | } | ||
| 18 | |||
| 19 | void Event::Signal() { | ||
| 20 | m_event->Signal(); | ||
| 21 | } | ||
| 22 | |||
| 23 | void Event::Clear() { | ||
| 24 | m_event->Clear(); | ||
| 25 | } | ||
| 26 | |||
| 27 | Kernel::KReadableEvent* Event::GetHandle() { | ||
| 28 | return &m_event->GetReadableEvent(); | ||
| 29 | } | ||
| 30 | |||
| 31 | } // namespace Service | ||
diff --git a/src/core/hle/service/event.h b/src/core/hle/service/event.h new file mode 100644 index 000000000..cdbc4635a --- /dev/null +++ b/src/core/hle/service/event.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | namespace Kernel { | ||
| 7 | class KEvent; | ||
| 8 | class KReadableEvent; | ||
| 9 | } // namespace Kernel | ||
| 10 | |||
| 11 | namespace Service { | ||
| 12 | |||
| 13 | namespace KernelHelpers { | ||
| 14 | class ServiceContext; | ||
| 15 | } | ||
| 16 | |||
| 17 | class Event { | ||
| 18 | public: | ||
| 19 | explicit Event(KernelHelpers::ServiceContext& ctx); | ||
| 20 | ~Event(); | ||
| 21 | |||
| 22 | void Signal(); | ||
| 23 | void Clear(); | ||
| 24 | |||
| 25 | Kernel::KReadableEvent* GetHandle(); | ||
| 26 | |||
| 27 | private: | ||
| 28 | Kernel::KEvent* m_event; | ||
| 29 | }; | ||
| 30 | |||
| 31 | } // namespace Service | ||
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp index 86e272b41..e71652cdf 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp | |||
| @@ -128,7 +128,7 @@ Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, Nvidia::D | |||
| 128 | 128 | ||
| 129 | // Ensure we maintain a clean state on failure. | 129 | // Ensure we maintain a clean state on failure. |
| 130 | ON_RESULT_FAILURE { | 130 | ON_RESULT_FAILURE { |
| 131 | ASSERT(R_SUCCEEDED(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd))); | 131 | R_ASSERT(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd)); |
| 132 | }; | 132 | }; |
| 133 | 133 | ||
| 134 | // Assign the allocated memory to the handle. | 134 | // Assign the allocated memory to the handle. |