diff options
Diffstat (limited to 'src/core')
162 files changed, 8053 insertions, 5187 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ea6b2c285..eb8f643a2 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -176,8 +176,8 @@ add_library(core STATIC frontend/applets/controller.h frontend/applets/error.cpp frontend/applets/error.h - frontend/applets/general_frontend.cpp - frontend/applets/general_frontend.h + frontend/applets/general.cpp + frontend/applets/general.h frontend/applets/mii_edit.cpp frontend/applets/mii_edit.h frontend/applets/profile_select.cpp @@ -390,39 +390,101 @@ add_library(core STATIC hle/service/acc/errors.h hle/service/acc/profile_manager.cpp hle/service/acc/profile_manager.h + hle/service/am/frontend/applet_cabinet.cpp + hle/service/am/frontend/applet_cabinet.h + hle/service/am/frontend/applet_controller.cpp + hle/service/am/frontend/applet_controller.h + hle/service/am/frontend/applet_error.cpp + hle/service/am/frontend/applet_error.h + hle/service/am/frontend/applet_general.cpp + hle/service/am/frontend/applet_general.h + hle/service/am/frontend/applet_mii_edit.cpp + hle/service/am/frontend/applet_mii_edit.h + hle/service/am/frontend/applet_mii_edit_types.h + hle/service/am/frontend/applet_profile_select.cpp + hle/service/am/frontend/applet_profile_select.h + hle/service/am/frontend/applet_software_keyboard.cpp + hle/service/am/frontend/applet_software_keyboard.h + hle/service/am/frontend/applet_software_keyboard_types.h + hle/service/am/frontend/applet_web_browser.cpp + hle/service/am/frontend/applet_web_browser.h + hle/service/am/frontend/applet_web_browser_types.h + hle/service/am/frontend/applets.cpp + hle/service/am/frontend/applets.h hle/service/am/am.cpp hle/service/am/am.h + hle/service/am/am_results.h + hle/service/am/am_types.h + hle/service/am/applet.cpp + hle/service/am/applet.h hle/service/am/applet_ae.cpp hle/service/am/applet_ae.h + hle/service/am/applet_manager.cpp + hle/service/am/applet_data_broker.cpp + hle/service/am/applet_data_broker.h + hle/service/am/applet_manager.h hle/service/am/applet_oe.cpp hle/service/am/applet_oe.h - hle/service/am/applets/applet_cabinet.cpp - hle/service/am/applets/applet_cabinet.h - hle/service/am/applets/applet_controller.cpp - hle/service/am/applets/applet_controller.h - hle/service/am/applets/applet_error.cpp - hle/service/am/applets/applet_error.h - hle/service/am/applets/applet_general_backend.cpp - hle/service/am/applets/applet_general_backend.h - hle/service/am/applets/applet_mii_edit.cpp - hle/service/am/applets/applet_mii_edit.h - hle/service/am/applets/applet_mii_edit_types.h - hle/service/am/applets/applet_profile_select.cpp - hle/service/am/applets/applet_profile_select.h - hle/service/am/applets/applet_software_keyboard.cpp - hle/service/am/applets/applet_software_keyboard.h - hle/service/am/applets/applet_software_keyboard_types.h - hle/service/am/applets/applet_web_browser.cpp - hle/service/am/applets/applet_web_browser.h - 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/hid_registration.cpp + hle/service/am/hid_registration.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/library_applet_storage.cpp + hle/service/am/library_applet_storage.h + hle/service/am/lock_accessor.cpp + hle/service/am/lock_accessor.h + hle/service/am/managed_layer_holder.cpp + hle/service/am/managed_layer_holder.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/process.cpp + hle/service/am/process.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/system_buffer_manager.cpp + hle/service/am/system_buffer_manager.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 @@ -486,6 +548,8 @@ add_library(core STATIC hle/service/es/es.h hle/service/eupld/eupld.cpp hle/service/eupld/eupld.h + hle/service/event.cpp + hle/service/event.h hle/service/fatal/fatal.cpp hle/service/fatal/fatal.h hle/service/fatal/fatal_p.cpp @@ -711,6 +775,9 @@ add_library(core STATIC hle/service/nvnflinger/graphic_buffer_producer.h hle/service/nvnflinger/hos_binder_driver_server.cpp hle/service/nvnflinger/hos_binder_driver_server.h + hle/service/nvnflinger/hardware_composer.cpp + hle/service/nvnflinger/hardware_composer.h + hle/service/nvnflinger/hwc_layer.h hle/service/nvnflinger/nvnflinger.cpp hle/service/nvnflinger/nvnflinger.h hle/service/nvnflinger/parcel.h diff --git a/src/core/core.cpp b/src/core/core.cpp index 11bf8d2f6..435ef6793 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -36,7 +36,8 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" #include "core/hle/service/acc/profile_manager.h" -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/applet_manager.h" +#include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/apm/apm_controller.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/glue/glue_manager.h" @@ -135,8 +136,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, struct System::Impl { explicit Impl(System& system) - : kernel{system}, fs_controller{system}, hid_core{}, room_network{}, - cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{} {} + : kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system}, + reporter{system}, applet_manager{system}, frontend_applets{system}, profile_manager{} {} void Initialize(System& system) { device_memory = std::make_unique<Core::DeviceMemory>(); @@ -157,7 +158,7 @@ struct System::Impl { } // Create default implementations of applets if one is not provided. - applet_manager.SetDefaultAppletsIfMissing(); + frontend_applets.SetDefaultAppletsIfMissing(); is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue(); @@ -330,16 +331,27 @@ struct System::Impl { } SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window, - const std::string& filepath, u64 program_id, - std::size_t program_index) { + const std::string& filepath, + Service::AM::FrontendAppletParameters& params) { app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath), - program_id, program_index); + params.program_id, params.program_index); if (!app_loader) { LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); return SystemResultStatus::ErrorGetLoader; } + if (app_loader->ReadProgramId(params.program_id) != Loader::ResultStatus::Success) { + LOG_ERROR(Core, "Failed to find title id for ROM!"); + } + + std::string name = "Unknown program"; + if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) { + LOG_ERROR(Core, "Failed to read title for ROM!"); + } + + LOG_INFO(Core, "Loading {} ({})", name, params.program_id); + InitializeKernel(system); // Create the application process. @@ -373,9 +385,14 @@ struct System::Impl { cheat_engine->Initialize(); } + // Register with applet manager. + applet_manager.CreateAndInsertByFrontendAppletParameters(main_process->GetProcessId(), + params); + // All threads are started, begin main process execution, now that we're in the clear. main_process->Run(load_parameters->main_thread_priority, load_parameters->main_thread_stack_size); + main_process->Close(); if (Settings::values.gamecard_inserted) { if (Settings::values.gamecard_current_game) { @@ -386,21 +403,13 @@ struct System::Impl { } } - if (app_loader->ReadProgramId(program_id) != Loader::ResultStatus::Success) { - LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", load_result); - } - perf_stats = std::make_unique<PerfStats>(program_id); + perf_stats = std::make_unique<PerfStats>(params.program_id); // Reset counters and set time origin to current frame GetAndResetPerfStats(); perf_stats->BeginSystemFrame(); - std::string name = "Unknown Game"; - if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) { - LOG_ERROR(Core, "Failed to read title for ROM (Error {})", load_result); - } - std::string title_version; - const FileSys::PatchManager pm(program_id, system.GetFileSystemController(), + const FileSys::PatchManager pm(params.program_id, system.GetFileSystemController(), system.GetContentProvider()); const auto metadata = pm.GetControlMetadata(); if (metadata.first != nullptr) { @@ -409,14 +418,15 @@ struct System::Impl { if (auto room_member = room_network.GetRoomMember().lock()) { Network::GameInfo game_info; game_info.name = name; - game_info.id = program_id; + game_info.id = params.program_id; game_info.version = title_version; room_member->SendGameInfo(game_info); } // Workarounds: // Activate this in Super Smash Brothers Ultimate, it only affects AMD cards using AMDVLK - Settings::values.renderer_amdvlk_depth_bias_workaround = program_id == 0x1006A800016E000ULL; + Settings::values.renderer_amdvlk_depth_bias_workaround = + params.program_id == 0x1006A800016E000ULL; status = SystemResultStatus::Success; return status; @@ -455,6 +465,7 @@ struct System::Impl { } kernel.CloseServices(); kernel.ShutdownCores(); + applet_manager.Reset(); services.reset(); service_manager.reset(); fs_controller.Reset(); @@ -566,8 +577,9 @@ struct System::Impl { std::unique_ptr<Tools::RenderdocAPI> renderdoc_api; - /// Frontend applets - Service::AM::Applets::AppletManager applet_manager; + /// Applets + Service::AM::AppletManager applet_manager; + Service::AM::Frontend::FrontendAppletHolder frontend_applets; /// APM (Performance) services Service::APM::Controller apm_controller{core_timing}; @@ -680,8 +692,8 @@ void System::InitializeDebugger() { } SystemResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath, - u64 program_id, std::size_t program_index) { - return impl->Load(*this, emu_window, filepath, program_id, program_index); + Service::AM::FrontendAppletParameters& params) { + return impl->Load(*this, emu_window, filepath, params); } bool System::IsPoweredOn() const { @@ -871,19 +883,19 @@ void System::RegisterCheatList(const std::vector<Memory::CheatEntry>& list, impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size); } -void System::SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set) { - impl->applet_manager.SetAppletFrontendSet(std::move(set)); +void System::SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set) { + impl->frontend_applets.SetFrontendAppletSet(std::move(set)); } -void System::SetDefaultAppletFrontendSet() { - impl->applet_manager.SetDefaultAppletFrontendSet(); +Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() { + return impl->frontend_applets; } -Service::AM::Applets::AppletManager& System::GetAppletManager() { - return impl->applet_manager; +const Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() const { + return impl->frontend_applets; } -const Service::AM::Applets::AppletManager& System::GetAppletManager() const { +Service::AM::AppletManager& System::GetAppletManager() { return impl->applet_manager; } diff --git a/src/core/core.h b/src/core/core.h index d8862e9ce..90826bd3a 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -50,10 +50,15 @@ namespace Account { class ProfileManager; } // namespace Account -namespace AM::Applets { -struct AppletFrontendSet; +namespace AM { +struct FrontendAppletParameters; class AppletManager; -} // namespace AM::Applets +} // namespace AM + +namespace AM::Frontend { +struct FrontendAppletSet; +class FrontendAppletHolder; +} // namespace AM::Frontend namespace APM { class Controller; @@ -203,8 +208,8 @@ public: * @returns SystemResultStatus code, indicating if the operation succeeded. */ [[nodiscard]] SystemResultStatus Load(Frontend::EmuWindow& emu_window, - const std::string& filepath, u64 program_id = 0, - std::size_t program_index = 0); + const std::string& filepath, + Service::AM::FrontendAppletParameters& params); /** * Indicates if the emulated system is powered on (all subsystems initialized and able to run an @@ -344,11 +349,13 @@ public: const std::array<u8, 0x20>& build_id, u64 main_region_begin, u64 main_region_size); - void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set); - void SetDefaultAppletFrontendSet(); + void SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set); + + [[nodiscard]] Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder(); + [[nodiscard]] const Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder() + const; - [[nodiscard]] Service::AM::Applets::AppletManager& GetAppletManager(); - [[nodiscard]] const Service::AM::Applets::AppletManager& GetAppletManager() const; + [[nodiscard]] Service::AM::AppletManager& GetAppletManager(); void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider); diff --git a/src/core/device_memory_manager.h b/src/core/device_memory_manager.h index ffeed46cc..0568a821b 100644 --- a/src/core/device_memory_manager.h +++ b/src/core/device_memory_manager.h @@ -5,11 +5,13 @@ #include <array> #include <atomic> +#include <bit> #include <deque> #include <memory> #include <mutex> #include "common/common_types.h" +#include "common/range_mutex.h" #include "common/scratch_buffer.h" #include "common/virtual_buffer.h" @@ -180,31 +182,35 @@ private: } Common::VirtualBuffer<VAddr> cpu_backing_address; - static constexpr size_t subentries = 8 / sizeof(u8); + using CounterType = u8; + using CounterAtomicType = std::atomic_uint8_t; + static constexpr size_t subentries = 8 / sizeof(CounterType); static constexpr size_t subentries_mask = subentries - 1; + static constexpr size_t subentries_shift = + std::countr_zero(sizeof(u64)) - std::countr_zero(sizeof(CounterType)); class CounterEntry final { public: CounterEntry() = default; - std::atomic_uint8_t& Count(std::size_t page) { + CounterAtomicType& Count(std::size_t page) { return values[page & subentries_mask]; } - const std::atomic_uint8_t& Count(std::size_t page) const { + const CounterAtomicType& Count(std::size_t page) const { return values[page & subentries_mask]; } private: - std::array<std::atomic_uint8_t, subentries> values{}; + std::array<CounterAtomicType, subentries> values{}; }; - static_assert(sizeof(CounterEntry) == subentries * sizeof(u8), + static_assert(sizeof(CounterEntry) == subentries * sizeof(CounterType), "CounterEntry should be 8 bytes!"); static constexpr size_t num_counter_entries = (1ULL << (device_virtual_bits - page_bits)) / subentries; using CachedPages = std::array<CounterEntry, num_counter_entries>; std::unique_ptr<CachedPages> cached_pages; - std::mutex counter_guard; + Common::RangeMutex counter_guard; std::mutex mapping_guard; }; diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index eab8a2731..b026f4220 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -213,8 +213,8 @@ void DeviceMemoryManager<Traits>::Free(DAddr start, size_t size) { } template <typename Traits> -void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size_t size, - Asid asid, bool track) { +void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size_t size, Asid asid, + bool track) { Core::Memory::Memory* process_memory = registered_processes[asid.id]; size_t start_page_d = address >> Memory::YUZU_PAGEBITS; size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; @@ -508,12 +508,7 @@ void DeviceMemoryManager<Traits>::UnregisterProcess(Asid asid) { template <typename Traits> void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) { - std::unique_lock<std::mutex> lk(counter_guard, std::defer_lock); - const auto Lock = [&] { - if (!lk) { - lk.lock(); - } - }; + Common::ScopedRangeLock lk(counter_guard, addr, size); u64 uncache_begin = 0; u64 cache_begin = 0; u64 uncache_bytes = 0; @@ -524,22 +519,36 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE); size_t page = addr >> Memory::YUZU_PAGEBITS; auto [asid, base_vaddress] = ExtractCPUBacking(page); - size_t vpage = base_vaddress >> Memory::YUZU_PAGEBITS; auto* memory_device_inter = registered_processes[asid.id]; + const auto release_pending = [&] { + if (uncache_bytes > 0) { + MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, + uncache_bytes, false); + uncache_bytes = 0; + } + if (cache_bytes > 0) { + MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, + cache_bytes, true); + cache_bytes = 0; + } + }; for (; page != page_end; ++page) { - std::atomic_uint8_t& count = cached_pages->at(page >> 3).Count(page); + CounterAtomicType& count = cached_pages->at(page >> subentries_shift).Count(page); + auto [asid_2, vpage] = ExtractCPUBacking(page); + vpage >>= Memory::YUZU_PAGEBITS; - if (delta > 0) { - ASSERT_MSG(count.load(std::memory_order::relaxed) < std::numeric_limits<u8>::max(), - "Count may overflow!"); - } else if (delta < 0) { - ASSERT_MSG(count.load(std::memory_order::relaxed) > 0, "Count may underflow!"); - } else { - ASSERT_MSG(false, "Delta must be non-zero!"); + if (vpage == 0) [[unlikely]] { + release_pending(); + continue; + } + + if (asid.id != asid_2.id) [[unlikely]] { + release_pending(); + memory_device_inter = registered_processes[asid_2.id]; } // Adds or subtracts 1, as count is a unsigned 8-bit value - count.fetch_add(static_cast<u8>(delta), std::memory_order_release); + count.fetch_add(static_cast<CounterType>(delta), std::memory_order_release); // Assume delta is either -1 or 1 if (count.load(std::memory_order::relaxed) == 0) { @@ -548,7 +557,6 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size } uncache_bytes += Memory::YUZU_PAGESIZE; } else if (uncache_bytes > 0) { - Lock(); MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, false); uncache_bytes = 0; @@ -559,23 +567,12 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size } cache_bytes += Memory::YUZU_PAGESIZE; } else if (cache_bytes > 0) { - Lock(); - MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, - true); + MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, + cache_bytes, true); cache_bytes = 0; } - vpage++; - } - if (uncache_bytes > 0) { - Lock(); - MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, - false); - } - if (cache_bytes > 0) { - Lock(); - MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, - true); } + release_pending(); } } // namespace Core diff --git a/src/core/frontend/applets/general_frontend.cpp b/src/core/frontend/applets/general.cpp index b4b213a31..4c299ee9c 100644 --- a/src/core/frontend/applets/general_frontend.cpp +++ b/src/core/frontend/applets/general.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/logging/log.h" -#include "core/frontend/applets/general_frontend.h" +#include "core/frontend/applets/general.h" namespace Core::Frontend { diff --git a/src/core/frontend/applets/general_frontend.h b/src/core/frontend/applets/general.h index 319838ac7..319838ac7 100644 --- a/src/core/frontend/applets/general_frontend.h +++ b/src/core/frontend/applets/general.h diff --git a/src/core/frontend/applets/profile_select.h b/src/core/frontend/applets/profile_select.h index 92e2737ea..880b69ad6 100644 --- a/src/core/frontend/applets/profile_select.h +++ b/src/core/frontend/applets/profile_select.h @@ -8,15 +8,15 @@ #include "common/uuid.h" #include "core/frontend/applets/applet.h" -#include "core/hle/service/am/applets/applet_profile_select.h" +#include "core/hle/service/am/frontend/applet_profile_select.h" namespace Core::Frontend { struct ProfileSelectParameters { - Service::AM::Applets::UiMode mode; + Service::AM::Frontend::UiMode mode; std::array<Common::UUID, 8> invalid_uid_list; - Service::AM::Applets::UiSettingsDisplayOptions display_options; - Service::AM::Applets::UserSelectionPurpose purpose; + Service::AM::Frontend::UiSettingsDisplayOptions display_options; + Service::AM::Frontend::UserSelectionPurpose purpose; }; class ProfileSelectApplet : public Applet { diff --git a/src/core/frontend/applets/software_keyboard.cpp b/src/core/frontend/applets/software_keyboard.cpp index 7655d215b..d00da8ac9 100644 --- a/src/core/frontend/applets/software_keyboard.cpp +++ b/src/core/frontend/applets/software_keyboard.cpp @@ -69,7 +69,7 @@ void DefaultSoftwareKeyboardApplet::ShowNormalKeyboard() const { } void DefaultSoftwareKeyboardApplet::ShowTextCheckDialog( - Service::AM::Applets::SwkbdTextCheckResult text_check_result, + Service::AM::Frontend::SwkbdTextCheckResult text_check_result, std::u16string text_check_message) const { LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to show the text check dialog."); } @@ -118,7 +118,7 @@ void DefaultSoftwareKeyboardApplet::InlineTextChanged(InlineTextParameters text_ "\ncursor_position={}", Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position); - submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, + submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, text_parameters.input_text, text_parameters.cursor_position); } @@ -127,22 +127,22 @@ void DefaultSoftwareKeyboardApplet::ExitKeyboard() const { } void DefaultSoftwareKeyboardApplet::SubmitNormalText(std::u16string text) const { - submit_normal_callback(Service::AM::Applets::SwkbdResult::Ok, text, true); + submit_normal_callback(Service::AM::Frontend::SwkbdResult::Ok, text, true); } void DefaultSoftwareKeyboardApplet::SubmitInlineText(std::u16string_view text) const { std::this_thread::sleep_for(std::chrono::milliseconds(500)); for (std::size_t index = 0; index < text.size(); ++index) { - submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, + submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, std::u16string(text.data(), text.data() + index + 1), static_cast<s32>(index) + 1); std::this_thread::sleep_for(std::chrono::milliseconds(250)); } - submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, std::u16string(text), - static_cast<s32>(text.size())); + submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::DecidedEnter, + std::u16string(text), static_cast<s32>(text.size())); } } // namespace Core::Frontend diff --git a/src/core/frontend/applets/software_keyboard.h b/src/core/frontend/applets/software_keyboard.h index 8ed96da24..a32a98e4c 100644 --- a/src/core/frontend/applets/software_keyboard.h +++ b/src/core/frontend/applets/software_keyboard.h @@ -8,7 +8,7 @@ #include "common/common_types.h" #include "core/frontend/applets/applet.h" -#include "core/hle/service/am/applets/applet_software_keyboard_types.h" +#include "core/hle/service/am/frontend/applet_software_keyboard_types.h" namespace Core::Frontend { @@ -23,10 +23,10 @@ struct KeyboardInitializeParameters { u32 max_text_length; u32 min_text_length; s32 initial_cursor_position; - Service::AM::Applets::SwkbdType type; - Service::AM::Applets::SwkbdPasswordMode password_mode; - Service::AM::Applets::SwkbdTextDrawType text_draw_type; - Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags; + Service::AM::Frontend::SwkbdType type; + Service::AM::Frontend::SwkbdPasswordMode password_mode; + Service::AM::Frontend::SwkbdTextDrawType text_draw_type; + Service::AM::Frontend::SwkbdKeyDisableFlags key_disable_flags; bool use_blur_background; bool enable_backspace_button; bool enable_return_button; @@ -40,8 +40,8 @@ struct InlineAppearParameters { f32 key_top_scale_y; f32 key_top_translate_x; f32 key_top_translate_y; - Service::AM::Applets::SwkbdType type; - Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags; + Service::AM::Frontend::SwkbdType type; + Service::AM::Frontend::SwkbdKeyDisableFlags key_disable_flags; bool key_top_as_floating; bool enable_backspace_button; bool enable_return_button; @@ -56,9 +56,9 @@ struct InlineTextParameters { class SoftwareKeyboardApplet : public Applet { public: using SubmitInlineCallback = - std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>; + std::function<void(Service::AM::Frontend::SwkbdReplyType, std::u16string, s32)>; using SubmitNormalCallback = - std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>; + std::function<void(Service::AM::Frontend::SwkbdResult, std::u16string, bool)>; virtual ~SoftwareKeyboardApplet(); @@ -69,7 +69,7 @@ public: virtual void ShowNormalKeyboard() const = 0; - virtual void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, + virtual void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result, std::u16string text_check_message) const = 0; virtual void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const = 0; @@ -93,7 +93,7 @@ public: void ShowNormalKeyboard() const override; - void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, + void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result, std::u16string text_check_message) const override; void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const override; diff --git a/src/core/frontend/applets/web_browser.cpp b/src/core/frontend/applets/web_browser.cpp index 6e703ef06..eca8d6d98 100644 --- a/src/core/frontend/applets/web_browser.cpp +++ b/src/core/frontend/applets/web_browser.cpp @@ -18,7 +18,7 @@ void DefaultWebBrowserApplet::OpenLocalWebPage(const std::string& local_url, LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open local web page at {}", local_url); - callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/"); + callback(Service::AM::Frontend::WebExitReason::WindowClosed, "http://localhost/"); } void DefaultWebBrowserApplet::OpenExternalWebPage(const std::string& external_url, @@ -26,7 +26,7 @@ void DefaultWebBrowserApplet::OpenExternalWebPage(const std::string& external_ur LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open external web page at {}", external_url); - callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/"); + callback(Service::AM::Frontend::WebExitReason::WindowClosed, "http://localhost/"); } } // namespace Core::Frontend diff --git a/src/core/frontend/applets/web_browser.h b/src/core/frontend/applets/web_browser.h index 178bbdd3f..b70856a22 100644 --- a/src/core/frontend/applets/web_browser.h +++ b/src/core/frontend/applets/web_browser.h @@ -6,7 +6,7 @@ #include <functional> #include "core/frontend/applets/applet.h" -#include "core/hle/service/am/applets/applet_web_browser_types.h" +#include "core/hle/service/am/frontend/applet_web_browser_types.h" namespace Core::Frontend { @@ -14,7 +14,7 @@ class WebBrowserApplet : public Applet { public: using ExtractROMFSCallback = std::function<void()>; using OpenWebPageCallback = - std::function<void(Service::AM::Applets::WebExitReason, std::string)>; + std::function<void(Service::AM::Frontend::WebExitReason, std::string)>; virtual ~WebBrowserApplet(); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index f3683cdcc..34b25be66 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -97,8 +97,14 @@ struct KernelCore::Impl { RegisterHostThread(nullptr); } - void TerminateApplicationProcess() { - application_process.load()->Terminate(); + void TerminateAllProcesses() { + std::scoped_lock lk{process_list_lock}; + for (auto& process : process_list) { + process->Terminate(); + process->Close(); + process = nullptr; + } + process_list.clear(); } void Shutdown() { @@ -107,18 +113,9 @@ struct KernelCore::Impl { CloseServices(); - auto* old_process = application_process.exchange(nullptr); - if (old_process) { - old_process->Close(); - } - - { - std::scoped_lock lk{process_list_lock}; - for (auto* const process : process_list) { - process->Terminate(); - process->Close(); - } - process_list.clear(); + if (application_process) { + application_process->Close(); + application_process = nullptr; } next_object_id = 0; @@ -354,6 +351,7 @@ struct KernelCore::Impl { void MakeApplicationProcess(KProcess* process) { application_process = process; + application_process->Open(); } static inline thread_local u8 host_thread_id = UINT8_MAX; @@ -779,7 +777,7 @@ struct KernelCore::Impl { // Lists all processes that exist in the current session. std::mutex process_list_lock; std::vector<KProcess*> process_list; - std::atomic<KProcess*> application_process{}; + KProcess* application_process{}; std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; std::unique_ptr<Kernel::KHardwareTimer> hardware_timer; @@ -1243,7 +1241,7 @@ void KernelCore::SuspendApplication(bool suspended) { } void KernelCore::ShutdownCores() { - impl->TerminateApplicationProcess(); + impl->TerminateAllProcesses(); KScopedSchedulerLock lk{*this}; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 38f67adcd..8f90eba34 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -1,2704 +1,27 @@ // 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_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); - server_manager->RegisterNamedService( - "appletAE", std::make_shared<AppletAE>(nvnflinger, message_queue, system)); - server_manager->RegisterNamedService( - "appletOE", std::make_shared<AppletOE>(nvnflinger, message_queue, system)); + server_manager->RegisterNamedService("appletAE", + std::make_shared<AppletAE>(nvnflinger, system)); + server_manager->RegisterNamedService("appletOE", + std::make_shared<AppletOE>(nvnflinger, system)); server_manager->RegisterNamedService("idle:sys", std::make_shared<IdleSys>(system)); server_manager->RegisterNamedService("omm", std::make_shared<OMM>(system)); server_manager->RegisterNamedService("spsm", std::make_shared<SPSM>(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..a2afc9eec --- /dev/null +++ b/src/core/hle/service/am/am_results.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/result.h" + +namespace Service::AM { + +constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2}; +constexpr Result ResultNoMessages{ErrorModule::AM, 3}; +constexpr Result ResultInvalidOffset{ErrorModule::AM, 503}; +constexpr Result ResultInvalidStorageType{ErrorModule::AM, 511}; +constexpr Result ResultFatalSectionCountImbalance{ErrorModule::AM, 512}; + +} // namespace Service::AM 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..a2b852b12 --- /dev/null +++ b/src/core/hle/service/am/am_types.h @@ -0,0 +1,178 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_funcs.h" +#include "common/common_types.h" + +namespace Service::AM { + +namespace Frontend { +class FrontendApplet; +} + +enum class AppletType { + Application, + LibraryApplet, + SystemApplet, +}; + +enum class GameplayRecordingState : u32 { + Disabled, + Enabled, +}; + +// 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, +}; + +struct AppletProcessLaunchReason { + u8 flag; + INSERT_PADDING_BYTES(3); +}; +static_assert(sizeof(AppletProcessLaunchReason) == 0x4, + "AppletProcessLaunchReason is an invalid size"); + +enum class ScreenshotPermission : u32 { + Inherit = 0, + Enable = 1, + Disable = 2, +}; + +struct FocusHandlingMode { + bool unknown0; + bool unknown1; + bool unknown2; + bool unknown3; +}; + +enum class IdleTimeDetectionExtension : u32 { + Disabled = 0, + Extended = 1, + ExtendedUnsafe = 2, +}; + +enum class AppletId : u32 { + None = 0x00, + Application = 0x01, + OverlayDisplay = 0x02, + QLaunch = 0x03, + Starter = 0x04, + Auth = 0x0A, + Cabinet = 0x0B, + Controller = 0x0C, + DataErase = 0x0D, + Error = 0x0E, + NetConnect = 0x0F, + ProfileSelect = 0x10, + SoftwareKeyboard = 0x11, + MiiEdit = 0x12, + Web = 0x13, + Shop = 0x14, + PhotoViewer = 0x15, + Settings = 0x16, + OfflineWeb = 0x17, + LoginShare = 0x18, + WebAuth = 0x19, + MyPage = 0x1A, +}; + +enum class AppletProgramId : u64 { + QLaunch = 0x0100000000001000ull, + Auth = 0x0100000000001001ull, + Cabinet = 0x0100000000001002ull, + Controller = 0x0100000000001003ull, + DataErase = 0x0100000000001004ull, + Error = 0x0100000000001005ull, + NetConnect = 0x0100000000001006ull, + ProfileSelect = 0x0100000000001007ull, + SoftwareKeyboard = 0x0100000000001008ull, + MiiEdit = 0x0100000000001009ull, + Web = 0x010000000000100Aull, + Shop = 0x010000000000100Bull, + OverlayDisplay = 0x010000000000100Cull, + PhotoViewer = 0x010000000000100Dull, + Settings = 0x010000000000100Eull, + OfflineWeb = 0x010000000000100Full, + LoginShare = 0x0100000000001010ull, + WebAuth = 0x0100000000001011ull, + Starter = 0x0100000000001012ull, + MyPage = 0x0100000000001013ull, + MaxProgramId = 0x0100000000001FFFull, +}; + +enum class LibraryAppletMode : u32 { + AllForeground = 0, + Background = 1, + NoUI = 2, + BackgroundIndirectDisplay = 3, + AllForegroundInitiallyHidden = 4, +}; + +enum class CommonArgumentVersion : u32 { + Version0, + Version1, + Version2, + Version3, +}; + +enum class CommonArgumentSize : u32 { + Version3 = 0x20, +}; + +enum class ThemeColor : u32 { + BasicWhite = 0, + BasicBlack = 3, +}; + +struct CommonArguments { + CommonArgumentVersion arguments_version; + CommonArgumentSize size; + u32 library_version; + ThemeColor theme_color; + bool play_startup_sound; + u64 system_tick; +}; +static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size."); + +struct AppletIdentityInfo { + AppletId applet_id; + INSERT_PADDING_BYTES(0x4); + u64 application_id; +}; +static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); + +using AppletResourceUserId = u64; +using ProgramId = u64; + +struct Applet; +class AppletDataBroker; + +} // 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..5b9056c12 --- /dev/null +++ b/src/core/hle/service/am/applet.cpp @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/scope_exit.h" + +#include "core/core.h" +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/applet.h" +#include "core/hle/service/am/applet_manager.h" + +namespace Service::AM { + +Applet::Applet(Core::System& system, std::unique_ptr<Process> process_) + : context(system, "Applet"), message_queue(system), process(std::move(process_)), + hid_registration(system, *process), gpu_error_detected_event(context), + friend_invitation_storage_channel_event(context), notification_storage_channel_event(context), + health_warning_disappeared_system_event(context), acquired_sleep_lock_event(context), + pop_from_general_channel_event(context), library_applet_launchable_event(context), + accumulated_suspended_tick_changed_event(context), sleep_lock_event(context) { + + aruid = process->GetProcessId(); + program_id = process->GetProgramId(); +} + +Applet::~Applet() = default; + +} // 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..bce6f9050 --- /dev/null +++ b/src/core/hle/service/am/applet.h @@ -0,0 +1,133 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <list> +#include <mutex> + +#include "common/math_util.h" +#include "core/hle/service/apm/apm_controller.h" +#include "core/hle/service/caps/caps_types.h" +#include "core/hle/service/event.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/service.h" + +#include "core/hle/service/am/am_types.h" +#include "core/hle/service/am/applet_message_queue.h" +#include "core/hle/service/am/hid_registration.h" +#include "core/hle/service/am/managed_layer_holder.h" +#include "core/hle/service/am/process.h" +#include "core/hle/service/am/storage.h" +#include "core/hle/service/am/system_buffer_manager.h" + +namespace Service::AM { + +struct Applet { + explicit Applet(Core::System& system, std::unique_ptr<Process> process_); + ~Applet(); + + // Lock + std::mutex lock{}; + + // Event creation helper + KernelHelpers::ServiceContext context; + + // Applet message queue + AppletMessageQueue message_queue; + + // Process + std::unique_ptr<Process> process; + + // Creation state + AppletId applet_id{}; + AppletResourceUserId aruid{}; + AppletProcessLaunchReason launch_reason{}; + AppletType type{}; + ProgramId program_id{}; + LibraryAppletMode library_applet_mode{}; + s32 previous_program_index{-1}; + ScreenshotPermission previous_screenshot_permission{ScreenshotPermission::Enable}; + + // TODO: some fields above can be AppletIdentityInfo + AppletIdentityInfo screen_shot_identity; + + // hid state + HidRegistration hid_registration; + + // vi state + SystemBufferManager system_buffer_manager{}; + ManagedLayerHolder managed_layer_holder{}; + + // Applet common functions + Result terminate_result{}; + s32 display_logical_width{}; + s32 display_logical_height{}; + Common::Rectangle<f32> display_magnification{0, 0, 1, 1}; + bool home_button_double_click_enabled{}; + bool home_button_short_pressed_blocked{}; + bool home_button_long_pressed_blocked{}; + bool vr_mode_curtain_required{}; + bool sleep_required_by_high_temperature{}; + bool sleep_required_by_low_battery{}; + s32 cpu_boost_request_priority{-1}; + bool handling_capture_button_short_pressed_message_enabled_for_applet{}; + bool handling_capture_button_long_pressed_message_enabled_for_applet{}; + u32 application_core_usage_mode{}; + + // Application functions + bool gameplay_recording_supported{}; + GameplayRecordingState gameplay_recording_state{GameplayRecordingState::Disabled}; + bool jit_service_launched{}; + bool is_running{}; + bool application_crash_report_enabled{}; + + // Common state + FocusState focus_state{}; + bool sleep_lock_enabled{}; + bool vr_mode_enabled{}; + bool lcd_backlight_off_enabled{}; + APM::CpuBoostMode boost_mode{}; + bool request_exit_to_library_applet_at_execute_next_program_enabled{}; + + // Channels + std::deque<std::vector<u8>> user_channel_launch_parameter{}; + std::deque<std::vector<u8>> preselected_user_launch_parameter{}; + + // Caller applet + std::weak_ptr<Applet> caller_applet{}; + std::shared_ptr<AppletDataBroker> caller_applet_broker{}; + + // Self state + bool exit_locked{}; + s32 fatal_section_count{}; + bool operation_mode_changed_notification_enabled{true}; + bool performance_mode_changed_notification_enabled{true}; + FocusHandlingMode focus_handling_mode{}; + bool restart_message_enabled{}; + bool out_of_focus_suspension_enabled{true}; + Capture::AlbumImageOrientation album_image_orientation{}; + bool handles_request_to_display{}; + ScreenshotPermission screenshot_permission{}; + IdleTimeDetectionExtension idle_time_detection_extension{}; + bool auto_sleep_disabled{}; + u64 suspended_ticks{}; + bool album_image_taken_notification_enabled{}; + bool record_volume_muted{}; + + // Events + Event gpu_error_detected_event; + Event friend_invitation_storage_channel_event; + Event notification_storage_channel_event; + Event health_warning_disappeared_system_event; + Event acquired_sleep_lock_event; + Event pop_from_general_channel_event; + Event library_applet_launchable_event; + Event accumulated_suspended_tick_changed_event; + Event sleep_lock_event; + + // Frontend state + std::shared_ptr<Frontend::FrontendApplet> frontend{}; +}; + +} // 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..1b715dea6 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp @@ -1,311 +1,73 @@ // 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/applet_manager.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); - } +AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_) + : ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_} { + // clang-format off + static const FunctionInfo functions[] = { + {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, + {200, &AppletAE::OpenLibraryAppletProxyOld, "OpenLibraryAppletProxyOld"}, + {201, &AppletAE::OpenLibraryAppletProxy, "OpenLibraryAppletProxy"}, + {300, nullptr, "OpenOverlayAppletProxy"}, + {350, nullptr, "OpenSystemApplicationProxy"}, + {400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"}, + {410, nullptr, "GetSystemAppletControllerForDebug"}, + {1000, nullptr, "GetDebugFunctions"}, + }; + // clang-format on - void GetLibraryAppletCreator(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); + RegisterHandlers(functions); +} - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ILibraryAppletCreator>(system); - } +AppletAE::~AppletAE() = default; - void GetHomeMenuFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); +void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + if (const auto applet = GetAppletFromContext(ctx)) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface<IHomeMenuFunctions>(system); - } - - void GetGlobalStateController(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); + rb.PushIpcInterface<ISystemAppletProxy>(nvnflinger, applet, system); + } else { + UNIMPLEMENTED(); - 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); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); } +} - void GetAppletCommonFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); +void AppletAE::OpenLibraryAppletProxy(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + if (const auto applet = GetAppletFromContext(ctx)) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface<IAppletCommonFunctions>(system); - } - - void GetDebugFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); + rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, applet, system); + } else { + UNIMPLEMENTED(); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IDebugFunctions>(system); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); } - - Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr<AppletMessageQueue> msg_queue; -}; - -void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ISystemAppletProxy>(nvnflinger, msg_queue, system); -} - -void AppletAE::OpenLibraryAppletProxy(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, msg_queue, system); } void AppletAE::OpenLibraryAppletProxyOld(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, msg_queue, system); + return OpenLibraryAppletProxy(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_)} { - // clang-format off - static const FunctionInfo functions[] = { - {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, - {200, &AppletAE::OpenLibraryAppletProxyOld, "OpenLibraryAppletProxyOld"}, - {201, &AppletAE::OpenLibraryAppletProxy, "OpenLibraryAppletProxy"}, - {300, nullptr, "OpenOverlayAppletProxy"}, - {350, nullptr, "OpenSystemApplicationProxy"}, - {400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"}, - {410, nullptr, "GetSystemAppletControllerForDebug"}, - {1000, nullptr, "GetDebugFunctions"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -AppletAE::~AppletAE() = default; - -const std::shared_ptr<AppletMessageQueue>& AppletAE::GetMessageQueue() const { - return msg_queue; +std::shared_ptr<Applet> AppletAE::GetAppletFromContext(HLERequestContext& ctx) { + const auto aruid = ctx.GetPID(); + return system.GetAppletManager().GetByAppletResourceUserId(aruid); } } // namespace Service::AM diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h index 538ce2903..3d7961fa1 100644 --- a/src/core/hle/service/am/applet_ae.h +++ b/src/core/hle/service/am/applet_ae.h @@ -18,23 +18,21 @@ class Nvnflinger; namespace AM { -class AppletMessageQueue; +struct Applet; class AppletAE final : public ServiceFramework<AppletAE> { public: - explicit AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_); + explicit AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_); ~AppletAE() override; - const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const; - private: void OpenSystemAppletProxy(HLERequestContext& ctx); void OpenLibraryAppletProxy(HLERequestContext& ctx); void OpenLibraryAppletProxyOld(HLERequestContext& ctx); + std::shared_ptr<Applet> GetAppletFromContext(HLERequestContext& ctx); + Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr<AppletMessageQueue> msg_queue; }; } // namespace AM 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..130614ae5 --- /dev/null +++ b/src/core/hle/service/am/applet_common_functions.cpp @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applet.h" +#include "core/hle/service/am/applet_common_functions.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_, + std::shared_ptr<Applet> applet_) + : ServiceFramework{system_, "IAppletCommonFunctions"}, applet{std::move(applet_)} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "SetTerminateResult"}, + {10, nullptr, "ReadThemeStorage"}, + {11, nullptr, "WriteThemeStorage"}, + {20, nullptr, "PushToAppletBoundChannel"}, + {21, nullptr, "TryPopFromAppletBoundChannel"}, + {40, nullptr, "GetDisplayLogicalResolution"}, + {42, nullptr, "SetDisplayMagnification"}, + {50, nullptr, "SetHomeButtonDoubleClickEnabled"}, + {51, 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"}, + {300, &IAppletCommonFunctions::GetCurrentApplicationId, "GetCurrentApplicationId"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IAppletCommonFunctions::~IAppletCommonFunctions() = default; + +void IAppletCommonFunctions::SetCpuBoostRequestPriority(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::RequestParser rp{ctx}; + + std::scoped_lock lk{applet->lock}; + applet->cpu_boost_request_priority = rp.Pop<s32>(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IAppletCommonFunctions::GetCurrentApplicationId(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(system.GetApplicationProcessProgramID() & ~0xFFFULL); +} + +} // 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..b86adf5cb --- /dev/null +++ b/src/core/hle/service/am/applet_common_functions.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 { + +struct Applet; + +class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> { +public: + explicit IAppletCommonFunctions(Core::System& system_, std::shared_ptr<Applet> applet_); + ~IAppletCommonFunctions() override; + +private: + void SetCpuBoostRequestPriority(HLERequestContext& ctx); + void GetCurrentApplicationId(HLERequestContext& ctx); + + const std::shared_ptr<Applet> applet; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet_data_broker.cpp b/src/core/hle/service/am/applet_data_broker.cpp new file mode 100644 index 000000000..4d58c4db5 --- /dev/null +++ b/src/core/hle/service/am/applet_data_broker.cpp @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/scope_exit.h" + +#include "core/core.h" +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/applet_data_broker.h" +#include "core/hle/service/am/applet_manager.h" + +namespace Service::AM { + +AppletStorageChannel::AppletStorageChannel(KernelHelpers::ServiceContext& context) + : m_event(context) {} +AppletStorageChannel::~AppletStorageChannel() = default; + +void AppletStorageChannel::Push(std::shared_ptr<IStorage> storage) { + std::scoped_lock lk{m_lock}; + + m_data.emplace_back(std::move(storage)); + m_event.Signal(); +} + +Result AppletStorageChannel::Pop(std::shared_ptr<IStorage>* out_storage) { + std::scoped_lock lk{m_lock}; + + SCOPE_EXIT({ + if (m_data.empty()) { + m_event.Clear(); + } + }); + + R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel); + + *out_storage = std::move(m_data.front()); + m_data.pop_front(); + + R_SUCCEED(); +} + +Kernel::KReadableEvent* AppletStorageChannel::GetEvent() { + return m_event.GetHandle(); +} + +AppletDataBroker::AppletDataBroker(Core::System& system_) + : system(system_), context(system_, "AppletDataBroker"), in_data(context), + interactive_in_data(context), out_data(context), interactive_out_data(context), + state_changed_event(context), is_completed(false) {} + +AppletDataBroker::~AppletDataBroker() = default; + +void AppletDataBroker::SignalCompletion() { + { + std::scoped_lock lk{lock}; + + if (is_completed) { + return; + } + + is_completed = true; + state_changed_event.Signal(); + } + + system.GetAppletManager().FocusStateChanged(); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applet_data_broker.h b/src/core/hle/service/am/applet_data_broker.h new file mode 100644 index 000000000..12326fd04 --- /dev/null +++ b/src/core/hle/service/am/applet_data_broker.h @@ -0,0 +1,80 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <deque> +#include <memory> +#include <mutex> + +#include "core/hle/service/event.h" +#include "core/hle/service/kernel_helpers.h" + +union Result; + +namespace Service::AM { + +struct Applet; +class IStorage; + +class AppletStorageChannel { +public: + explicit AppletStorageChannel(KernelHelpers::ServiceContext& ctx); + ~AppletStorageChannel(); + + void Push(std::shared_ptr<IStorage> storage); + Result Pop(std::shared_ptr<IStorage>* out_storage); + Kernel::KReadableEvent* GetEvent(); + +private: + std::mutex m_lock{}; + std::deque<std::shared_ptr<IStorage>> m_data{}; + Event m_event; +}; + +class AppletDataBroker { +public: + explicit AppletDataBroker(Core::System& system_); + ~AppletDataBroker(); + + AppletStorageChannel& GetInData() { + return in_data; + } + + AppletStorageChannel& GetInteractiveInData() { + return interactive_in_data; + } + + AppletStorageChannel& GetOutData() { + return out_data; + } + + AppletStorageChannel& GetInteractiveOutData() { + return interactive_out_data; + } + + Event& GetStateChangedEvent() { + return state_changed_event; + } + + bool IsCompleted() const { + return is_completed; + } + + void SignalCompletion(); + +private: + Core::System& system; + KernelHelpers::ServiceContext context; + + AppletStorageChannel in_data; + AppletStorageChannel interactive_in_data; + AppletStorageChannel out_data; + AppletStorageChannel interactive_out_data; + Event state_changed_event; + + std::mutex lock; + bool is_completed; +}; + +} // 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..52200d5b2 --- /dev/null +++ b/src/core/hle/service/am/applet_manager.cpp @@ -0,0 +1,361 @@ +// 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/core.h" +#include "core/core_timing.h" +#include "core/hle/service/acc/profile_manager.h" +#include "core/hle/service/am/applet_data_broker.h" +#include "core/hle/service/am/applet_manager.h" +#include "core/hle/service/am/frontend/applet_cabinet.h" +#include "core/hle/service/am/frontend/applet_controller.h" +#include "core/hle/service/am/frontend/applet_mii_edit_types.h" +#include "core/hle/service/am/frontend/applet_software_keyboard_types.h" +#include "hid_core/hid_types.h" + +namespace Service::AM { + +namespace { + +constexpr u32 LaunchParameterAccountPreselectedUserMagic = 0xC79497CA; + +struct LaunchParameterAccountPreselectedUser { + u32 magic; + u32 is_account_selected; + Common::UUID current_user; + INSERT_PADDING_BYTES(0x70); +}; +static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); + +AppletStorageChannel& InitializeFakeCallerApplet(Core::System& system, + std::shared_ptr<Applet>& applet) { + applet->caller_applet_broker = std::make_shared<AppletDataBroker>(system); + return applet->caller_applet_broker->GetInData(); +} + +void PushInShowAlbum(Core::System& system, AppletStorageChannel& channel) { + const CommonArguments arguments{ + .arguments_version = CommonArgumentVersion::Version3, + .size = CommonArgumentSize::Version3, + .library_version = 1, + .theme_color = 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)); + channel.Push(std::make_shared<IStorage>(system, std::move(argument_data))); + channel.Push(std::make_shared<IStorage>(system, std::move(settings_data))); +} + +void PushInShowController(Core::System& system, AppletStorageChannel& channel) { + const CommonArguments common_args = { + .arguments_version = CommonArgumentVersion::Version3, + .size = CommonArgumentSize::Version3, + .library_version = static_cast<u32>(Frontend::ControllerAppletVersion::Version8), + .theme_color = ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + + Frontend::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 = {}, + }; + + Frontend::ControllerSupportArgPrivate private_args = { + .arg_private_size = sizeof(Frontend::ControllerSupportArgPrivate), + .arg_size = sizeof(Frontend::ControllerSupportArgNew), + .is_home_menu = true, + .flag_1 = true, + .mode = Frontend::ControllerSupportMode::ShowControllerSupport, + .caller = Frontend::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)); + + channel.Push(std::make_shared<IStorage>(system, std::move(common_args_data))); + channel.Push(std::make_shared<IStorage>(system, std::move(private_args_data))); + channel.Push(std::make_shared<IStorage>(system, std::move(user_args_data))); +} + +void PushInShowCabinetData(Core::System& system, AppletStorageChannel& channel) { + const CommonArguments arguments{ + .arguments_version = CommonArgumentVersion::Version3, + .size = CommonArgumentSize::Version3, + .library_version = static_cast<u32>(Frontend::CabinetAppletVersion::Version1), + .theme_color = ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + + const Frontend::StartParamForAmiiboSettings amiibo_settings{ + .param_1 = 0, + .applet_mode = system.GetFrontendAppletHolder().GetCabinetMode(), + .flags = Frontend::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)); + channel.Push(std::make_shared<IStorage>(system, std::move(argument_data))); + channel.Push(std::make_shared<IStorage>(system, std::move(settings_data))); +} + +void PushInShowMiiEditData(Core::System& system, AppletStorageChannel& channel) { + struct MiiEditV3 { + Frontend::MiiEditAppletInputCommon common; + Frontend::MiiEditAppletInputV3 input; + }; + static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size."); + + MiiEditV3 mii_arguments{ + .common = + { + .version = Frontend::MiiEditAppletVersion::Version3, + .applet_mode = Frontend::MiiEditAppletMode::ShowMiiEdit, + }, + .input{}, + }; + + std::vector<u8> argument_data(sizeof(mii_arguments)); + std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments)); + + channel.Push(std::make_shared<IStorage>(system, std::move(argument_data))); +} + +void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& channel) { + const CommonArguments arguments{ + .arguments_version = CommonArgumentVersion::Version3, + .size = CommonArgumentSize::Version3, + .library_version = static_cast<u32>(Frontend::SwkbdAppletVersion::Version524301), + .theme_color = ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + + std::vector<char16_t> initial_string(0); + + const Frontend::SwkbdConfigCommon swkbd_config{ + .type = Frontend::SwkbdType::Qwerty, + .ok_text{}, + .left_optional_symbol_key{}, + .right_optional_symbol_key{}, + .use_prediction = false, + .key_disable_flags{}, + .initial_cursor_position = Frontend::SwkbdInitialCursorPosition::Start, + .header_text{}, + .sub_text{}, + .guide_text{}, + .max_text_length = 500, + .min_text_length = 0, + .password_mode = Frontend::SwkbdPasswordMode::Disabled, + .text_draw_type = Frontend::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, + }; + + Frontend::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(Frontend::SwkbdConfigNew)); + std::memcpy(work_buffer.data(), initial_string.data(), + swkbd_config.initial_string_length * sizeof(char16_t)); + + channel.Push(std::make_shared<IStorage>(system, std::move(argument_data))); + channel.Push(std::make_shared<IStorage>(system, std::move(swkbd_data))); + channel.Push(std::make_shared<IStorage>(system, std::move(work_buffer))); +} + +} // namespace + +AppletManager::AppletManager(Core::System& system) : m_system(system) {} +AppletManager::~AppletManager() { + this->Reset(); +} + +void AppletManager::InsertApplet(std::shared_ptr<Applet> applet) { + std::scoped_lock lk{m_lock}; + + m_applets.emplace(applet->aruid, std::move(applet)); +} + +void AppletManager::TerminateAndRemoveApplet(AppletResourceUserId aruid) { + std::shared_ptr<Applet> applet; + bool should_stop = false; + { + std::scoped_lock lk{m_lock}; + + const auto it = m_applets.find(aruid); + if (it == m_applets.end()) { + return; + } + + applet = it->second; + m_applets.erase(it); + + should_stop = m_applets.empty(); + } + + // Terminate process. + applet->process->Terminate(); + + // If there were no applets left, stop emulation. + if (should_stop) { + m_system.Exit(); + } +} + +void AppletManager::CreateAndInsertByFrontendAppletParameters( + AppletResourceUserId aruid, const FrontendAppletParameters& params) { + // TODO: this should be run inside AM so that the events will have a parent process + // TODO: have am create the guest process + auto applet = std::make_shared<Applet>(m_system, std::make_unique<Process>(m_system)); + + applet->aruid = aruid; + applet->program_id = params.program_id; + applet->applet_id = params.applet_id; + applet->type = params.applet_type; + applet->previous_program_index = params.previous_program_index; + + // Push UserChannel data from previous application + if (params.launch_type == LaunchType::ApplicationInitiated) { + applet->user_channel_launch_parameter.swap(m_system.GetUserChannel()); + } + + // TODO: Read whether we need a preselected user from NACP? + // TODO: This can be done quite easily from loader + { + LaunchParameterAccountPreselectedUser lp{}; + + lp.magic = LaunchParameterAccountPreselectedUserMagic; + lp.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()); + lp.current_user = *uuid; + + std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); + std::memcpy(buffer.data(), &lp, buffer.size()); + + applet->preselected_user_launch_parameter.push_back(std::move(buffer)); + } + + // Starting from frontend, some applets require input data. + switch (applet->applet_id) { + case AppletId::Cabinet: + PushInShowCabinetData(m_system, InitializeFakeCallerApplet(m_system, applet)); + break; + case AppletId::MiiEdit: + PushInShowMiiEditData(m_system, InitializeFakeCallerApplet(m_system, applet)); + break; + case AppletId::PhotoViewer: + PushInShowAlbum(m_system, InitializeFakeCallerApplet(m_system, applet)); + break; + case AppletId::SoftwareKeyboard: + PushInShowSoftwareKeyboard(m_system, InitializeFakeCallerApplet(m_system, applet)); + break; + case AppletId::Controller: + PushInShowController(m_system, InitializeFakeCallerApplet(m_system, applet)); + break; + default: + break; + } + + // Applet was started by frontend, so it is foreground. + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); + applet->focus_state = FocusState::InFocus; + + this->InsertApplet(std::move(applet)); +} + +std::shared_ptr<Applet> AppletManager::GetByAppletResourceUserId(AppletResourceUserId aruid) const { + std::scoped_lock lk{m_lock}; + + if (const auto it = m_applets.find(aruid); it != m_applets.end()) { + return it->second; + } + + return {}; +} + +void AppletManager::Reset() { + std::scoped_lock lk{m_lock}; + + m_applets.clear(); +} + +void AppletManager::RequestExit() { + std::scoped_lock lk{m_lock}; + + for (const auto& [aruid, applet] : m_applets) { + applet->message_queue.RequestExit(); + } +} + +void AppletManager::RequestResume() { + std::scoped_lock lk{m_lock}; + + for (const auto& [aruid, applet] : m_applets) { + applet->message_queue.RequestResume(); + } +} + +void AppletManager::OperationModeChanged() { + std::scoped_lock lk{m_lock}; + + for (const auto& [aruid, applet] : m_applets) { + applet->message_queue.OperationModeChanged(); + } +} + +void AppletManager::FocusStateChanged() { + std::scoped_lock lk{m_lock}; + + for (const auto& [aruid, applet] : m_applets) { + applet->message_queue.FocusStateChanged(); + } +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <map> +#include <mutex> + +#include "core/hle/service/am/applet.h" + +namespace Core { +class System; +} + +namespace Service::AM { + +enum class LaunchType { + FrontendInitiated, + ApplicationInitiated, +}; + +struct FrontendAppletParameters { + ProgramId program_id{}; + AppletId applet_id{}; + AppletType applet_type{}; + LaunchType launch_type{}; + s32 program_index{}; + s32 previous_program_index{-1}; +}; + +class AppletManager { +public: + explicit AppletManager(Core::System& system); + ~AppletManager(); + + void InsertApplet(std::shared_ptr<Applet> applet); + void TerminateAndRemoveApplet(AppletResourceUserId aruid); + + void CreateAndInsertByFrontendAppletParameters(AppletResourceUserId aruid, + const FrontendAppletParameters& params); + std::shared_ptr<Applet> GetByAppletResourceUserId(AppletResourceUserId aruid) const; + + void Reset(); + + void RequestExit(); + void RequestResume(); + void OperationModeChanged(); + void FocusStateChanged(); + +private: + Core::System& m_system; + + mutable std::mutex m_lock{}; + std::map<AppletResourceUserId, std::shared_ptr<Applet>> m_applets{}; + + // AudioController state goes here +}; + +} // 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..5ed996b70 --- /dev/null +++ b/src/core/hle/service/am/applet_message_queue.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/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) { + { + std::scoped_lock lk{lock}; + messages.push(msg); + } + on_new_message->Signal(); +} + +AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { + std::scoped_lock lk{lock}; + 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 { + std::scoped_lock lk{lock}; + 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..5cb236d47 --- /dev/null +++ b/src/core/hle/service/am/applet_message_queue.h @@ -0,0 +1,76 @@ +// 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; + + mutable std::mutex lock; + 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..56bafd162 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp @@ -1,129 +1,42 @@ // 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_manager.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"); +AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_) + : ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_} { + static const FunctionInfo functions[] = { + {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, + }; + RegisterHandlers(functions); +} - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue); - } +AppletOE::~AppletOE() = default; - void GetLibraryAppletCreator(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); +void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + if (const auto applet = GetAppletFromContext(ctx)) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface<ILibraryAppletCreator>(system); - } - - void GetApplicationFunctions(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); + rb.PushIpcInterface<IApplicationProxy>(nvnflinger, applet, system); + } else { + UNIMPLEMENTED(); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IApplicationFunctions>(system); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); } - - Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr<AppletMessageQueue> msg_queue; -}; - -void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IApplicationProxy>(nvnflinger, msg_queue, system); -} - -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_)} { - static const FunctionInfo functions[] = { - {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, - }; - RegisterHandlers(functions); } -AppletOE::~AppletOE() = default; - -const std::shared_ptr<AppletMessageQueue>& AppletOE::GetMessageQueue() const { - return msg_queue; +std::shared_ptr<Applet> AppletOE::GetAppletFromContext(HLERequestContext& ctx) { + const auto aruid = ctx.GetPID(); + return system.GetAppletManager().GetByAppletResourceUserId(aruid); } } // namespace Service::AM diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h index 39eccc4ab..f2ba1c924 100644 --- a/src/core/hle/service/am/applet_oe.h +++ b/src/core/hle/service/am/applet_oe.h @@ -18,21 +18,19 @@ class Nvnflinger; namespace AM { -class AppletMessageQueue; +struct Applet; class AppletOE final : public ServiceFramework<AppletOE> { public: - explicit AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, - std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_); + explicit AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_); ~AppletOE() override; - const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const; - private: void OpenApplicationProxy(HLERequestContext& ctx); + std::shared_ptr<Applet> GetAppletFromContext(HLERequestContext& ctx); + Nvnflinger::Nvnflinger& nvnflinger; - std::shared_ptr<AppletMessageQueue> msg_queue; }; } // namespace AM diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp deleted file mode 100644 index 89d5434af..000000000 --- a/src/core/hle/service/am/applets/applets.cpp +++ /dev/null @@ -1,338 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <cstring> - -#include "common/assert.h" -#include "core/core.h" -#include "core/frontend/applets/cabinet.h" -#include "core/frontend/applets/controller.h" -#include "core/frontend/applets/error.h" -#include "core/frontend/applets/general_frontend.h" -#include "core/frontend/applets/mii_edit.h" -#include "core/frontend/applets/profile_select.h" -#include "core/frontend/applets/software_keyboard.h" -#include "core/frontend/applets/web_browser.h" -#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_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_error.h" -#include "core/hle/service/am/applets/applet_general_backend.h" -#include "core/hle/service/am/applets/applet_mii_edit.h" -#include "core/hle/service/am/applets/applet_profile_select.h" -#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/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"} { - state_changed_event = service_context.CreateEvent("ILibraryAppletAccessor:StateChangedEvent"); - pop_out_data_event = service_context.CreateEvent("ILibraryAppletAccessor:PopDataOutEvent"); - pop_interactive_out_data_event = - service_context.CreateEvent("ILibraryAppletAccessor:PopInteractiveDataOutEvent"); -} - -AppletDataBroker::~AppletDataBroker() { - service_context.CloseEvent(state_changed_event); - service_context.CloseEvent(pop_out_data_event); - service_context.CloseEvent(pop_interactive_out_data_event); -} - -AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() const { - std::vector<std::vector<u8>> out_normal; - - for (const auto& storage : in_channel) { - out_normal.push_back(storage->GetData()); - } - - std::vector<std::vector<u8>> out_interactive; - - for (const auto& storage : in_interactive_channel) { - out_interactive.push_back(storage->GetData()); - } - - return {std::move(out_normal), std::move(out_interactive)}; -} - -std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() { - if (out_channel.empty()) - return nullptr; - - auto out = std::move(out_channel.front()); - out_channel.pop_front(); - pop_out_data_event->Clear(); - return out; -} - -std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() { - if (in_channel.empty()) - return nullptr; - - auto out = std::move(in_channel.front()); - in_channel.pop_front(); - return out; -} - -std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() { - if (out_interactive_channel.empty()) - return nullptr; - - auto out = std::move(out_interactive_channel.front()); - out_interactive_channel.pop_front(); - pop_interactive_out_data_event->Clear(); - return out; -} - -std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() { - if (in_interactive_channel.empty()) - return nullptr; - - auto out = std::move(in_interactive_channel.front()); - in_interactive_channel.pop_front(); - return out; -} - -void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage) { - in_channel.emplace_back(std::move(storage)); -} - -void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) { - out_channel.emplace_back(std::move(storage)); - pop_out_data_event->Signal(); -} - -void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) { - in_interactive_channel.emplace_back(std::move(storage)); -} - -void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) { - out_interactive_channel.emplace_back(std::move(storage)); - pop_interactive_out_data_event->Signal(); -} - -void AppletDataBroker::SignalStateChanged() { - state_changed_event->Signal(); - - switch (applet_mode) { - case LibraryAppletMode::AllForeground: - case LibraryAppletMode::AllForegroundInitiallyHidden: { - auto applet_oe = system.ServiceManager().GetService<AppletOE>("appletOE"); - auto applet_ae = system.ServiceManager().GetService<AppletAE>("appletAE"); - - if (applet_oe) { - applet_oe->GetMessageQueue()->FocusStateChanged(); - break; - } - - if (applet_ae) { - applet_ae->GetMessageQueue()->FocusStateChanged(); - break; - } - break; - } - default: - break; - } -} - -Kernel::KReadableEvent& AppletDataBroker::GetNormalDataEvent() { - return pop_out_data_event->GetReadableEvent(); -} - -Kernel::KReadableEvent& AppletDataBroker::GetInteractiveDataEvent() { - return pop_interactive_out_data_event->GetReadableEvent(); -} - -Kernel::KReadableEvent& AppletDataBroker::GetStateChangedEvent() { - return state_changed_event->GetReadableEvent(); -} - -Applet::Applet(Core::System& system_, LibraryAppletMode applet_mode_) - : broker{system_, applet_mode_}, applet_mode{applet_mode_} {} - -Applet::~Applet() = default; - -void Applet::Initialize() { - const auto common = broker.PopNormalDataToApplet(); - ASSERT(common != nullptr); - - const auto common_data = common->GetData(); - - ASSERT(common_data.size() >= sizeof(CommonArguments)); - std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments)); - - initialized = true; -} - -AppletFrontendSet::AppletFrontendSet() = default; - -AppletFrontendSet::AppletFrontendSet(CabinetApplet cabinet_applet, - ControllerApplet controller_applet, ErrorApplet error_applet, - MiiEdit mii_edit_, - ParentalControlsApplet parental_controls_applet, - PhotoViewer photo_viewer_, ProfileSelect profile_select_, - SoftwareKeyboard software_keyboard_, WebBrowser web_browser_) - : cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)}, - error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)}, - parental_controls{std::move(parental_controls_applet)}, - photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)}, - software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {} - -AppletFrontendSet::~AppletFrontendSet() = default; - -AppletFrontendSet::AppletFrontendSet(AppletFrontendSet&&) noexcept = default; - -AppletFrontendSet& AppletFrontendSet::operator=(AppletFrontendSet&&) noexcept = default; - -AppletManager::AppletManager(Core::System& system_) : system{system_} {} - -AppletManager::~AppletManager() = default; - -const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const { - return frontend; -} - -NFP::CabinetMode AppletManager::GetCabinetMode() const { - return cabinet_mode; -} - -AppletId AppletManager::GetCurrentAppletId() const { - return current_applet_id; -} - -void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { - if (set.cabinet != nullptr) { - frontend.cabinet = std::move(set.cabinet); - } - - if (set.controller != nullptr) { - frontend.controller = std::move(set.controller); - } - - if (set.error != nullptr) { - frontend.error = std::move(set.error); - } - - if (set.mii_edit != nullptr) { - frontend.mii_edit = std::move(set.mii_edit); - } - - if (set.parental_controls != nullptr) { - frontend.parental_controls = std::move(set.parental_controls); - } - - if (set.photo_viewer != nullptr) { - frontend.photo_viewer = std::move(set.photo_viewer); - } - - if (set.profile_select != nullptr) { - frontend.profile_select = std::move(set.profile_select); - } - - if (set.software_keyboard != nullptr) { - frontend.software_keyboard = std::move(set.software_keyboard); - } - - if (set.web_browser != nullptr) { - frontend.web_browser = std::move(set.web_browser); - } -} - -void AppletManager::SetCabinetMode(NFP::CabinetMode mode) { - cabinet_mode = mode; -} - -void AppletManager::SetCurrentAppletId(AppletId applet_id) { - current_applet_id = applet_id; -} - -void AppletManager::SetDefaultAppletFrontendSet() { - ClearAll(); - SetDefaultAppletsIfMissing(); -} - -void AppletManager::SetDefaultAppletsIfMissing() { - if (frontend.cabinet == nullptr) { - frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>(); - } - - if (frontend.controller == nullptr) { - frontend.controller = - std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore()); - } - - if (frontend.error == nullptr) { - frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>(); - } - - if (frontend.mii_edit == nullptr) { - frontend.mii_edit = std::make_unique<Core::Frontend::DefaultMiiEditApplet>(); - } - - if (frontend.parental_controls == nullptr) { - frontend.parental_controls = - std::make_unique<Core::Frontend::DefaultParentalControlsApplet>(); - } - - if (frontend.photo_viewer == nullptr) { - frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>(); - } - - if (frontend.profile_select == nullptr) { - frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>(); - } - - if (frontend.software_keyboard == nullptr) { - frontend.software_keyboard = - std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>(); - } - - if (frontend.web_browser == nullptr) { - frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); - } -} - -void AppletManager::ClearAll() { - frontend = {}; -} - -std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode mode) const { - switch (id) { - case AppletId::Auth: - return std::make_shared<Auth>(system, mode, *frontend.parental_controls); - case AppletId::Cabinet: - return std::make_shared<Cabinet>(system, mode, *frontend.cabinet); - case AppletId::Controller: - return std::make_shared<Controller>(system, mode, *frontend.controller); - case AppletId::Error: - return std::make_shared<Error>(system, mode, *frontend.error); - case AppletId::ProfileSelect: - return std::make_shared<ProfileSelect>(system, mode, *frontend.profile_select); - case AppletId::SoftwareKeyboard: - return std::make_shared<SoftwareKeyboard>(system, mode, *frontend.software_keyboard); - case AppletId::MiiEdit: - return std::make_shared<MiiEdit>(system, mode, *frontend.mii_edit); - case AppletId::Web: - case AppletId::Shop: - case AppletId::OfflineWeb: - case AppletId::LoginShare: - case AppletId::WebAuth: - return std::make_shared<WebBrowser>(system, mode, *frontend.web_browser); - case AppletId::PhotoViewer: - return std::make_shared<PhotoViewer>(system, mode, *frontend.photo_viewer); - default: - UNIMPLEMENTED_MSG( - "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", - static_cast<u8>(id)); - return std::make_shared<StubApplet>(system, id, mode); - } -} - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h deleted file mode 100644 index 0bf2598b7..000000000 --- a/src/core/hle/service/am/applets/applets.h +++ /dev/null @@ -1,289 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <memory> -#include <queue> - -#include "common/swap.h" -#include "core/hle/service/kernel_helpers.h" - -union Result; - -namespace Core { -class System; -} - -namespace Core::Frontend { -class CabinetApplet; -class ControllerApplet; -class ECommerceApplet; -class ErrorApplet; -class MiiEditApplet; -class ParentalControlsApplet; -class PhotoViewerApplet; -class ProfileSelectApplet; -class SoftwareKeyboardApplet; -class WebBrowserApplet; -} // namespace Core::Frontend - -namespace Kernel { -class KernelCore; -class KEvent; -class KReadableEvent; -} // namespace Kernel - -namespace Service::NFP { -enum class CabinetMode : u8; -} // namespace Service::NFP - -namespace Service::AM { - -class IStorage; - -namespace Applets { - -enum class AppletId : u32 { - None = 0x00, - Application = 0x01, - OverlayDisplay = 0x02, - QLaunch = 0x03, - Starter = 0x04, - Auth = 0x0A, - Cabinet = 0x0B, - Controller = 0x0C, - DataErase = 0x0D, - Error = 0x0E, - NetConnect = 0x0F, - ProfileSelect = 0x10, - SoftwareKeyboard = 0x11, - MiiEdit = 0x12, - Web = 0x13, - Shop = 0x14, - PhotoViewer = 0x15, - Settings = 0x16, - OfflineWeb = 0x17, - LoginShare = 0x18, - WebAuth = 0x19, - MyPage = 0x1A, -}; - -enum class AppletProgramId : u64 { - QLaunch = 0x0100000000001000ull, - Auth = 0x0100000000001001ull, - Cabinet = 0x0100000000001002ull, - Controller = 0x0100000000001003ull, - DataErase = 0x0100000000001004ull, - Error = 0x0100000000001005ull, - NetConnect = 0x0100000000001006ull, - ProfileSelect = 0x0100000000001007ull, - SoftwareKeyboard = 0x0100000000001008ull, - MiiEdit = 0x0100000000001009ull, - Web = 0x010000000000100Aull, - Shop = 0x010000000000100Bull, - OverlayDisplay = 0x010000000000100Cull, - PhotoViewer = 0x010000000000100Dull, - Settings = 0x010000000000100Eull, - OfflineWeb = 0x010000000000100Full, - LoginShare = 0x0100000000001010ull, - WebAuth = 0x0100000000001011ull, - Starter = 0x0100000000001012ull, - MyPage = 0x0100000000001013ull, - MaxProgramId = 0x0100000000001FFFull, -}; - -enum class LibraryAppletMode : u32 { - AllForeground = 0, - Background = 1, - NoUI = 2, - BackgroundIndirectDisplay = 3, - AllForegroundInitiallyHidden = 4, -}; - -enum class CommonArgumentVersion : u32 { - Version0, - Version1, - Version2, - Version3, -}; - -enum class CommonArgumentSize : u32 { - Version3 = 0x20, -}; - -enum class ThemeColor : u32 { - BasicWhite = 0, - BasicBlack = 3, -}; - -struct CommonArguments { - CommonArgumentVersion arguments_version; - CommonArgumentSize size; - u32 library_version; - ThemeColor theme_color; - bool play_startup_sound; - u64_le system_tick; -}; -static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size."); - -class AppletDataBroker final { -public: - explicit AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_); - ~AppletDataBroker(); - - struct RawChannelData { - std::vector<std::vector<u8>> normal; - std::vector<std::vector<u8>> interactive; - }; - - // Retrieves but does not pop the data sent to applet. - RawChannelData PeekDataToAppletForDebug() const; - - std::shared_ptr<IStorage> PopNormalDataToGame(); - std::shared_ptr<IStorage> PopNormalDataToApplet(); - - std::shared_ptr<IStorage> PopInteractiveDataToGame(); - std::shared_ptr<IStorage> PopInteractiveDataToApplet(); - - void PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage); - void PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage); - - void PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage); - void PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage); - - void SignalStateChanged(); - - Kernel::KReadableEvent& GetNormalDataEvent(); - Kernel::KReadableEvent& GetInteractiveDataEvent(); - Kernel::KReadableEvent& GetStateChangedEvent(); - -private: - Core::System& system; - LibraryAppletMode applet_mode; - - KernelHelpers::ServiceContext service_context; - - // Queues are named from applet's perspective - - // PopNormalDataToApplet and PushNormalDataFromGame - std::deque<std::shared_ptr<IStorage>> in_channel; - - // PopNormalDataToGame and PushNormalDataFromApplet - std::deque<std::shared_ptr<IStorage>> out_channel; - - // PopInteractiveDataToApplet and PushInteractiveDataFromGame - std::deque<std::shared_ptr<IStorage>> in_interactive_channel; - - // PopInteractiveDataToGame and PushInteractiveDataFromApplet - std::deque<std::shared_ptr<IStorage>> out_interactive_channel; - - Kernel::KEvent* state_changed_event; - - // Signaled on PushNormalDataFromApplet - Kernel::KEvent* pop_out_data_event; - - // Signaled on PushInteractiveDataFromApplet - Kernel::KEvent* pop_interactive_out_data_event; -}; - -class Applet { -public: - explicit Applet(Core::System& system_, LibraryAppletMode applet_mode_); - virtual ~Applet(); - - virtual void Initialize(); - - virtual bool TransactionComplete() const = 0; - virtual Result GetStatus() const = 0; - virtual void ExecuteInteractive() = 0; - virtual void Execute() = 0; - virtual Result RequestExit() = 0; - - AppletDataBroker& GetBroker() { - return broker; - } - - const AppletDataBroker& GetBroker() const { - return broker; - } - - LibraryAppletMode GetLibraryAppletMode() const { - return applet_mode; - } - - bool IsInitialized() const { - return initialized; - } - -protected: - CommonArguments common_args{}; - AppletDataBroker broker; - LibraryAppletMode applet_mode; - bool initialized = false; -}; - -struct AppletFrontendSet { - using CabinetApplet = std::unique_ptr<Core::Frontend::CabinetApplet>; - using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>; - using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; - using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>; - using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>; - using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>; - using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>; - using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>; - using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; - - AppletFrontendSet(); - AppletFrontendSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet, - ErrorApplet error_applet, MiiEdit mii_edit_, - ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_, - ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_, - WebBrowser web_browser_); - ~AppletFrontendSet(); - - AppletFrontendSet(const AppletFrontendSet&) = delete; - AppletFrontendSet& operator=(const AppletFrontendSet&) = delete; - - AppletFrontendSet(AppletFrontendSet&&) noexcept; - AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; - - CabinetApplet cabinet; - ControllerApplet controller; - ErrorApplet error; - MiiEdit mii_edit; - ParentalControlsApplet parental_controls; - PhotoViewer photo_viewer; - ProfileSelect profile_select; - SoftwareKeyboard software_keyboard; - WebBrowser web_browser; -}; - -class AppletManager { -public: - explicit AppletManager(Core::System& system_); - ~AppletManager(); - - const AppletFrontendSet& GetAppletFrontendSet() const; - NFP::CabinetMode GetCabinetMode() const; - AppletId GetCurrentAppletId() const; - - void SetAppletFrontendSet(AppletFrontendSet set); - void SetCabinetMode(NFP::CabinetMode mode); - void SetCurrentAppletId(AppletId applet_id); - void SetDefaultAppletFrontendSet(); - void SetDefaultAppletsIfMissing(); - void ClearAll(); - - std::shared_ptr<Applet> GetApplet(AppletId id, LibraryAppletMode mode) const; - -private: - AppletId current_applet_id{}; - NFP::CabinetMode cabinet_mode{}; - - AppletFrontendSet frontend; - Core::System& system; -}; - -} // namespace Applets -} // namespace Service::AM 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..51c5be2d1 --- /dev/null +++ b/src/core/hle/service/am/application_functions.cpp @@ -0,0 +1,594 @@ +// 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/applet.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, +}; + +IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet_) + : ServiceFramework{system_, "IApplicationFunctions"}, applet{std::move(applet_)} { + // 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); +} + +IApplicationFunctions::~IApplicationFunctions() = default; + +void IApplicationFunctions::EnableApplicationCrashReport(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::scoped_lock lk{applet->lock}; + applet->application_crash_report_enabled = true; + + 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"); + + std::scoped_lock lk{applet->lock}; + applet->home_button_long_pressed_blocked = true; + applet->home_button_short_pressed_blocked = true; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::scoped_lock lk{applet->lock}; + applet->home_button_long_pressed_blocked = false; + applet->home_button_short_pressed_blocked = false; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::BeginBlockingHomeButton(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::scoped_lock lk{applet->lock}; + applet->home_button_long_pressed_blocked = true; + applet->home_button_short_pressed_blocked = true; + applet->home_button_double_click_enabled = true; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::EndBlockingHomeButton(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::scoped_lock lk{applet->lock}; + applet->home_button_long_pressed_blocked = false; + applet->home_button_short_pressed_blocked = false; + applet->home_button_double_click_enabled = false; + + 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); + + std::scoped_lock lk{applet->lock}; + + auto& channel = kind == LaunchParameterKind::UserChannel + ? applet->user_channel_launch_parameter + : applet->preselected_user_launch_parameter; + + if (channel.empty()) { + LOG_WARNING(Service_AM, "Attempted to pop parameter {} but none was found!", kind); + 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)); +} + +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 = applet->program_id; + 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); + + std::scoped_lock lk{applet->lock}; + applet->terminate_result = Result(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 FileSys::PatchManager pm{applet->program_id, system.GetFileSystemController(), + system.GetContentProvider()}; + auto metadata = pm.GetControlMetadata(); + if (metadata.first != nullptr) { + return metadata; + } + + const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(applet->program_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 FileSys::PatchManager pm{applet->program_id, system.GetFileSystemController(), + system.GetContentProvider()}; + auto metadata = pm.GetControlMetadata(); + if (metadata.first != nullptr) { + return metadata; + } + + const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(applet->program_id), + system.GetFileSystemController(), + system.GetContentProvider()}; + return pm_update.GetControlMetadata(); + }(); + + if (res.first != nullptr) { + supported_languages = res.first->GetSupportedLanguages(); + } + + // Call IApplicationManagerInterface implementation. + auto& service_manager = system.ServiceManager(); + auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2"); + auto app_man = ns_am2->GetApplicationManagerInterface(); + + // Get desired application language + u8 desired_language{}; + 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"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(applet->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::RequestParser rp{ctx}; + + std::scoped_lock lk{applet->lock}; + applet->gameplay_recording_state = rp.PopRaw<GameplayRecordingState>(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IApplicationFunctions::NotifyRunning(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::scoped_lock lk{applet->lock}; + applet->is_running = true; + + 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, applet->program_id, 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, applet->program_id, 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); + + // Swap user channel ownership into the system so that it will be preserved + system.GetUserChannel().swap(applet->user_channel_launch_parameter); + system.ExecuteProgram(program_index); +} + +void IApplicationFunctions::ClearUserChannel(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + applet->user_channel_launch_parameter.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) { + applet->user_channel_launch_parameter.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>(applet->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(applet->gpu_error_detected_event.GetHandle()); +} + +void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(applet->friend_invitation_storage_channel_event.GetHandle()); +} + +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(applet->notification_storage_channel_event.GetHandle()); +} + +void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(applet->health_warning_disappeared_system_event.GetHandle()); +} + +void IApplicationFunctions::PrepareForJit(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::scoped_lock lk{applet->lock}; + applet->jit_service_launched = true; + + 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..55eb21d39 --- /dev/null +++ b/src/core/hle/service/am/application_functions.h @@ -0,0 +1,58 @@ +// 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 { + +struct Applet; + +class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { +public: + explicit IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet_); + ~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); + + const std::shared_ptr<Applet> applet; +}; + +} // 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..a6fd6d37f --- /dev/null +++ b/src/core/hle/service/am/application_proxy.cpp @@ -0,0 +1,115 @@ +// 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<Applet> applet_, Core::System& system_) + : ServiceFramework{system_, "IApplicationProxy"}, nvnflinger{nvnflinger_}, applet{std::move( + applet_)} { + // 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); +} + +IApplicationProxy::~IApplicationProxy() = default; + +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, applet); +} + +void IApplicationProxy::GetProcessWindingController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IProcessWindingController>(system, applet); +} + +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, applet); +} + +void IApplicationProxy::GetSelfController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ISelfController>(system, applet, 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, applet); +} + +void IApplicationProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILibraryAppletCreator>(system, applet); +} + +void IApplicationProxy::GetApplicationFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IApplicationFunctions>(system, applet); +} + +} // 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..eb98b095c --- /dev/null +++ b/src/core/hle/service/am/application_proxy.h @@ -0,0 +1,33 @@ +// 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 { + +struct Applet; + +class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { +public: + explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, + std::shared_ptr<Applet> msg_queue_, Core::System& system_); + ~IApplicationProxy(); + +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<Applet> applet; +}; + +} // 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..937ac0beb --- /dev/null +++ b/src/core/hle/service/am/common_state_getter.cpp @@ -0,0 +1,314 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/settings.h" +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/applet.h" +#include "core/hle/service/am/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<Applet> applet_) + : ServiceFramework{system_, "ICommonStateGetter"}, applet{std::move(applet_)} { + // 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, &ICommonStateGetter::GetAppletLaunchedHistory, "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); +} + +ICommonStateGetter::~ICommonStateGetter() = default; + +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, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(applet->message_queue.GetMessageReceiveEvent()); +} + +void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + const auto message = applet->message_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"); + + std::scoped_lock lk{applet->lock}; + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast<u8>(applet->focus_state)); +} + +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. + applet->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(applet->sleep_lock_event.GetHandle()); +} + +void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + std::scoped_lock lk{applet->lock}; + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(applet->vr_mode_enabled); +} + +void ICommonStateGetter::SetVrModeEnabled(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + std::scoped_lock lk{applet->lock}; + applet->vr_mode_enabled = rp.Pop<bool>(); + LOG_WARNING(Service_AM, "VR Mode is {}", applet->vr_mode_enabled ? "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"); + + std::scoped_lock lk{applet->lock}; + applet->vr_mode_enabled = true; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ICommonStateGetter::EndVrModeEx(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::scoped_lock lk{applet->lock}; + applet->vr_mode_enabled = false; + + 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(applet->message_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::GetAppletLaunchedHistory(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::shared_ptr<Applet> current_applet = applet; + std::vector<AppletId> result; + + const size_t count = ctx.GetWriteBufferNumElements<AppletId>(); + size_t i; + + for (i = 0; i < count && current_applet != nullptr; i++) { + result.push_back(current_applet->applet_id); + current_applet = current_applet->caller_applet.lock(); + } + + ctx.WriteBuffer(result); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast<u32>(i)); +} + +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"); + + std::scoped_lock lk{applet->lock}; + applet->request_exit_to_library_applet_at_execute_next_program_enabled = true; + + 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..bf652790c --- /dev/null +++ b/src/core/hle/service/am/common_state_getter.h @@ -0,0 +1,77 @@ +// 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 { + +struct Applet; + +class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { +public: + explicit ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet_); + ~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 GetAppletLaunchedHistory(HLERequestContext& ctx); + void GetSettingsPlatformRegion(HLERequestContext& ctx); + void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx); + + const std::shared_ptr<Applet> applet; +}; + +} // 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..4d6858348 --- /dev/null +++ b/src/core/hle/service/am/display_controller.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.h" +#include "core/hle/service/am/display_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +namespace { +struct OutputParameters { + bool was_written; + s32 fbshare_layer_index; +}; + +static_assert(sizeof(OutputParameters) == 8, "OutputParameters has wrong size"); +} // namespace + +IDisplayController::IDisplayController(Core::System& system_, std::shared_ptr<Applet> applet_) + : ServiceFramework{system_, "IDisplayController"}, applet(std::move(applet_)) { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetLastForegroundCaptureImage"}, + {1, nullptr, "UpdateLastForegroundCaptureImage"}, + {2, nullptr, "GetLastApplicationCaptureImage"}, + {3, nullptr, "GetCallerAppletCaptureImage"}, + {4, nullptr, "UpdateCallerAppletCaptureImage"}, + {5, nullptr, "GetLastForegroundCaptureImageEx"}, + {6, nullptr, "GetLastApplicationCaptureImageEx"}, + {7, &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, &IDisplayController::AcquireLastApplicationCaptureSharedBuffer, "AcquireLastApplicationCaptureSharedBuffer"}, + {23, &IDisplayController::ReleaseLastApplicationCaptureSharedBuffer, "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"); + + OutputParameters params{}; + const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer( + ¶ms.was_written, ¶ms.fbshare_layer_index); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.PushRaw(params); +} + +void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IDisplayController::AcquireLastApplicationCaptureSharedBuffer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + OutputParameters params{}; + const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer( + ¶ms.was_written, ¶ms.fbshare_layer_index); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.PushRaw(params); +} + +void IDisplayController::ReleaseLastApplicationCaptureSharedBuffer(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"); + + OutputParameters params{}; + const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer( + ¶ms.was_written, ¶ms.fbshare_layer_index); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.PushRaw(params); +} + +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"); + + OutputParameters params{}; + const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer( + ¶ms.was_written, ¶ms.fbshare_layer_index); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.PushRaw(params); +} + +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..75172580c --- /dev/null +++ b/src/core/hle/service/am/display_controller.h @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::AM { + +struct Applet; + +class IDisplayController final : public ServiceFramework<IDisplayController> { +public: + explicit IDisplayController(Core::System& system_, std::shared_ptr<Applet> applet_); + ~IDisplayController() override; + +private: + void GetCallerAppletCaptureImageEx(HLERequestContext& ctx); + void TakeScreenShotOfOwnLayer(HLERequestContext& ctx); + void AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx); + void ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx); + void AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx); + void ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx); + void AcquireLastApplicationCaptureSharedBuffer(HLERequestContext& ctx); + void ReleaseLastApplicationCaptureSharedBuffer(HLERequestContext& ctx); + + const std::shared_ptr<Applet> applet; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/frontend/applet_cabinet.cpp index c2ff444a6..0862c81b6 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ b/src/core/hle/service/am/frontend/applet_cabinet.cpp @@ -8,16 +8,17 @@ #include "core/hle/kernel/k_event.h" #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/frontend/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" -namespace Service::AM::Applets { +namespace Service::AM::Frontend { -Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::CabinetApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, service_context{ +Cabinet::Cabinet(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::CabinetApplet& frontend_) + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_}, service_context{ system_, "CabinetApplet"} { @@ -30,7 +31,7 @@ Cabinet::~Cabinet() { }; void Cabinet::Initialize() { - Applet::Initialize(); + FrontendApplet::Initialize(); LOG_INFO(Service_HID, "Initializing Cabinet Applet."); @@ -41,7 +42,7 @@ void Cabinet::Initialize() { common_args.play_startup_sound, common_args.size, common_args.system_tick, common_args.theme_color); - const auto storage = broker.PopNormalDataToApplet(); + std::shared_ptr<IStorage> storage = PopInData(); ASSERT(storage != nullptr); const auto applet_input_data = storage->GetData(); @@ -51,10 +52,6 @@ void Cabinet::Initialize() { sizeof(StartParamForAmiiboSettings)); } -bool Cabinet::TransactionComplete() const { - return is_complete; -} - Result Cabinet::GetStatus() const { return ResultSuccess; } @@ -160,8 +157,8 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) is_complete = true; - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::move(out_data))); + Exit(); } void Cabinet::Cancel() { @@ -175,8 +172,8 @@ void Cabinet::Cancel() { is_complete = true; - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::move(out_data))); + Exit(); } Result Cabinet::RequestExit() { @@ -184,4 +181,4 @@ Result Cabinet::RequestExit() { R_SUCCEED(); } -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/frontend/applet_cabinet.h index f498796f7..3a211ed37 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.h +++ b/src/core/hle/service/am/frontend/applet_cabinet.h @@ -6,7 +6,7 @@ #include <array> #include "core/hle/result.h" -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/kernel_helpers.h" #include "core/hle/service/nfp/nfp_types.h" @@ -23,7 +23,7 @@ namespace Service::NFC { class NfcDevice; } -namespace Service::AM::Applets { +namespace Service::AM::Frontend { enum class CabinetAppletVersion : u32 { Version1 = 0x1, @@ -84,15 +84,15 @@ static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188, "ReturnValueForAmiiboSettings is an invalid size"); #pragma pack(pop) -class Cabinet final : public Applet { +class Cabinet final : public FrontendApplet { public: - explicit Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, + explicit Cabinet(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::CabinetApplet& frontend_); ~Cabinet() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -102,7 +102,6 @@ public: private: const Core::Frontend::CabinetApplet& frontend; - Core::System& system; bool is_complete{false}; std::shared_ptr<Service::NFC::NfcDevice> nfp_device; @@ -111,4 +110,4 @@ private: StartParamForAmiiboSettings applet_input_common{}; }; -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/frontend/applet_controller.cpp index 0e4d9cc39..bd3e49fc4 100644 --- a/src/core/hle/service/am/applets/applet_controller.cpp +++ b/src/core/hle/service/am/frontend/applet_controller.cpp @@ -11,13 +11,14 @@ #include "core/frontend/applets/controller.h" #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/frontend/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" #include "hid_core/resources/npad/npad.h" -namespace Service::AM::Applets { +namespace Service::AM::Frontend { [[maybe_unused]] constexpr Result ResultControllerSupportCanceled{ErrorModule::HID, 3101}; [[maybe_unused]] constexpr Result ResultControllerSupportNotSupportedNpadStyle{ErrorModule::HID, @@ -46,14 +47,15 @@ static Core::Frontend::ControllerParameters ConvertToFrontendParameters( }; } -Controller::Controller(Core::System& system_, LibraryAppletMode applet_mode_, +Controller::Controller(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::ControllerApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} Controller::~Controller() = default; void Controller::Initialize() { - Applet::Initialize(); + FrontendApplet::Initialize(); LOG_INFO(Service_HID, "Initializing Controller Applet."); @@ -66,7 +68,7 @@ void Controller::Initialize() { controller_applet_version = ControllerAppletVersion{common_args.library_version}; - const auto private_arg_storage = broker.PopNormalDataToApplet(); + const std::shared_ptr<IStorage> private_arg_storage = PopInData(); ASSERT(private_arg_storage != nullptr); const auto& private_arg = private_arg_storage->GetData(); @@ -116,7 +118,7 @@ void Controller::Initialize() { switch (controller_private_arg.mode) { case ControllerSupportMode::ShowControllerSupport: case ControllerSupportMode::ShowControllerStrapGuide: { - const auto user_arg_storage = broker.PopNormalDataToApplet(); + const std::shared_ptr<IStorage> user_arg_storage = PopInData(); ASSERT(user_arg_storage != nullptr); const auto& user_arg = user_arg_storage->GetData(); @@ -142,7 +144,7 @@ void Controller::Initialize() { break; } case ControllerSupportMode::ShowControllerFirmwareUpdate: { - const auto update_arg_storage = broker.PopNormalDataToApplet(); + const std::shared_ptr<IStorage> update_arg_storage = PopInData(); ASSERT(update_arg_storage != nullptr); const auto& update_arg = update_arg_storage->GetData(); @@ -152,7 +154,7 @@ void Controller::Initialize() { break; } case ControllerSupportMode::ShowControllerKeyRemappingForSystem: { - const auto remapping_arg_storage = broker.PopNormalDataToApplet(); + const std::shared_ptr<IStorage> remapping_arg_storage = PopInData(); ASSERT(remapping_arg_storage != nullptr); const auto& remapping_arg = remapping_arg_storage->GetData(); @@ -168,10 +170,6 @@ void Controller::Initialize() { } } -bool Controller::TransactionComplete() const { - return complete; -} - Result Controller::GetStatus() const { return status; } @@ -260,8 +258,9 @@ void Controller::ConfigurationComplete(bool is_success) { complete = true; out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo)); std::memcpy(out_data.data(), &result_info, out_data.size()); - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); - broker.SignalStateChanged(); + + PushOutData(std::make_shared<IStorage>(system, std::move(out_data))); + Exit(); } Result Controller::RequestExit() { @@ -269,4 +268,4 @@ Result Controller::RequestExit() { R_SUCCEED(); } -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_controller.h b/src/core/hle/service/am/frontend/applet_controller.h index 9f839f3d7..2f219429c 100644 --- a/src/core/hle/service/am/applets/applet_controller.h +++ b/src/core/hle/service/am/frontend/applet_controller.h @@ -9,7 +9,7 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "core/hle/result.h" -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applets.h" namespace Core { class System; @@ -19,7 +19,7 @@ namespace Core::HID { enum class NpadStyleSet : u32; } -namespace Service::AM::Applets { +namespace Service::AM::Frontend { using IdentificationColor = std::array<u8, 4>; using ExplainText = std::array<char, 0x81>; @@ -122,15 +122,15 @@ struct ControllerSupportResultInfo { static_assert(sizeof(ControllerSupportResultInfo) == 0xC, "ControllerSupportResultInfo has incorrect size."); -class Controller final : public Applet { +class Controller final : public FrontendApplet { public: - explicit Controller(Core::System& system_, LibraryAppletMode applet_mode_, + explicit Controller(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::ControllerApplet& frontend_); ~Controller() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -140,7 +140,6 @@ public: private: const Core::Frontend::ControllerApplet& frontend; - Core::System& system; ControllerAppletVersion controller_applet_version; ControllerSupportArgPrivate controller_private_arg; @@ -154,4 +153,4 @@ private: std::vector<u8> out_data; }; -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/frontend/applet_error.cpp index 084bc138c..b97a5f3ea 100644 --- a/src/core/hle/service/am/applets/applet_error.cpp +++ b/src/core/hle/service/am/frontend/applet_error.cpp @@ -9,10 +9,11 @@ #include "core/core.h" #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/frontend/applet_error.h" +#include "core/hle/service/am/storage.h" #include "core/reporter.h" -namespace Service::AM::Applets { +namespace Service::AM::Frontend { struct ErrorCode { u32 error_category{}; @@ -103,18 +104,18 @@ Result Decode64BitError(u64 error) { } // Anonymous namespace -Error::Error(Core::System& system_, LibraryAppletMode applet_mode_, +Error::Error(Core::System& system_, std::shared_ptr<Applet> applet_, LibraryAppletMode applet_mode_, const Core::Frontend::ErrorApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} Error::~Error() = default; void Error::Initialize() { - Applet::Initialize(); + FrontendApplet::Initialize(); args = std::make_unique<ErrorArguments>(); complete = false; - const auto storage = broker.PopNormalDataToApplet(); + const std::shared_ptr<IStorage> storage = PopInData(); ASSERT(storage != nullptr); const auto data = storage->GetData(); @@ -152,10 +153,6 @@ void Error::Initialize() { } } -bool Error::TransactionComplete() const { - return complete; -} - Result Error::GetStatus() const { return ResultSuccess; } @@ -210,8 +207,8 @@ void Error::Execute() { void Error::DisplayCompleted() { complete = true; - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{})); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); + Exit(); } Result Error::RequestExit() { @@ -219,4 +216,4 @@ Result Error::RequestExit() { R_SUCCEED(); } -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_error.h b/src/core/hle/service/am/frontend/applet_error.h index d822a32bb..678bf33fa 100644 --- a/src/core/hle/service/am/applets/applet_error.h +++ b/src/core/hle/service/am/frontend/applet_error.h @@ -4,13 +4,13 @@ #pragma once #include "core/hle/result.h" -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applets.h" namespace Core { class System; } -namespace Service::AM::Applets { +namespace Service::AM::Frontend { enum class ErrorAppletMode : u8 { ShowError = 0, @@ -22,15 +22,14 @@ enum class ErrorAppletMode : u8 { ShowUpdateEula = 8, }; -class Error final : public Applet { +class Error final : public FrontendApplet { public: - explicit Error(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::ErrorApplet& frontend_); + explicit Error(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::ErrorApplet& frontend_); ~Error() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -47,7 +46,6 @@ private: std::unique_ptr<ErrorArguments> args; bool complete = false; - Core::System& system; }; -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/frontend/applet_general.cpp index c0032f652..3c091a602 100644 --- a/src/core/hle/service/am/applets/applet_general_backend.cpp +++ b/src/core/hle/service/am/frontend/applet_general.cpp @@ -5,27 +5,28 @@ #include "common/hex_util.h" #include "common/logging/log.h" #include "core/core.h" -#include "core/frontend/applets/general_frontend.h" +#include "core/frontend/applets/general.h" #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/applet_data_broker.h" +#include "core/hle/service/am/frontend/applet_general.h" +#include "core/hle/service/am/storage.h" #include "core/reporter.h" -namespace Service::AM::Applets { +namespace Service::AM::Frontend { constexpr Result ERROR_INVALID_PIN{ErrorModule::PCTL, 221}; -static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) { - std::shared_ptr<IStorage> storage = broker.PopNormalDataToApplet(); - for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) { +static void LogCurrentStorage(std::shared_ptr<Applet> applet, std::string_view prefix) { + std::shared_ptr<IStorage> storage; + while (R_SUCCEEDED(applet->caller_applet_broker->GetInData().Pop(&storage))) { const auto data = storage->GetData(); LOG_INFO(Service_AM, "called (STUBBED), during {} received normal data with size={:08X}, data={}", prefix, data.size(), Common::HexToString(data)); } - storage = broker.PopInteractiveDataToApplet(); - for (; storage != nullptr; storage = broker.PopInteractiveDataToApplet()) { + while (R_SUCCEEDED(applet->caller_applet_broker->GetInteractiveInData().Pop(&storage))) { const auto data = storage->GetData(); LOG_INFO(Service_AM, "called (STUBBED), during {} received interactive data with size={:08X}, data={}", @@ -33,17 +34,17 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) } } -Auth::Auth(Core::System& system_, LibraryAppletMode applet_mode_, +Auth::Auth(Core::System& system_, std::shared_ptr<Applet> applet_, LibraryAppletMode applet_mode_, Core::Frontend::ParentalControlsApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} Auth::~Auth() = default; void Auth::Initialize() { - Applet::Initialize(); + FrontendApplet::Initialize(); complete = false; - const auto storage = broker.PopNormalDataToApplet(); + const std::shared_ptr<IStorage> storage = PopInData(); ASSERT(storage != nullptr); const auto data = storage->GetData(); ASSERT(data.size() >= 0xC); @@ -67,10 +68,6 @@ void Auth::Initialize() { arg2 = arg.arg2; } -bool Auth::TransactionComplete() const { - return complete; -} - Result Auth::GetStatus() const { return successful ? ResultSuccess : ERROR_INVALID_PIN; } @@ -146,8 +143,8 @@ void Auth::AuthFinished(bool is_successful) { std::vector<u8> out(sizeof(Return)); std::memcpy(out.data(), &return_, sizeof(Return)); - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out))); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::move(out))); + Exit(); } Result Auth::RequestExit() { @@ -155,27 +152,24 @@ Result Auth::RequestExit() { R_SUCCEED(); } -PhotoViewer::PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_, +PhotoViewer::PhotoViewer(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::PhotoViewerApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} PhotoViewer::~PhotoViewer() = default; void PhotoViewer::Initialize() { - Applet::Initialize(); + FrontendApplet::Initialize(); complete = false; - const auto storage = broker.PopNormalDataToApplet(); + const std::shared_ptr<IStorage> storage = PopInData(); ASSERT(storage != nullptr); const auto data = storage->GetData(); ASSERT(!data.empty()); mode = static_cast<PhotoViewerAppletMode>(data[0]); } -bool PhotoViewer::TransactionComplete() const { - return complete; -} - Result PhotoViewer::GetStatus() const { return ResultSuccess; } @@ -203,8 +197,8 @@ void PhotoViewer::Execute() { } void PhotoViewer::ViewFinished() { - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{})); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::vector<u8>{})); + Exit(); } Result PhotoViewer::RequestExit() { @@ -212,27 +206,17 @@ Result PhotoViewer::RequestExit() { R_SUCCEED(); } -StubApplet::StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_) - : Applet{system_, applet_mode_}, id{id_}, system{system_} {} +StubApplet::StubApplet(Core::System& system_, std::shared_ptr<Applet> applet_, AppletId id_, + LibraryAppletMode applet_mode_) + : FrontendApplet{system_, applet_, applet_mode_}, id{id_} {} StubApplet::~StubApplet() = default; void StubApplet::Initialize() { LOG_WARNING(Service_AM, "called (STUBBED)"); - Applet::Initialize(); + FrontendApplet::Initialize(); - const auto data = broker.PeekDataToAppletForDebug(); - system.GetReporter().SaveUnimplementedAppletReport( - static_cast<u32>(id), static_cast<u32>(common_args.arguments_version), - common_args.library_version, static_cast<u32>(common_args.theme_color), - common_args.play_startup_sound, common_args.system_tick, data.normal, data.interactive); - - LogCurrentStorage(broker, "Initialize"); -} - -bool StubApplet::TransactionComplete() const { - LOG_WARNING(Service_AM, "called (STUBBED)"); - return true; + LogCurrentStorage(applet.lock(), "Initialize"); } Result StubApplet::GetStatus() const { @@ -242,22 +226,20 @@ Result StubApplet::GetStatus() const { void StubApplet::ExecuteInteractive() { LOG_WARNING(Service_AM, "called (STUBBED)"); - LogCurrentStorage(broker, "ExecuteInteractive"); + LogCurrentStorage(applet.lock(), "ExecuteInteractive"); - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); - broker.PushInteractiveDataFromApplet( - std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); + Exit(); } void StubApplet::Execute() { LOG_WARNING(Service_AM, "called (STUBBED)"); - LogCurrentStorage(broker, "Execute"); + LogCurrentStorage(applet.lock(), "Execute"); - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); - broker.PushInteractiveDataFromApplet( - std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); + Exit(); } Result StubApplet::RequestExit() { @@ -265,4 +247,4 @@ Result StubApplet::RequestExit() { R_SUCCEED(); } -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_general_backend.h b/src/core/hle/service/am/frontend/applet_general.h index 34ecaebb9..eaa7ae25f 100644 --- a/src/core/hle/service/am/applets/applet_general_backend.h +++ b/src/core/hle/service/am/frontend/applet_general.h @@ -3,13 +3,13 @@ #pragma once -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applets.h" namespace Core { class System; } -namespace Service::AM::Applets { +namespace Service::AM::Frontend { enum class AuthAppletType : u32 { ShowParentalAuthentication, @@ -17,14 +17,14 @@ enum class AuthAppletType : u32 { ChangeParentalPasscode, }; -class Auth final : public Applet { +class Auth final : public FrontendApplet { public: - explicit Auth(Core::System& system_, LibraryAppletMode applet_mode_, + explicit Auth(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, Core::Frontend::ParentalControlsApplet& frontend_); ~Auth() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -34,7 +34,6 @@ public: private: Core::Frontend::ParentalControlsApplet& frontend; - Core::System& system; bool complete = false; bool successful = false; @@ -49,14 +48,14 @@ enum class PhotoViewerAppletMode : u8 { AllApps = 1, }; -class PhotoViewer final : public Applet { +class PhotoViewer final : public FrontendApplet { public: - explicit PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_, + explicit PhotoViewer(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::PhotoViewerApplet& frontend_); ~PhotoViewer() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -68,17 +67,16 @@ private: const Core::Frontend::PhotoViewerApplet& frontend; bool complete = false; PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp; - Core::System& system; }; -class StubApplet final : public Applet { +class StubApplet final : public FrontendApplet { public: - explicit StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_); + explicit StubApplet(Core::System& system_, std::shared_ptr<Applet> applet_, AppletId id_, + LibraryAppletMode applet_mode_); ~StubApplet() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -86,7 +84,6 @@ public: private: AppletId id; - Core::System& system; }; -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_mii_edit.cpp b/src/core/hle/service/am/frontend/applet_mii_edit.cpp index e83e931c5..e3d19fb3d 100644 --- a/src/core/hle/service/am/applets/applet_mii_edit.cpp +++ b/src/core/hle/service/am/frontend/applet_mii_edit.cpp @@ -6,16 +6,17 @@ #include "core/core.h" #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/frontend/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" -namespace Service::AM::Applets { +namespace Service::AM::Frontend { -MiiEdit::MiiEdit(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::MiiEditApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} +MiiEdit::MiiEdit(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::MiiEditApplet& frontend_) + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} MiiEdit::~MiiEdit() = default; @@ -24,7 +25,7 @@ void MiiEdit::Initialize() { // Instead, it is initialized by an AppletInput storage with size 0x100 bytes. // Do NOT call Applet::Initialize() here. - const auto storage = broker.PopNormalDataToApplet(); + const std::shared_ptr<IStorage> storage = PopInData(); ASSERT(storage != nullptr); const auto applet_input_data = storage->GetData(); @@ -66,10 +67,6 @@ void MiiEdit::Initialize() { manager->Initialize(metadata); } -bool MiiEdit::TransactionComplete() const { - return is_complete; -} - Result MiiEdit::GetStatus() const { return ResultSuccess; } @@ -152,8 +149,8 @@ void MiiEdit::MiiEditOutput(MiiEditResult result, s32 index) { is_complete = true; - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::move(out_data))); + Exit(); } void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result, @@ -168,8 +165,8 @@ void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result, is_complete = true; - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::move(out_data))); + Exit(); } Result MiiEdit::RequestExit() { @@ -177,4 +174,4 @@ Result MiiEdit::RequestExit() { R_SUCCEED(); } -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_mii_edit.h b/src/core/hle/service/am/frontend/applet_mii_edit.h index 7ff34af49..5db792f7d 100644 --- a/src/core/hle/service/am/applets/applet_mii_edit.h +++ b/src/core/hle/service/am/frontend/applet_mii_edit.h @@ -4,8 +4,8 @@ #pragma once #include "core/hle/result.h" -#include "core/hle/service/am/applets/applet_mii_edit_types.h" -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applet_mii_edit_types.h" +#include "core/hle/service/am/frontend/applets.h" namespace Core { class System; @@ -16,17 +16,17 @@ struct DatabaseSessionMetadata; class MiiManager; } // namespace Service::Mii -namespace Service::AM::Applets { +namespace Service::AM::Frontend { -class MiiEdit final : public Applet { +class MiiEdit final : public FrontendApplet { public: - explicit MiiEdit(Core::System& system_, LibraryAppletMode applet_mode_, + explicit MiiEdit(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::MiiEditApplet& frontend_); ~MiiEdit() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -38,7 +38,6 @@ public: private: const Core::Frontend::MiiEditApplet& frontend; - Core::System& system; MiiEditAppletInputCommon applet_input_common{}; MiiEditAppletInputV3 applet_input_v3{}; @@ -49,4 +48,4 @@ private: Mii::DatabaseSessionMetadata metadata{}; }; -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_mii_edit_types.h b/src/core/hle/service/am/frontend/applet_mii_edit_types.h index f3d764073..23d9d7a69 100644 --- a/src/core/hle/service/am/applets/applet_mii_edit_types.h +++ b/src/core/hle/service/am/frontend/applet_mii_edit_types.h @@ -10,7 +10,7 @@ #include "common/uuid.h" #include "core/hle/service/mii/types/char_info.h" -namespace Service::AM::Applets { +namespace Service::AM::Frontend { enum class MiiEditAppletVersion : s32 { Version3 = 0x3, // 1.0.0 - 10.1.1 @@ -80,4 +80,4 @@ struct MiiEditAppletOutputForCharInfoEditing { static_assert(sizeof(MiiEditAppletOutputForCharInfoEditing) == 0x80, "MiiEditAppletOutputForCharInfoEditing has incorrect size."); -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_profile_select.cpp b/src/core/hle/service/am/frontend/applet_profile_select.cpp index 89cb323e9..efb4053b8 100644 --- a/src/core/hle/service/am/applets/applet_profile_select.cpp +++ b/src/core/hle/service/am/frontend/applet_profile_select.cpp @@ -9,13 +9,15 @@ #include "core/frontend/applets/profile_select.h" #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/frontend/applet_profile_select.h" +#include "core/hle/service/am/storage.h" -namespace Service::AM::Applets { +namespace Service::AM::Frontend { -ProfileSelect::ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_, +ProfileSelect::ProfileSelect(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::ProfileSelectApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} ProfileSelect::~ProfileSelect() = default; @@ -24,10 +26,10 @@ void ProfileSelect::Initialize() { status = ResultSuccess; final_data.clear(); - Applet::Initialize(); + FrontendApplet::Initialize(); profile_select_version = ProfileSelectAppletVersion{common_args.library_version}; - const auto user_config_storage = broker.PopNormalDataToApplet(); + const std::shared_ptr<IStorage> user_config_storage = PopInData(); ASSERT(user_config_storage != nullptr); const auto& user_config = user_config_storage->GetData(); @@ -50,10 +52,6 @@ void ProfileSelect::Initialize() { } } -bool ProfileSelect::TransactionComplete() const { - return complete; -} - Result ProfileSelect::GetStatus() const { return status; } @@ -64,7 +62,8 @@ void ProfileSelect::ExecuteInteractive() { void ProfileSelect::Execute() { if (complete) { - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data))); + PushOutData(std::make_shared<IStorage>(system, std::move(final_data))); + Exit(); return; } @@ -111,8 +110,9 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) { final_data = std::vector<u8>(sizeof(UiReturnArg)); std::memcpy(final_data.data(), &output, final_data.size()); - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data))); - broker.SignalStateChanged(); + + PushOutData(std::make_shared<IStorage>(system, std::move(final_data))); + Exit(); } Result ProfileSelect::RequestExit() { @@ -120,4 +120,4 @@ Result ProfileSelect::RequestExit() { R_SUCCEED(); } -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_profile_select.h b/src/core/hle/service/am/frontend/applet_profile_select.h index 673eed516..674e7afe1 100644 --- a/src/core/hle/service/am/applets/applet_profile_select.h +++ b/src/core/hle/service/am/frontend/applet_profile_select.h @@ -8,13 +8,13 @@ #include "common/common_funcs.h" #include "common/uuid.h" #include "core/hle/result.h" -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applets.h" namespace Core { class System; } -namespace Service::AM::Applets { +namespace Service::AM::Frontend { enum class ProfileSelectAppletVersion : u32 { Version1 = 0x1, // 1.0.0+ @@ -111,15 +111,15 @@ struct UiReturnArg { }; static_assert(sizeof(UiReturnArg) == 0x18, "UiReturnArg has incorrect size."); -class ProfileSelect final : public Applet { +class ProfileSelect final : public FrontendApplet { public: - explicit ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_, + explicit ProfileSelect(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::ProfileSelectApplet& frontend_); ~ProfileSelect() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -137,7 +137,6 @@ private: bool complete = false; Result status = ResultSuccess; std::vector<u8> final_data; - Core::System& system; }; -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.cpp b/src/core/hle/service/am/frontend/applet_software_keyboard.cpp index 4145bb84f..fbf75d379 100644 --- a/src/core/hle/service/am/applets/applet_software_keyboard.cpp +++ b/src/core/hle/service/am/frontend/applet_software_keyboard.cpp @@ -5,9 +5,10 @@ #include "core/core.h" #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/frontend/applet_software_keyboard.h" +#include "core/hle/service/am/storage.h" -namespace Service::AM::Applets { +namespace Service::AM::Frontend { namespace { @@ -41,14 +42,15 @@ void SetReplyBase(std::vector<u8>& reply, SwkbdState state, SwkbdReplyType reply } // Anonymous namespace -SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_, +SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, Core::Frontend::SoftwareKeyboardApplet& frontend_) - : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {} SoftwareKeyboard::~SoftwareKeyboard() = default; void SoftwareKeyboard::Initialize() { - Applet::Initialize(); + FrontendApplet::Initialize(); LOG_INFO(Service_AM, "Initializing Software Keyboard Applet with LibraryAppletMode={}", applet_mode); @@ -76,10 +78,6 @@ void SoftwareKeyboard::Initialize() { } } -bool SoftwareKeyboard::TransactionComplete() const { - return complete; -} - Result SoftwareKeyboard::GetStatus() const { return status; } @@ -184,7 +182,7 @@ void SoftwareKeyboard::InitializeForeground() { is_background = false; - const auto swkbd_config_storage = broker.PopNormalDataToApplet(); + const auto swkbd_config_storage = PopInData(); ASSERT(swkbd_config_storage != nullptr); const auto& swkbd_config_data = swkbd_config_storage->GetData(); @@ -221,7 +219,7 @@ void SoftwareKeyboard::InitializeForeground() { break; } - const auto work_buffer_storage = broker.PopNormalDataToApplet(); + const auto work_buffer_storage = PopInData(); ASSERT(work_buffer_storage != nullptr); if (swkbd_config_common.initial_string_length == 0) { @@ -250,7 +248,7 @@ void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mod is_background = true; - const auto swkbd_inline_initialize_arg_storage = broker.PopNormalDataToApplet(); + const auto swkbd_inline_initialize_arg_storage = PopInData(); ASSERT(swkbd_inline_initialize_arg_storage != nullptr); const auto& swkbd_inline_initialize_arg = swkbd_inline_initialize_arg_storage->GetData(); @@ -267,7 +265,7 @@ void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mod } void SoftwareKeyboard::ProcessTextCheck() { - const auto text_check_storage = broker.PopInteractiveDataToApplet(); + const auto text_check_storage = PopInteractiveInData(); ASSERT(text_check_storage != nullptr); const auto& text_check_data = text_check_storage->GetData(); @@ -314,7 +312,7 @@ void SoftwareKeyboard::ProcessTextCheck() { } void SoftwareKeyboard::ProcessInlineKeyboardRequest() { - const auto request_data_storage = broker.PopInteractiveDataToApplet(); + const auto request_data_storage = PopInteractiveInData(); ASSERT(request_data_storage != nullptr); const auto& request_data = request_data_storage->GetData(); @@ -377,7 +375,7 @@ void SoftwareKeyboard::SubmitNormalOutputAndExit(SwkbdResult result, submitted_text.size() * sizeof(char16_t)); } - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); + PushOutData(std::make_shared<IStorage>(system, std::move(out_data))); ExitKeyboard(); } @@ -410,7 +408,7 @@ void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) { current_text.size() * sizeof(char16_t)); } - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(out_data))); } void SoftwareKeyboard::SendReply(SwkbdReplyType reply_type) { @@ -767,7 +765,7 @@ void SoftwareKeyboard::ExitKeyboard() { frontend.ExitKeyboard(); - broker.SignalStateChanged(); + Exit(); } Result SoftwareKeyboard::RequestExit() { @@ -967,7 +965,7 @@ void SoftwareKeyboard::ReplyFinishedInitialize() { SetReplyBase(reply, swkbd_state, SwkbdReplyType::FinishedInitialize); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyDefault() { @@ -977,7 +975,7 @@ void SoftwareKeyboard::ReplyDefault() { SetReplyBase(reply, swkbd_state, SwkbdReplyType::Default); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyChangedString() { @@ -999,7 +997,7 @@ void SoftwareKeyboard::ReplyChangedString() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg, sizeof(SwkbdChangedStringArg)); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyMovedCursor() { @@ -1019,7 +1017,7 @@ void SoftwareKeyboard::ReplyMovedCursor() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg, sizeof(SwkbdMovedCursorArg)); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyMovedTab() { @@ -1039,7 +1037,7 @@ void SoftwareKeyboard::ReplyMovedTab() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_tab_arg, sizeof(SwkbdMovedTabArg)); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyDecidedEnter() { @@ -1058,7 +1056,7 @@ void SoftwareKeyboard::ReplyDecidedEnter() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &decided_enter_arg, sizeof(SwkbdDecidedEnterArg)); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); HideInlineKeyboard(); } @@ -1070,7 +1068,7 @@ void SoftwareKeyboard::ReplyDecidedCancel() { SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedCancel); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); HideInlineKeyboard(); } @@ -1095,7 +1093,7 @@ void SoftwareKeyboard::ReplyChangedStringUtf8() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg, sizeof(SwkbdChangedStringArg)); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyMovedCursorUtf8() { @@ -1116,7 +1114,7 @@ void SoftwareKeyboard::ReplyMovedCursorUtf8() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg, sizeof(SwkbdMovedCursorArg)); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyDecidedEnterUtf8() { @@ -1136,7 +1134,7 @@ void SoftwareKeyboard::ReplyDecidedEnterUtf8() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &decided_enter_arg, sizeof(SwkbdDecidedEnterArg)); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); HideInlineKeyboard(); } @@ -1148,7 +1146,7 @@ void SoftwareKeyboard::ReplyUnsetCustomizeDic() { SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizeDic); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyReleasedUserWordInfo() { @@ -1158,7 +1156,7 @@ void SoftwareKeyboard::ReplyReleasedUserWordInfo() { SetReplyBase(reply, swkbd_state, SwkbdReplyType::ReleasedUserWordInfo); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() { @@ -1168,7 +1166,7 @@ void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() { SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizedDictionaries); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyChangedStringV2() { @@ -1194,7 +1192,7 @@ void SoftwareKeyboard::ReplyChangedStringV2() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg), &flag, 1); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyMovedCursorV2() { @@ -1218,7 +1216,7 @@ void SoftwareKeyboard::ReplyMovedCursorV2() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg), &flag, 1); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyChangedStringUtf8V2() { @@ -1245,7 +1243,7 @@ void SoftwareKeyboard::ReplyChangedStringUtf8V2() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg), &flag, 1); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } void SoftwareKeyboard::ReplyMovedCursorUtf8V2() { @@ -1270,7 +1268,7 @@ void SoftwareKeyboard::ReplyMovedCursorUtf8V2() { std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg), &flag, 1); - broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); + PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply))); } -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.h b/src/core/hle/service/am/frontend/applet_software_keyboard.h index 2e919811b..f464b7e15 100644 --- a/src/core/hle/service/am/applets/applet_software_keyboard.h +++ b/src/core/hle/service/am/frontend/applet_software_keyboard.h @@ -5,8 +5,8 @@ #include "common/common_types.h" #include "core/hle/result.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/frontend/applet_software_keyboard_types.h" +#include "core/hle/service/am/frontend/applets.h" namespace Core { class System; @@ -17,17 +17,17 @@ struct KeyboardInitializeParameters; struct InlineAppearParameters; } // namespace Core::Frontend -namespace Service::AM::Applets { +namespace Service::AM::Frontend { -class SoftwareKeyboard final : public Applet { +class SoftwareKeyboard final : public FrontendApplet { public: - explicit SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_, + explicit SoftwareKeyboard(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, Core::Frontend::SoftwareKeyboardApplet& frontend_); ~SoftwareKeyboard() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -156,7 +156,6 @@ private: void ReplyMovedCursorUtf8V2(); Core::Frontend::SoftwareKeyboardApplet& frontend; - Core::System& system; SwkbdAppletVersion swkbd_applet_version; @@ -184,4 +183,4 @@ private: Result status{ResultSuccess}; }; -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_software_keyboard_types.h b/src/core/hle/service/am/frontend/applet_software_keyboard_types.h index 1f696900e..a25ff2a6d 100644 --- a/src/core/hle/service/am/applets/applet_software_keyboard_types.h +++ b/src/core/hle/service/am/frontend/applet_software_keyboard_types.h @@ -11,7 +11,7 @@ #include "common/swap.h" #include "common/uuid.h" -namespace Service::AM::Applets { +namespace Service::AM::Frontend { constexpr std::size_t MAX_OK_TEXT_LENGTH = 8; constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64; @@ -351,4 +351,4 @@ struct SwkbdDecidedEnterArg { }; static_assert(sizeof(SwkbdDecidedEnterArg) == 0x4, "SwkbdDecidedEnterArg has incorrect size."); -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/frontend/applet_web_browser.cpp index 19057ad7b..6ee4caf34 100644 --- a/src/core/hle/service/am/applets/applet_web_browser.cpp +++ b/src/core/hle/service/am/frontend/applet_web_browser.cpp @@ -19,12 +19,13 @@ #include "core/frontend/applets/web_browser.h" #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/frontend/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" -namespace Service::AM::Applets { +namespace Service::AM::Frontend { namespace { @@ -223,14 +224,15 @@ void ExtractSharedFonts(Core::System& system) { } // namespace -WebBrowser::WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_, +WebBrowser::WebBrowser(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::WebBrowserApplet& frontend_) - : Applet{system_, applet_mode_}, frontend(frontend_), system{system_} {} + : FrontendApplet{system_, applet_, applet_mode_}, frontend(frontend_) {} WebBrowser::~WebBrowser() = default; void WebBrowser::Initialize() { - Applet::Initialize(); + FrontendApplet::Initialize(); LOG_INFO(Service_AM, "Initializing Web Browser Applet."); @@ -243,7 +245,7 @@ void WebBrowser::Initialize() { web_applet_version = WebAppletVersion{common_args.library_version}; - const auto web_arg_storage = broker.PopNormalDataToApplet(); + const auto web_arg_storage = PopInData(); ASSERT(web_arg_storage != nullptr); const auto& web_arg = web_arg_storage->GetData(); @@ -284,10 +286,6 @@ void WebBrowser::Initialize() { } } -bool WebBrowser::TransactionComplete() const { - return complete; -} - Result WebBrowser::GetStatus() const { return status; } @@ -358,8 +356,8 @@ void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url) complete = true; std::vector<u8> out_data(sizeof(WebCommonReturnValue)); std::memcpy(out_data.data(), &web_common_return_value, out_data.size()); - broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); - broker.SignalStateChanged(); + PushOutData(std::make_shared<IStorage>(system, std::move(out_data))); + Exit(); } Result WebBrowser::RequestExit() { @@ -504,4 +502,4 @@ void WebBrowser::ExecuteLobby() { LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented"); WebBrowserExit(WebExitReason::EndButtonPressed); } -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_web_browser.h b/src/core/hle/service/am/frontend/applet_web_browser.h index 36adb2510..ba20b7a4c 100644 --- a/src/core/hle/service/am/applets/applet_web_browser.h +++ b/src/core/hle/service/am/frontend/applet_web_browser.h @@ -9,8 +9,8 @@ #include "common/common_types.h" #include "core/file_sys/vfs/vfs_types.h" #include "core/hle/result.h" -#include "core/hle/service/am/applets/applet_web_browser_types.h" -#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/frontend/applet_web_browser_types.h" +#include "core/hle/service/am/frontend/applets.h" namespace Core { class System; @@ -20,18 +20,17 @@ namespace FileSys { enum class ContentRecordType : u8; } -namespace Service::AM::Applets { +namespace Service::AM::Frontend { -class WebBrowser final : public Applet { +class WebBrowser final : public FrontendApplet { public: - WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_, - const Core::Frontend::WebBrowserApplet& frontend_); + WebBrowser(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_, const Core::Frontend::WebBrowserApplet& frontend_); ~WebBrowser() override; void Initialize() override; - bool TransactionComplete() const override; Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; @@ -80,8 +79,6 @@ private: FileSys::VirtualFile offline_romfs; std::string external_url; - - Core::System& system; }; -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/applets/applet_web_browser_types.h b/src/core/hle/service/am/frontend/applet_web_browser_types.h index c522c5c1a..2f7c05c24 100644 --- a/src/core/hle/service/am/applets/applet_web_browser_types.h +++ b/src/core/hle/service/am/frontend/applet_web_browser_types.h @@ -11,7 +11,7 @@ #include "common/common_types.h" #include "common/swap.h" -namespace Service::AM::Applets { +namespace Service::AM::Frontend { enum class WebAppletVersion : u32_le { Version0 = 0x0, // Only used by WifiWebAuthApplet @@ -174,4 +174,4 @@ static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has using WebArgInputTLVMap = std::unordered_map<WebArgInputTLVType, std::vector<u8>>; -} // namespace Service::AM::Applets +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applets.cpp b/src/core/hle/service/am/frontend/applets.cpp new file mode 100644 index 000000000..db2b04575 --- /dev/null +++ b/src/core/hle/service/am/frontend/applets.cpp @@ -0,0 +1,240 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <cstring> + +#include "common/assert.h" +#include "core/core.h" +#include "core/frontend/applets/cabinet.h" +#include "core/frontend/applets/controller.h" +#include "core/frontend/applets/error.h" +#include "core/frontend/applets/general.h" +#include "core/frontend/applets/mii_edit.h" +#include "core/frontend/applets/profile_select.h" +#include "core/frontend/applets/software_keyboard.h" +#include "core/frontend/applets/web_browser.h" +#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_data_broker.h" +#include "core/hle/service/am/applet_manager.h" +#include "core/hle/service/am/applet_message_queue.h" +#include "core/hle/service/am/applet_oe.h" +#include "core/hle/service/am/frontend/applet_cabinet.h" +#include "core/hle/service/am/frontend/applet_controller.h" +#include "core/hle/service/am/frontend/applet_error.h" +#include "core/hle/service/am/frontend/applet_general.h" +#include "core/hle/service/am/frontend/applet_mii_edit.h" +#include "core/hle/service/am/frontend/applet_profile_select.h" +#include "core/hle/service/am/frontend/applet_software_keyboard.h" +#include "core/hle/service/am/frontend/applet_web_browser.h" +#include "core/hle/service/am/frontend/applets.h" +#include "core/hle/service/am/storage.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::AM::Frontend { + +FrontendApplet::FrontendApplet(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_) + : system{system_}, applet{std::move(applet_)}, applet_mode{applet_mode_} {} + +FrontendApplet::~FrontendApplet() = default; + +void FrontendApplet::Initialize() { + std::shared_ptr<IStorage> common = PopInData(); + ASSERT(common != nullptr); + const auto common_data = common->GetData(); + + ASSERT(common_data.size() >= sizeof(CommonArguments)); + std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments)); + + initialized = true; +} + +std::shared_ptr<IStorage> FrontendApplet::PopInData() { + std::shared_ptr<IStorage> ret; + applet.lock()->caller_applet_broker->GetInData().Pop(&ret); + return ret; +} + +std::shared_ptr<IStorage> FrontendApplet::PopInteractiveInData() { + std::shared_ptr<IStorage> ret; + applet.lock()->caller_applet_broker->GetInteractiveInData().Pop(&ret); + return ret; +} + +void FrontendApplet::PushOutData(std::shared_ptr<IStorage> storage) { + applet.lock()->caller_applet_broker->GetOutData().Push(storage); +} + +void FrontendApplet::PushInteractiveOutData(std::shared_ptr<IStorage> storage) { + applet.lock()->caller_applet_broker->GetInteractiveOutData().Push(storage); +} + +void FrontendApplet::Exit() { + applet.lock()->caller_applet_broker->SignalCompletion(); +} + +FrontendAppletSet::FrontendAppletSet() = default; + +FrontendAppletSet::FrontendAppletSet(CabinetApplet cabinet_applet, + ControllerApplet controller_applet, ErrorApplet error_applet, + MiiEdit mii_edit_, + ParentalControlsApplet parental_controls_applet, + PhotoViewer photo_viewer_, ProfileSelect profile_select_, + SoftwareKeyboard software_keyboard_, WebBrowser web_browser_) + : cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)}, + error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)}, + parental_controls{std::move(parental_controls_applet)}, + photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)}, + software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {} + +FrontendAppletSet::~FrontendAppletSet() = default; + +FrontendAppletSet::FrontendAppletSet(FrontendAppletSet&&) noexcept = default; + +FrontendAppletSet& FrontendAppletSet::operator=(FrontendAppletSet&&) noexcept = default; + +FrontendAppletHolder::FrontendAppletHolder(Core::System& system_) : system{system_} {} + +FrontendAppletHolder::~FrontendAppletHolder() = default; + +const FrontendAppletSet& FrontendAppletHolder::GetFrontendAppletSet() const { + return frontend; +} + +NFP::CabinetMode FrontendAppletHolder::GetCabinetMode() const { + return cabinet_mode; +} + +AppletId FrontendAppletHolder::GetCurrentAppletId() const { + return current_applet_id; +} + +void FrontendAppletHolder::SetFrontendAppletSet(FrontendAppletSet set) { + if (set.cabinet != nullptr) { + frontend.cabinet = std::move(set.cabinet); + } + + if (set.controller != nullptr) { + frontend.controller = std::move(set.controller); + } + + if (set.error != nullptr) { + frontend.error = std::move(set.error); + } + + if (set.mii_edit != nullptr) { + frontend.mii_edit = std::move(set.mii_edit); + } + + if (set.parental_controls != nullptr) { + frontend.parental_controls = std::move(set.parental_controls); + } + + if (set.photo_viewer != nullptr) { + frontend.photo_viewer = std::move(set.photo_viewer); + } + + if (set.profile_select != nullptr) { + frontend.profile_select = std::move(set.profile_select); + } + + if (set.software_keyboard != nullptr) { + frontend.software_keyboard = std::move(set.software_keyboard); + } + + if (set.web_browser != nullptr) { + frontend.web_browser = std::move(set.web_browser); + } +} + +void FrontendAppletHolder::SetCabinetMode(NFP::CabinetMode mode) { + cabinet_mode = mode; +} + +void FrontendAppletHolder::SetCurrentAppletId(AppletId applet_id) { + current_applet_id = applet_id; +} + +void FrontendAppletHolder::SetDefaultAppletsIfMissing() { + if (frontend.cabinet == nullptr) { + frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>(); + } + + if (frontend.controller == nullptr) { + frontend.controller = + std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore()); + } + + if (frontend.error == nullptr) { + frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>(); + } + + if (frontend.mii_edit == nullptr) { + frontend.mii_edit = std::make_unique<Core::Frontend::DefaultMiiEditApplet>(); + } + + if (frontend.parental_controls == nullptr) { + frontend.parental_controls = + std::make_unique<Core::Frontend::DefaultParentalControlsApplet>(); + } + + if (frontend.photo_viewer == nullptr) { + frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>(); + } + + if (frontend.profile_select == nullptr) { + frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>(); + } + + if (frontend.software_keyboard == nullptr) { + frontend.software_keyboard = + std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>(); + } + + if (frontend.web_browser == nullptr) { + frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); + } +} + +void FrontendAppletHolder::ClearAll() { + frontend = {}; +} + +std::shared_ptr<FrontendApplet> FrontendAppletHolder::GetApplet(std::shared_ptr<Applet> applet, + AppletId id, + LibraryAppletMode mode) const { + switch (id) { + case AppletId::Auth: + return std::make_shared<Auth>(system, applet, mode, *frontend.parental_controls); + case AppletId::Cabinet: + return std::make_shared<Cabinet>(system, applet, mode, *frontend.cabinet); + case AppletId::Controller: + return std::make_shared<Controller>(system, applet, mode, *frontend.controller); + case AppletId::Error: + return std::make_shared<Error>(system, applet, mode, *frontend.error); + case AppletId::ProfileSelect: + return std::make_shared<ProfileSelect>(system, applet, mode, *frontend.profile_select); + case AppletId::SoftwareKeyboard: + return std::make_shared<SoftwareKeyboard>(system, applet, mode, + *frontend.software_keyboard); + case AppletId::MiiEdit: + return std::make_shared<MiiEdit>(system, applet, mode, *frontend.mii_edit); + case AppletId::Web: + case AppletId::Shop: + case AppletId::OfflineWeb: + case AppletId::LoginShare: + case AppletId::WebAuth: + return std::make_shared<WebBrowser>(system, applet, mode, *frontend.web_browser); + case AppletId::PhotoViewer: + return std::make_shared<PhotoViewer>(system, applet, mode, *frontend.photo_viewer); + default: + UNIMPLEMENTED_MSG( + "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", + static_cast<u8>(id)); + return std::make_shared<StubApplet>(system, applet, id, mode); + } +} + +} // namespace Service::AM::Frontend diff --git a/src/core/hle/service/am/frontend/applets.h b/src/core/hle/service/am/frontend/applets.h new file mode 100644 index 000000000..1e1fd28b8 --- /dev/null +++ b/src/core/hle/service/am/frontend/applets.h @@ -0,0 +1,146 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <memory> +#include <queue> + +#include "common/swap.h" +#include "core/hle/service/am/applet.h" + +union Result; + +namespace Core { +class System; +} + +namespace Core::Frontend { +class CabinetApplet; +class ControllerApplet; +class ECommerceApplet; +class ErrorApplet; +class MiiEditApplet; +class ParentalControlsApplet; +class PhotoViewerApplet; +class ProfileSelectApplet; +class SoftwareKeyboardApplet; +class WebBrowserApplet; +} // namespace Core::Frontend + +namespace Kernel { +class KernelCore; +class KEvent; +class KReadableEvent; +} // namespace Kernel + +namespace Service::NFP { +enum class CabinetMode : u8; +} // namespace Service::NFP + +namespace Service::AM { + +class IStorage; + +namespace Frontend { + +class FrontendApplet { +public: + explicit FrontendApplet(Core::System& system_, std::shared_ptr<Applet> applet_, + LibraryAppletMode applet_mode_); + virtual ~FrontendApplet(); + + virtual void Initialize(); + + virtual Result GetStatus() const = 0; + virtual void ExecuteInteractive() = 0; + virtual void Execute() = 0; + virtual Result RequestExit() = 0; + + LibraryAppletMode GetLibraryAppletMode() const { + return applet_mode; + } + + bool IsInitialized() const { + return initialized; + } + +protected: + std::shared_ptr<IStorage> PopInData(); + std::shared_ptr<IStorage> PopInteractiveInData(); + void PushOutData(std::shared_ptr<IStorage> storage); + void PushInteractiveOutData(std::shared_ptr<IStorage> storage); + void Exit(); + +protected: + Core::System& system; + CommonArguments common_args{}; + std::weak_ptr<Applet> applet{}; + LibraryAppletMode applet_mode{}; + bool initialized{false}; +}; + +struct FrontendAppletSet { + using CabinetApplet = std::unique_ptr<Core::Frontend::CabinetApplet>; + using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>; + using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; + using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>; + using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>; + using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>; + using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>; + using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>; + using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; + + FrontendAppletSet(); + FrontendAppletSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet, + ErrorApplet error_applet, MiiEdit mii_edit_, + ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_, + ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_, + WebBrowser web_browser_); + ~FrontendAppletSet(); + + FrontendAppletSet(const FrontendAppletSet&) = delete; + FrontendAppletSet& operator=(const FrontendAppletSet&) = delete; + + FrontendAppletSet(FrontendAppletSet&&) noexcept; + FrontendAppletSet& operator=(FrontendAppletSet&&) noexcept; + + CabinetApplet cabinet; + ControllerApplet controller; + ErrorApplet error; + MiiEdit mii_edit; + ParentalControlsApplet parental_controls; + PhotoViewer photo_viewer; + ProfileSelect profile_select; + SoftwareKeyboard software_keyboard; + WebBrowser web_browser; +}; + +class FrontendAppletHolder { +public: + explicit FrontendAppletHolder(Core::System& system_); + ~FrontendAppletHolder(); + + const FrontendAppletSet& GetFrontendAppletSet() const; + NFP::CabinetMode GetCabinetMode() const; + AppletId GetCurrentAppletId() const; + + void SetFrontendAppletSet(FrontendAppletSet set); + void SetCabinetMode(NFP::CabinetMode mode); + void SetCurrentAppletId(AppletId applet_id); + void SetDefaultAppletsIfMissing(); + void ClearAll(); + + std::shared_ptr<FrontendApplet> GetApplet(std::shared_ptr<Applet> applet, AppletId id, + LibraryAppletMode mode) const; + +private: + AppletId current_applet_id{}; + NFP::CabinetMode cabinet_mode{}; + + FrontendAppletSet frontend; + Core::System& system; +}; + +} // namespace Frontend +} // 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/hid_registration.cpp b/src/core/hle/service/am/hid_registration.cpp new file mode 100644 index 000000000..8ed49bac1 --- /dev/null +++ b/src/core/hle/service/am/hid_registration.cpp @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/service/am/hid_registration.h" +#include "core/hle/service/am/process.h" +#include "core/hle/service/hid/hid_server.h" +#include "core/hle/service/sm/sm.h" +#include "hid_core/resource_manager.h" + +namespace Service::AM { + +HidRegistration::HidRegistration(Core::System& system, Process& process) : m_process(process) { + m_hid_server = system.ServiceManager().GetService<HID::IHidServer>("hid"); + + if (m_process.IsInitialized()) { + m_hid_server->GetResourceManager()->RegisterAppletResourceUserId(m_process.GetProcessId(), + true); + } +} + +HidRegistration::~HidRegistration() { + if (m_process.IsInitialized()) { + m_hid_server->GetResourceManager()->UnregisterAppletResourceUserId( + m_process.GetProcessId()); + } +} + +void HidRegistration::EnableAppletToGetInput(bool enable) { + if (m_process.IsInitialized()) { + m_hid_server->GetResourceManager()->EnableInput(m_process.GetProcessId(), enable); + } +} + +} // 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..67cd84961 --- /dev/null +++ b/src/core/hle/service/am/hid_registration.h @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <memory> + +namespace Core { +class System; +} + +namespace Service::HID { +class IHidServer; +} + +namespace Service::AM { + +class Process; + +class HidRegistration { +public: + explicit HidRegistration(Core::System& system, Process& process); + ~HidRegistration(); + + void EnableAppletToGetInput(bool enable); + +private: + Process& m_process; + std::shared_ptr<Service::HID::IHidServer> m_hid_server; +}; + +} // 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..6b20814f8 --- /dev/null +++ b/src/core/hle/service/am/library_applet_accessor.cpp @@ -0,0 +1,202 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/scope_exit.h" +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/applet_data_broker.h" +#include "core/hle/service/am/frontend/applets.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<AppletDataBroker> broker_, + std::shared_ptr<Applet> applet_) + : ServiceFramework{system_, "ILibraryAppletAccessor"}, broker{std::move(broker_)}, + 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); +} + +ILibraryAppletAccessor::~ILibraryAppletAccessor() = default; + +void ILibraryAppletAccessor::GetAppletStateChangedEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(broker->GetStateChangedEvent().GetHandle()); +} + +void ILibraryAppletAccessor::IsCompleted(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + std::scoped_lock lk{applet->lock}; + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u32>(broker->IsCompleted()); +} + +void ILibraryAppletAccessor::GetResult(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(applet->terminate_result); +} + +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"); + + applet->process->Run(); + FrontendExecute(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletAccessor::RequestExit(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + ASSERT(applet != nullptr); + applet->message_queue.RequestExit(); + FrontendRequestExit(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletAccessor::PushInData(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::RequestParser rp{ctx}; + broker->GetInData().Push(rp.PopIpcInterface<IStorage>().lock()); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletAccessor::PopOutData(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + std::shared_ptr<IStorage> data; + const auto res = broker->GetOutData().Pop(&data); + + if (res.IsSuccess()) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface(std::move(data)); + } else { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); + } +} + +void ILibraryAppletAccessor::PushInteractiveInData(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::RequestParser rp{ctx}; + broker->GetInteractiveInData().Push(rp.PopIpcInterface<IStorage>().lock()); + FrontendExecuteInteractive(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletAccessor::PopInteractiveOutData(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + std::shared_ptr<IStorage> data; + const auto res = broker->GetInteractiveOutData().Pop(&data); + + if (res.IsSuccess()) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface(std::move(data)); + } else { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); + } +} + +void ILibraryAppletAccessor::GetPopOutDataEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(broker->GetOutData().GetEvent()); +} + +void ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(broker->GetInteractiveOutData().GetEvent()); +} + +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); +} + +void ILibraryAppletAccessor::FrontendExecute() { + if (applet->frontend) { + applet->frontend->Initialize(); + applet->frontend->Execute(); + } +} + +void ILibraryAppletAccessor::FrontendExecuteInteractive() { + if (applet->frontend) { + applet->frontend->ExecuteInteractive(); + applet->frontend->Execute(); + } +} + +void ILibraryAppletAccessor::FrontendRequestExit() { + if (applet->frontend) { + applet->frontend->RequestExit(); + } +} + +} // 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..8be29e003 --- /dev/null +++ b/src/core/hle/service/am/library_applet_accessor.h @@ -0,0 +1,43 @@ +// 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 AppletDataBroker; +struct Applet; + +class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { +public: + explicit ILibraryAppletAccessor(Core::System& system_, + std::shared_ptr<AppletDataBroker> broker_, + std::shared_ptr<Applet> applet_); + ~ILibraryAppletAccessor(); + +protected: + 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); + + void FrontendExecute(); + void FrontendExecuteInteractive(); + void FrontendRequestExit(); + + const std::shared_ptr<AppletDataBroker> broker; + const std::shared_ptr<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..47bab7528 --- /dev/null +++ b/src/core/hle/service/am/library_applet_creator.cpp @@ -0,0 +1,271 @@ +// 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/applet_data_broker.h" +#include "core/hle/service/am/applet_manager.h" +#include "core/hle/service/am/frontend/applets.h" +#include "core/hle/service/am/library_applet_accessor.h" +#include "core/hle/service/am/library_applet_creator.h" +#include "core/hle/service/am/library_applet_storage.h" +#include "core/hle/service/am/storage.h" +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::AM { + +namespace { + +AppletProgramId AppletIdToProgramId(AppletId applet_id) { + switch (applet_id) { + case AppletId::OverlayDisplay: + return AppletProgramId::OverlayDisplay; + case AppletId::QLaunch: + return AppletProgramId::QLaunch; + case AppletId::Starter: + return AppletProgramId::Starter; + case AppletId::Auth: + return AppletProgramId::Auth; + case AppletId::Cabinet: + return AppletProgramId::Cabinet; + case AppletId::Controller: + return AppletProgramId::Controller; + case AppletId::DataErase: + return AppletProgramId::DataErase; + case AppletId::Error: + return AppletProgramId::Error; + case AppletId::NetConnect: + return AppletProgramId::NetConnect; + case AppletId::ProfileSelect: + return AppletProgramId::ProfileSelect; + case AppletId::SoftwareKeyboard: + return AppletProgramId::SoftwareKeyboard; + case AppletId::MiiEdit: + return AppletProgramId::MiiEdit; + case AppletId::Web: + return AppletProgramId::Web; + case AppletId::Shop: + return AppletProgramId::Shop; + case AppletId::PhotoViewer: + return AppletProgramId::PhotoViewer; + case AppletId::Settings: + return AppletProgramId::Settings; + case AppletId::OfflineWeb: + return AppletProgramId::OfflineWeb; + case AppletId::LoginShare: + return AppletProgramId::LoginShare; + case AppletId::WebAuth: + return AppletProgramId::WebAuth; + case AppletId::MyPage: + return AppletProgramId::MyPage; + default: + return static_cast<AppletProgramId>(0); + } +} + +[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet( + Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id, + LibraryAppletMode mode) { + const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id)); + if (program_id == 0) { + // Unknown applet + return {}; + } + + auto process = std::make_unique<Process>(system); + if (!process->Initialize(program_id)) { + // Couldn't initialize the guest process + return {}; + } + + const auto applet = std::make_shared<Applet>(system, std::move(process)); + applet->program_id = program_id; + applet->applet_id = applet_id; + applet->type = AppletType::LibraryApplet; + applet->library_applet_mode = mode; + + // Set focus state + switch (mode) { + case LibraryAppletMode::AllForeground: + case LibraryAppletMode::NoUI: + applet->focus_state = FocusState::InFocus; + applet->hid_registration.EnableAppletToGetInput(true); + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); + break; + case LibraryAppletMode::AllForegroundInitiallyHidden: + applet->system_buffer_manager.SetWindowVisibility(false); + applet->focus_state = FocusState::NotInFocus; + applet->hid_registration.EnableAppletToGetInput(false); + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); + break; + case LibraryAppletMode::Background: + case LibraryAppletMode::BackgroundIndirectDisplay: + default: + applet->focus_state = FocusState::Background; + applet->hid_registration.EnableAppletToGetInput(true); + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); + break; + } + + auto broker = std::make_shared<AppletDataBroker>(system); + applet->caller_applet = caller_applet; + applet->caller_applet_broker = broker; + + system.GetAppletManager().InsertApplet(applet); + + return std::make_shared<ILibraryAppletAccessor>(system, broker, applet); +} + +[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet( + Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id, + LibraryAppletMode mode) { + const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id)); + + auto process = std::make_unique<Process>(system); + auto applet = std::make_shared<Applet>(system, std::move(process)); + applet->program_id = program_id; + applet->applet_id = applet_id; + applet->type = AppletType::LibraryApplet; + applet->library_applet_mode = mode; + + auto storage = std::make_shared<AppletDataBroker>(system); + applet->caller_applet = caller_applet; + applet->caller_applet_broker = storage; + applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode); + + return std::make_shared<ILibraryAppletAccessor>(system, storage, applet); +} + +} // namespace + +ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet_) + : ServiceFramework{system_, "ILibraryAppletCreator"}, applet{std::move(applet_)} { + 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<AppletId>(); + const auto applet_mode = rp.PopRaw<LibraryAppletMode>(); + + LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, + applet_mode); + + auto library_applet = CreateFrontendApplet(system, applet, applet_id, applet_mode); + if (!library_applet) { + LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + // Applet is created, can now be launched. + applet->library_applet_launchable_event.Signal(); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILibraryAppletAccessor>(library_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> data(size); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IStorage>(system, AM::CreateStorage(std::move(data))); +} + +void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + struct Parameters { + bool is_writable; + s64 size; + }; + + const auto params{rp.PopRaw<Parameters>()}; + const auto handle{ctx.GetCopyHandle(0)}; + + LOG_DEBUG(Service_AM, "called, is_writable={}, size={}, handle={:08X}", params.is_writable, + params.size, handle); + + if (params.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; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IStorage>( + system, AM::CreateTransferMemoryStorage(ctx.GetMemory(), transfer_mem.GetPointerUnsafe(), + params.is_writable, params.size)); +} + +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; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IStorage>( + system, AM::CreateHandleStorage(ctx.GetMemory(), transfer_mem.GetPointerUnsafe(), size)); +} + +} // 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..551f287bd --- /dev/null +++ b/src/core/hle/service/am/library_applet_creator.h @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::AM { + +struct Applet; + +class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { +public: + explicit ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet_); + ~ILibraryAppletCreator() override; + +private: + void CreateLibraryApplet(HLERequestContext& ctx); + void CreateStorage(HLERequestContext& ctx); + void CreateTransferMemoryStorage(HLERequestContext& ctx); + void CreateHandleStorage(HLERequestContext& ctx); + + const std::shared_ptr<Applet> applet; +}; + +} // 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..d6108fba3 --- /dev/null +++ b/src/core/hle/service/am/library_applet_proxy.cpp @@ -0,0 +1,143 @@ +// 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<Applet> applet_, Core::System& system_) + : ServiceFramework{system_, "ILibraryAppletProxy"}, nvnflinger{nvnflinger_}, applet{std::move( + applet_)} { + // 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); +} + +ILibraryAppletProxy::~ILibraryAppletProxy() = default; + +void ILibraryAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ICommonStateGetter>(system, applet); +} + +void ILibraryAppletProxy::GetSelfController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ISelfController>(system, applet, 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, applet); +} + +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, applet); +} + +void ILibraryAppletProxy::GetProcessWindingController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IProcessWindingController>(system, applet); +} + +void ILibraryAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILibraryAppletCreator>(system, applet); +} + +void ILibraryAppletProxy::OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILibraryAppletSelfAccessor>(system, applet); +} + +void ILibraryAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IAppletCommonFunctions>(system, applet); +} + +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..8f7a25897 --- /dev/null +++ b/src/core/hle/service/am/library_applet_proxy.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 { + +struct Applet; + +class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { +public: + explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, + std::shared_ptr<Applet> applet_, Core::System& system_); + ~ILibraryAppletProxy(); + +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<Applet> applet; +}; + +} // 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..b560f580b --- /dev/null +++ b/src/core/hle/service/am/library_applet_self_accessor.cpp @@ -0,0 +1,338 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/scope_exit.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/hle/service/acc/profile_manager.h" +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/applet_data_broker.h" +#include "core/hle/service/am/applet_manager.h" +#include "core/hle/service/am/frontend/applet_cabinet.h" +#include "core/hle/service/am/frontend/applet_controller.h" +#include "core/hle/service/am/frontend/applet_mii_edit_types.h" +#include "core/hle/service/am/frontend/applet_software_keyboard_types.h" +#include "core/hle/service/am/frontend/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 "core/hle/service/ns/ns.h" +#include "core/hle/service/sm/sm.h" +#include "hid_core/hid_types.h" + +namespace Service::AM { + +namespace { + +AppletIdentityInfo GetCallerIdentity(std::shared_ptr<Applet> applet) { + if (const auto caller_applet = applet->caller_applet.lock(); caller_applet) { + // TODO: is this actually the application ID? + return { + .applet_id = caller_applet->applet_id, + .application_id = caller_applet->program_id, + }; + } else { + return { + .applet_id = AppletId::QLaunch, + .application_id = 0x0100000000001000ull, + }; + } +} + +} // namespace + +ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_, + std::shared_ptr<Applet> applet_) + : ServiceFramework{system_, "ILibraryAppletSelfAccessor"}, applet{std::move(applet_)}, + broker{applet->caller_applet_broker} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ILibraryAppletSelfAccessor::PopInData, "PopInData"}, + {1, &ILibraryAppletSelfAccessor::PushOutData, "PushOutData"}, + {2, &ILibraryAppletSelfAccessor::PopInteractiveInData, "PopInteractiveInData"}, + {3, &ILibraryAppletSelfAccessor::PushInteractiveOutData, "PushInteractiveOutData"}, + {5, &ILibraryAppletSelfAccessor::GetPopInDataEvent, "GetPopInDataEvent"}, + {6, &ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent, "GetPopInteractiveInDataEvent"}, + {10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"}, + {11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"}, + {12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"}, + {13, &ILibraryAppletSelfAccessor::CanUseApplicationCore, "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, &ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage, "GetMainAppletApplicationDesiredLanguage"}, + {70, &ILibraryAppletSelfAccessor::GetCurrentApplicationId, "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"}, + {160, &ILibraryAppletSelfAccessor::Cmd160, "Cmd160"}, + }; + // clang-format on + RegisterHandlers(functions); +} + +ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default; + +void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + std::shared_ptr<IStorage> data; + const auto res = broker->GetInData().Pop(&data); + + if (res.IsSuccess()) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface(std::move(data)); + } else { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); + } +} + +void ILibraryAppletSelfAccessor::PushOutData(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + IPC::RequestParser rp{ctx}; + broker->GetOutData().Push(rp.PopIpcInterface<IStorage>().lock()); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletSelfAccessor::PopInteractiveInData(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + std::shared_ptr<IStorage> data; + const auto res = broker->GetInteractiveInData().Pop(&data); + + if (res.IsSuccess()) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface(std::move(data)); + } else { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); + } +} + +void ILibraryAppletSelfAccessor::PushInteractiveOutData(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + IPC::RequestParser rp{ctx}; + broker->GetInteractiveOutData().Push(rp.PopIpcInterface<IStorage>().lock()); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletSelfAccessor::GetPopInDataEvent(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(broker->GetInData().GetEvent()); +} + +void ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(broker->GetInteractiveInData().GetEvent()); +} + +void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + system.GetAppletManager().TerminateAndRemoveApplet(applet->aruid); + broker->SignalCompletion(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) { + struct LibraryAppletInfo { + AppletId applet_id; + LibraryAppletMode library_applet_mode; + }; + + LOG_WARNING(Service_AM, "(STUBBED) called"); + + const LibraryAppletInfo applet_info{ + .applet_id = applet->applet_id, + .library_applet_mode = applet->library_applet_mode, + }; + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.PushRaw(applet_info); +} + +void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + const AppletIdentityInfo applet_info{ + .applet_id = AppletId::QLaunch, + .application_id = 0x0100000000001000ull, + }; + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.PushRaw(applet_info); +} + +void ILibraryAppletSelfAccessor::CanUseApplicationCore(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + // TODO: This appears to read the NPDM from state and check the core mask of the applet. + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u8>(0); +} + +void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.PushRaw(GetCallerIdentity(applet)); +} + +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::GetMainAppletApplicationDesiredLanguage(HLERequestContext& ctx) { + // FIXME: this is copied from IApplicationFunctions::GetDesiredLanguage + auto identity = GetCallerIdentity(applet); + + // TODO(bunnei): This should be configurable + LOG_DEBUG(Service_AM, "called"); + + // Get supported languages from NACP, if possible + // Default to 0 (all languages supported) + u32 supported_languages = 0; + + const auto res = [this, identity] { + const FileSys::PatchManager pm{identity.application_id, system.GetFileSystemController(), + system.GetContentProvider()}; + auto metadata = pm.GetControlMetadata(); + if (metadata.first != nullptr) { + return metadata; + } + + const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(identity.application_id), + system.GetFileSystemController(), + system.GetContentProvider()}; + return pm_update.GetControlMetadata(); + }(); + + if (res.first != nullptr) { + supported_languages = res.first->GetSupportedLanguages(); + } + + // Call IApplicationManagerInterface implementation. + auto& service_manager = system.ServiceManager(); + auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2"); + auto app_man = ns_am2->GetApplicationManagerInterface(); + + // Get desired application language + u8 desired_language{}; + 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 ILibraryAppletSelfAccessor::GetCurrentApplicationId(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + u64 application_id = 0; + if (auto caller_applet = applet->caller_applet.lock(); caller_applet) { + application_id = caller_applet->program_id; + } + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(application_id); +} + +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::Cmd160(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(0); +} + +} // 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..8717a989a --- /dev/null +++ b/src/core/hle/service/am/library_applet_self_accessor.h @@ -0,0 +1,44 @@ +// 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 AppletDataBroker; +struct Applet; + +class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> { +public: + explicit ILibraryAppletSelfAccessor(Core::System& system_, std::shared_ptr<Applet> applet_); + ~ILibraryAppletSelfAccessor() override; + +private: + void PopInData(HLERequestContext& ctx); + void PushOutData(HLERequestContext& ctx); + void PopInteractiveInData(HLERequestContext& ctx); + void PushInteractiveOutData(HLERequestContext& ctx); + void GetPopInDataEvent(HLERequestContext& ctx); + void GetPopInteractiveInDataEvent(HLERequestContext& ctx); + void GetLibraryAppletInfo(HLERequestContext& ctx); + void GetMainAppletIdentityInfo(HLERequestContext& ctx); + void CanUseApplicationCore(HLERequestContext& ctx); + void ExitProcessAndReturn(HLERequestContext& ctx); + void GetCallerAppletIdentityInfo(HLERequestContext& ctx); + void GetDesirableKeyboardLayout(HLERequestContext& ctx); + void GetMainAppletApplicationDesiredLanguage(HLERequestContext& ctx); + void GetCurrentApplicationId(HLERequestContext& ctx); + void GetMainAppletAvailableUsers(HLERequestContext& ctx); + void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx); + void Cmd160(HLERequestContext& ctx); + + const std::shared_ptr<Applet> applet; + const std::shared_ptr<AppletDataBroker> broker; +}; + +} // 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 @@ +// 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/am_results.h" +#include "core/hle/service/am/library_applet_storage.h" +#include "core/memory.h" + +namespace Service::AM { + +namespace { + +Result ValidateOffset(s64 offset, size_t size, size_t data_size) { + R_UNLESS(offset >= 0, AM::ResultInvalidOffset); + + const size_t begin = offset; + const size_t end = begin + size; + + R_UNLESS(begin <= end && end <= data_size, AM::ResultInvalidOffset); + R_SUCCEED(); +} + +class BufferLibraryAppletStorage final : public LibraryAppletStorage { +public: + explicit BufferLibraryAppletStorage(std::vector<u8>&& data) : m_data(std::move(data)) {} + ~BufferLibraryAppletStorage() = default; + + Result Read(s64 offset, void* buffer, size_t size) override { + R_TRY(ValidateOffset(offset, size, m_data.size())); + + std::memcpy(buffer, m_data.data() + offset, size); + + R_SUCCEED(); + } + + Result Write(s64 offset, const void* buffer, size_t size) override { + R_TRY(ValidateOffset(offset, size, m_data.size())); + + std::memcpy(m_data.data() + offset, buffer, size); + + R_SUCCEED(); + } + + s64 GetSize() override { + return m_data.size(); + } + + Kernel::KTransferMemory* GetHandle() override { + return nullptr; + } + +private: + std::vector<u8> m_data; +}; + +class TransferMemoryLibraryAppletStorage : public LibraryAppletStorage { +public: + explicit TransferMemoryLibraryAppletStorage(Core::Memory::Memory& memory, + Kernel::KTransferMemory* trmem, bool is_writable, + s64 size) + : m_memory(memory), m_trmem(trmem), m_is_writable(is_writable), m_size(size) { + m_trmem->Open(); + } + + ~TransferMemoryLibraryAppletStorage() { + m_trmem->Close(); + m_trmem = nullptr; + } + + Result Read(s64 offset, void* buffer, size_t size) override { + R_TRY(ValidateOffset(offset, size, m_size)); + + m_memory.ReadBlock(m_trmem->GetSourceAddress(), buffer, size); + + R_SUCCEED(); + } + + Result Write(s64 offset, const void* buffer, size_t size) override { + R_UNLESS(m_is_writable, ResultUnknown); + R_TRY(ValidateOffset(offset, size, m_size)); + + m_memory.WriteBlock(m_trmem->GetSourceAddress(), buffer, size); + + R_SUCCEED(); + } + + s64 GetSize() override { + return m_size; + } + + Kernel::KTransferMemory* GetHandle() override { + return nullptr; + } + +protected: + Core::Memory::Memory& m_memory; + Kernel::KTransferMemory* m_trmem; + bool m_is_writable; + s64 m_size; +}; + +class HandleLibraryAppletStorage : public TransferMemoryLibraryAppletStorage { +public: + explicit HandleLibraryAppletStorage(Core::Memory::Memory& memory, + Kernel::KTransferMemory* trmem, s64 size) + : TransferMemoryLibraryAppletStorage(memory, trmem, true, size) {} + ~HandleLibraryAppletStorage() = default; + + Kernel::KTransferMemory* GetHandle() override { + return m_trmem; + } +}; + +} // namespace + +LibraryAppletStorage::~LibraryAppletStorage() = default; + +std::vector<u8> LibraryAppletStorage::GetData() { + std::vector<u8> data(this->GetSize()); + this->Read(0, data.data(), data.size()); + return data; +} + +std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data) { + return std::make_shared<BufferLibraryAppletStorage>(std::move(data)); +} + +std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory, + Kernel::KTransferMemory* trmem, + bool is_writable, s64 size) { + return std::make_shared<TransferMemoryLibraryAppletStorage>(memory, trmem, is_writable, size); +} + +std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory, + Kernel::KTransferMemory* trmem, + s64 size) { + return std::make_shared<HandleLibraryAppletStorage>(memory, trmem, size); +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" + +namespace Core::Memory { +class Memory; +} + +namespace Kernel { +class KTransferMemory; +} + +namespace Service::AM { + +class LibraryAppletStorage { +public: + virtual ~LibraryAppletStorage(); + virtual Result Read(s64 offset, void* buffer, size_t size) = 0; + virtual Result Write(s64 offset, const void* buffer, size_t size) = 0; + virtual s64 GetSize() = 0; + virtual Kernel::KTransferMemory* GetHandle() = 0; + + std::vector<u8> GetData(); +}; + +std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data); +std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory, + Kernel::KTransferMemory* trmem, + bool is_writable, s64 size); +std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory, + Kernel::KTransferMemory* trmem, s64 size); + +} // 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/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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/managed_layer_holder.h" +#include "core/hle/service/nvnflinger/nvnflinger.h" + +namespace Service::AM { + +ManagedLayerHolder::ManagedLayerHolder() = default; +ManagedLayerHolder::~ManagedLayerHolder() { + if (!m_nvnflinger) { + return; + } + + for (const auto& layer : m_managed_display_layers) { + m_nvnflinger->DestroyLayer(layer); + } + + for (const auto& layer : m_managed_display_recording_layers) { + m_nvnflinger->DestroyLayer(layer); + } + + m_nvnflinger = nullptr; +} + +void ManagedLayerHolder::Initialize(Nvnflinger::Nvnflinger* nvnflinger) { + m_nvnflinger = nvnflinger; +} + +void ManagedLayerHolder::CreateManagedDisplayLayer(u64* out_layer) { + // 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 = m_nvnflinger->OpenDisplay("Default"); + const auto layer_id = m_nvnflinger->CreateLayer(*display_id); + + m_managed_display_layers.emplace(*layer_id); + + *out_layer = *layer_id; +} + +void ManagedLayerHolder::CreateManagedDisplaySeparableLayer(u64* out_layer, + u64* out_recording_layer) { + // 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 = m_nvnflinger->OpenDisplay("Default"); + const auto layer_id = m_nvnflinger->CreateLayer(*display_id); + + m_managed_display_layers.emplace(*layer_id); + + *out_layer = *layer_id; + *out_recording_layer = 0; +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <set> + +#include "common/common_funcs.h" +#include "common/common_types.h" + +namespace Service::Nvnflinger { +class Nvnflinger; +} + +namespace Service::AM { + +class ManagedLayerHolder { +public: + ManagedLayerHolder(); + ~ManagedLayerHolder(); + + void Initialize(Nvnflinger::Nvnflinger* nvnflinger); + void CreateManagedDisplayLayer(u64* out_layer); + void CreateManagedDisplaySeparableLayer(u64* out_layer, u64* out_recording_layer); + +private: + Nvnflinger::Nvnflinger* m_nvnflinger{}; + std::set<u64> m_managed_display_layers{}; + std::set<u64> m_managed_display_recording_layers{}; +}; + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/scope_exit.h" + +#include "core/file_sys/nca_metadata.h" +#include "core/file_sys/registered_cache.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/service/am/process.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/loader/loader.h" + +namespace Service::AM { + +Process::Process(Core::System& system) + : m_system(system), m_process(), m_main_thread_priority(), m_main_thread_stack_size(), + m_program_id(), m_process_started() {} + +Process::~Process() { + this->Finalize(); +} + +bool Process::Initialize(u64 program_id) { + // First, ensure we are not holding another process. + this->Finalize(); + + // Get the filesystem controller. + auto& fsc = m_system.GetFileSystemController(); + + // Attempt to load program NCA. + const FileSys::RegisteredCache* bis_system{}; + FileSys::VirtualFile nca{}; + + // Get the program NCA from built-in storage. + bis_system = fsc.GetSystemNANDContents(); + if (bis_system) { + nca = bis_system->GetEntryRaw(program_id, FileSys::ContentRecordType::Program); + } + + // Ensure we retrieved a program NCA. + if (!nca) { + return false; + } + + // Get the appropriate loader to parse this NCA. + auto app_loader = Loader::GetLoader(m_system, nca, program_id, 0); + + // Ensure we have a loader which can parse the NCA. + if (!app_loader) { + return false; + } + + // Create the process. + auto* const process = Kernel::KProcess::Create(m_system.Kernel()); + Kernel::KProcess::Register(m_system.Kernel(), process); + + // On exit, ensure we free the additional reference to the process. + SCOPE_EXIT({ process->Close(); }); + + // Insert process modules into memory. + const auto [load_result, load_parameters] = app_loader->Load(*process, m_system); + + // Ensure loading was successful. + if (load_result != Loader::ResultStatus::Success) { + return false; + } + + // TODO: remove this, kernel already tracks this + m_system.Kernel().AppendNewProcess(process); + + // Note the load parameters from NPDM. + m_main_thread_priority = load_parameters->main_thread_priority; + m_main_thread_stack_size = load_parameters->main_thread_stack_size; + + // This process has not started yet. + m_process_started = false; + + // Take ownership of the process object. + m_process = process; + m_process->Open(); + + // We succeeded. + return true; +} + +void Process::Finalize() { + // Terminate, if we are currently holding a process. + this->Terminate(); + + // Close the process. + if (m_process) { + m_process->Close(); + + // TODO: remove this, kernel already tracks this + m_system.Kernel().RemoveProcess(m_process); + } + + // Clean up. + m_process = nullptr; + m_main_thread_priority = 0; + m_main_thread_stack_size = 0; + m_program_id = 0; + m_process_started = false; +} + +bool Process::Run() { + // If we already started the process, don't start again. + if (m_process_started) { + return false; + } + + // Start. + if (m_process) { + m_process->Run(m_main_thread_priority, m_main_thread_stack_size); + } + + // Mark as started. + m_process_started = true; + + // We succeeded. + return true; +} + +void Process::Terminate() { + if (m_process) { + m_process->Terminate(); + } +} + +u64 Process::GetProcessId() const { + if (m_process) { + return m_process->GetProcessId(); + } + + return 0; +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_funcs.h" +#include "common/common_types.h" + +namespace Kernel { +class KProcess; +} + +namespace Core { +class System; +} + +namespace Service::AM { + +class Process { +public: + explicit Process(Core::System& system); + ~Process(); + + bool Initialize(u64 program_id); + void Finalize(); + + bool Run(); + void Terminate(); + + bool IsInitialized() const { + return m_process != nullptr; + } + u64 GetProcessId() const; + u64 GetProgramId() const { + return m_program_id; + } + Kernel::KProcess* GetProcess() const { + return m_process; + } + +private: + Core::System& m_system; + Kernel::KProcess* m_process{}; + s32 m_main_thread_priority{}; + u64 m_main_thread_stack_size{}; + u64 m_program_id{}; + bool m_process_started{}; +}; + +} // 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..b48b52797 --- /dev/null +++ b/src/core/hle/service/am/process_winding_controller.cpp @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/frontend/applets.h" +#include "core/hle/service/am/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_, + std::shared_ptr<Applet> applet_) + : ServiceFramework{system_, "IProcessWindingController"}, applet{std::move(applet_)} { + // 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"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushRaw(applet->launch_reason); +} + +void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) { + const auto caller_applet = applet->caller_applet.lock(); + if (caller_applet == nullptr) { + LOG_ERROR(Service_AM, "No calling applet available"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet->caller_applet_broker, + caller_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..71ae4c4f5 --- /dev/null +++ b/src/core/hle/service/am/process_winding_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 { + +struct Applet; + +class IProcessWindingController final : public ServiceFramework<IProcessWindingController> { +public: + explicit IProcessWindingController(Core::System& system_, std::shared_ptr<Applet> applet_); + ~IProcessWindingController() override; + +private: + void GetLaunchReason(HLERequestContext& ctx); + void OpenCallingLibraryApplet(HLERequestContext& ctx); + + const std::shared_ptr<Applet> applet; +}; + +} // 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..0289f5cf1 --- /dev/null +++ b/src/core/hle/service/am/self_controller.cpp @@ -0,0 +1,456 @@ +// 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/frontend/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_, std::shared_ptr<Applet> applet_, + Nvnflinger::Nvnflinger& nvnflinger_) + : ServiceFramework{system_, "ISelfController"}, nvnflinger{nvnflinger_}, applet{std::move( + applet_)} { + // 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, &ISelfController::SetScreenShotAppletIdentityInfo, "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); +} + +ISelfController::~ISelfController() = default; + +void ISelfController::Exit(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + + // TODO + 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) { + + std::scoped_lock lk{applet->lock}; + applet->fatal_section_count++; + LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", applet->fatal_section_count); + + 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. + std::scoped_lock lk{applet->lock}; + if (applet->fatal_section_count == 0) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultFatalSectionCountImbalance); + return; + } + + applet->fatal_section_count--; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::GetLibraryAppletLaunchableEvent(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + applet->library_applet_launchable_event.Signal(); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(applet->library_applet_launchable_event.GetHandle()); +} + +void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto permission = rp.PopEnum<ScreenshotPermission>(); + LOG_DEBUG(Service_AM, "called, permission={}", permission); + + std::scoped_lock lk{applet->lock}; + applet->screenshot_permission = permission; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const bool notification_enabled = rp.Pop<bool>(); + LOG_WARNING(Service_AM, "(STUBBED) called notification_enabled={}", notification_enabled); + + std::scoped_lock lk{applet->lock}; + applet->operation_mode_changed_notification_enabled = notification_enabled; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetPerformanceModeChangedNotification(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const bool notification_enabled = rp.Pop<bool>(); + LOG_WARNING(Service_AM, "(STUBBED) called notification_enabled={}", notification_enabled); + + std::scoped_lock lk{applet->lock}; + applet->performance_mode_changed_notification_enabled = notification_enabled; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetFocusHandlingMode(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto flags = rp.PopRaw<FocusHandlingMode>(); + + LOG_WARNING(Service_AM, "(STUBBED) called. unknown0={}, unknown1={}, unknown2={}", + flags.unknown0, flags.unknown1, flags.unknown2); + + std::scoped_lock lk{applet->lock}; + applet->focus_handling_mode = flags; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetRestartMessageEnabled(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::scoped_lock lk{applet->lock}; + applet->restart_message_enabled = true; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetScreenShotAppletIdentityInfo(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::RequestParser rp{ctx}; + std::scoped_lock lk{applet->lock}; + applet->screen_shot_identity = rp.PopRaw<AppletIdentityInfo>(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const bool enabled = rp.Pop<bool>(); + LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled); + + std::scoped_lock lk{applet->lock}; + ASSERT(applet->type == AppletType::Application); + applet->out_of_focus_suspension_enabled = enabled; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::SetAlbumImageOrientation(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto orientation = rp.PopRaw<Capture::AlbumImageOrientation>(); + LOG_WARNING(Service_AM, "(STUBBED) called, orientation={}", static_cast<s32>(orientation)); + + std::scoped_lock lk{applet->lock}; + applet->album_image_orientation = orientation; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + u64 layer_id{}; + applet->managed_layer_holder.Initialize(&nvnflinger); + applet->managed_layer_holder.CreateManagedDisplayLayer(&layer_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"); + + u64 buffer_id, layer_id; + applet->system_buffer_manager.GetSystemSharedLayerHandle(&buffer_id, &layer_id); + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess())); + rb.Push<s64>(buffer_id); + rb.Push<s64>(layer_id); +} + +void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + u64 buffer_id, layer_id; + applet->system_buffer_manager.GetSystemSharedLayerHandle(&buffer_id, &layer_id); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess())); + rb.Push<s64>(buffer_id); +} + +Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) { + if (applet->system_buffer_manager.Initialize(&nvnflinger, process, applet->applet_id)) { + return ResultSuccess; + } + + return VI::ResultOperationFailed; +} + +void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + u64 layer_id{}; + u64 recording_layer_id{}; + applet->managed_layer_holder.Initialize(&nvnflinger); + applet->managed_layer_holder.CreateManagedDisplaySeparableLayer(&layer_id, &recording_layer_id); + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.Push(layer_id); + rb.Push(recording_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}; + + const auto extension = rp.PopRaw<IdleTimeDetectionExtension>(); + LOG_DEBUG(Service_AM, "(STUBBED) called extension={}", extension); + + std::scoped_lock lk{applet->lock}; + applet->idle_time_detection_extension = extension; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::GetIdleTimeDetectionExtension(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + std::scoped_lock lk{applet->lock}; + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushRaw<IdleTimeDetectionExtension>(applet->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}; + + std::scoped_lock lk{applet->lock}; + applet->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={}", applet->auto_sleep_disabled); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISelfController::IsAutoSleepDisabled(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called."); + + std::scoped_lock lk{applet->lock}; + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(applet->auto_sleep_disabled); +} + +void ISelfController::GetAccumulatedSuspendedTickValue(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called."); + + std::scoped_lock lk{applet->lock}; + // 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>(applet->suspended_ticks); +} + +void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called."); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(applet->accumulated_suspended_tick_changed_event.GetHandle()); +} + +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 enabled = rp.Pop<bool>(); + LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled); + + std::scoped_lock lk{applet->lock}; + applet->album_image_taken_notification_enabled = 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 enabled = rp.Pop<bool>(); + LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled); + + std::scoped_lock lk{applet->lock}; + applet->record_volume_muted = enabled; + + 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..a63bc2e74 --- /dev/null +++ b/src/core/hle/service/am/self_controller.h @@ -0,0 +1,58 @@ +// 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 { + +struct Applet; + +class ISelfController final : public ServiceFramework<ISelfController> { +public: + explicit ISelfController(Core::System& system_, std::shared_ptr<Applet> applet_, + 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 SetScreenShotAppletIdentityInfo(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); + + Nvnflinger::Nvnflinger& nvnflinger; + const std::shared_ptr<Applet> applet; +}; + +} // 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..4e82afd1c --- /dev/null +++ b/src/core/hle/service/am/storage.cpp @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/am_results.h" +#include "core/hle/service/am/library_applet_storage.h" +#include "core/hle/service/am/storage.h" +#include "core/hle/service/am/storage_accessor.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IStorage::IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl_) + : ServiceFramework{system_, "IStorage"}, impl{std::move(impl_)} { + static const FunctionInfo functions[] = { + {0, &IStorage::Open, "Open"}, + {1, &IStorage::OpenTransferStorage, "OpenTransferStorage"}, + }; + + RegisterHandlers(functions); +} + +IStorage::IStorage(Core::System& system_, std::vector<u8>&& data) + : IStorage(system_, CreateStorage(std::move(data))) {} + +IStorage::~IStorage() = default; + +void IStorage::Open(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + if (impl->GetHandle() != nullptr) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultInvalidStorageType); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IStorageAccessor>(system, impl); +} + +void IStorage::OpenTransferStorage(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + if (impl->GetHandle() == nullptr) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(AM::ResultInvalidStorageType); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ITransferStorageAccessor>(system, impl); +} + +std::vector<u8> IStorage::GetData() const { + return impl->GetData(); +} + +} // 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..10d00b141 --- /dev/null +++ b/src/core/hle/service/am/storage.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::AM { + +class LibraryAppletStorage; + +class IStorage final : public ServiceFramework<IStorage> { +public: + explicit IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl_); + explicit IStorage(Core::System& system_, std::vector<u8>&& buffer); + ~IStorage() override; + + std::shared_ptr<LibraryAppletStorage> GetImpl() const { + return impl; + } + + std::vector<u8> GetData() const; + +private: + void Open(HLERequestContext& ctx); + void OpenTransferStorage(HLERequestContext& ctx); + + const std::shared_ptr<LibraryAppletStorage> 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..a1184b065 --- /dev/null +++ b/src/core/hle/service/am/storage_accessor.cpp @@ -0,0 +1,90 @@ +// 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/am_results.h" +#include "core/hle/service/am/library_applet_storage.h" +#include "core/hle/service/am/storage_accessor.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IStorageAccessor::IStorageAccessor(Core::System& system_, + std::shared_ptr<LibraryAppletStorage> impl_) + : ServiceFramework{system_, "IStorageAccessor"}, impl{std::move(impl_)} { + static const FunctionInfo functions[] = { + {0, &IStorageAccessor::GetSize, "GetSize"}, + {10, &IStorageAccessor::Write, "Write"}, + {11, &IStorageAccessor::Read, "Read"}, + }; + + 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(impl->GetSize()); +} + +void IStorageAccessor::Write(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const s64 offset{rp.Pop<s64>()}; + const auto data{ctx.ReadBuffer()}; + LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size()); + + const auto res{impl->Write(offset, data.data(), data.size())}; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void IStorageAccessor::Read(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const s64 offset{rp.Pop<s64>()}; + std::vector<u8> data(ctx.GetWriteBufferSize()); + + LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size()); + + const auto res{impl->Read(offset, data.data(), data.size())}; + + ctx.WriteBuffer(data); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +ITransferStorageAccessor::ITransferStorageAccessor(Core::System& system_, + std::shared_ptr<LibraryAppletStorage> impl_) + : ServiceFramework{system_, "ITransferStorageAccessor"}, impl{std::move(impl_)} { + static const FunctionInfo functions[] = { + {0, &ITransferStorageAccessor::GetSize, "GetSize"}, + {1, &ITransferStorageAccessor::GetHandle, "GetHandle"}, + }; + + RegisterHandlers(functions); +} + +ITransferStorageAccessor::~ITransferStorageAccessor() = default; + +void ITransferStorageAccessor::GetSize(HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(impl->GetSize()); +} + +void ITransferStorageAccessor::GetHandle(HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 4, 1}; + rb.Push(ResultSuccess); + rb.Push(impl->GetSize()); + rb.PushCopyObjects(impl->GetHandle()); +} + +} // 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..b9aa85a66 --- /dev/null +++ b/src/core/hle/service/am/storage_accessor.h @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/am/storage.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { +public: + explicit IStorageAccessor(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl_); + ~IStorageAccessor() override; + +private: + void GetSize(HLERequestContext& ctx); + void Write(HLERequestContext& ctx); + void Read(HLERequestContext& ctx); + + const std::shared_ptr<LibraryAppletStorage> impl; +}; + +class ITransferStorageAccessor final : public ServiceFramework<ITransferStorageAccessor> { +public: + explicit ITransferStorageAccessor(Core::System& system_, + std::shared_ptr<LibraryAppletStorage> impl_); + ~ITransferStorageAccessor() override; + +private: + void GetSize(HLERequestContext& ctx); + void GetHandle(HLERequestContext& ctx); + + const std::shared_ptr<LibraryAppletStorage> impl; +}; + +} // 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..38643408e --- /dev/null +++ b/src/core/hle/service/am/system_applet_proxy.cpp @@ -0,0 +1,136 @@ +// 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<Applet> applet_, Core::System& system_) + : ServiceFramework{system_, "ISystemAppletProxy"}, nvnflinger{nvnflinger_}, applet{std::move( + applet_)} { + // 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); +} + +ISystemAppletProxy::~ISystemAppletProxy() = default; + +void ISystemAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ICommonStateGetter>(system, applet); +} + +void ISystemAppletProxy::GetSelfController(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ISelfController>(system, applet, 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, applet); +} + +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, applet); +} + +void ISystemAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ILibraryAppletCreator>(system, applet); +} + +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, applet); +} + +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..0390cd1e5 --- /dev/null +++ b/src/core/hle/service/am/system_applet_proxy.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/am/applet_message_queue.h" +#include "core/hle/service/service.h" + +namespace Service::AM { + +struct Applet; + +class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { +public: + explicit ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, + std::shared_ptr<Applet> applet_, Core::System& system_); + ~ISystemAppletProxy(); + +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<Applet> applet; +}; + +} // 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..60a9afc9d --- /dev/null +++ b/src/core/hle/service/am/system_buffer_manager.cpp @@ -0,0 +1,69 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/system_buffer_manager.h" +#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" +#include "core/hle/service/nvnflinger/nvnflinger.h" +#include "core/hle/service/vi/vi_results.h" + +namespace Service::AM { + +SystemBufferManager::SystemBufferManager() = default; + +SystemBufferManager::~SystemBufferManager() { + if (!m_nvnflinger) { + return; + } + + // Clean up shared layers. + if (m_buffer_sharing_enabled) { + } +} + +bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process, + AppletId applet_id) { + if (m_nvnflinger) { + return m_buffer_sharing_enabled; + } + + m_process = process; + m_nvnflinger = nvnflinger; + m_buffer_sharing_enabled = false; + m_system_shared_buffer_id = 0; + m_system_shared_layer_id = 0; + + if (applet_id <= AppletId::Application) { + return false; + } + + const auto display_id = m_nvnflinger->OpenDisplay("Default").value(); + const auto res = m_nvnflinger->GetSystemBufferManager().Initialize( + &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id); + + if (res.IsSuccess()) { + m_buffer_sharing_enabled = true; + m_nvnflinger->SetLayerVisibility(m_system_shared_layer_id, m_visible); + } + + return m_buffer_sharing_enabled; +} + +void SystemBufferManager::SetWindowVisibility(bool visible) { + if (m_visible == visible) { + return; + } + + m_visible = visible; + + if (m_nvnflinger) { + m_nvnflinger->SetLayerVisibility(m_system_shared_layer_id, m_visible); + } +} + +Result SystemBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, + s32* out_fbshare_layer_index) { + // TODO + R_SUCCEED(); +} + +} // 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..98c3cf055 --- /dev/null +++ b/src/core/hle/service/am/system_buffer_manager.h @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <set> + +#include "common/common_funcs.h" +#include "common/common_types.h" + +#include "core/hle/service/am/am_types.h" + +namespace Kernel { +class KProcess; +} + +namespace Service::Nvnflinger { +class Nvnflinger; +} + +union Result; + +namespace Service::AM { + +class SystemBufferManager { +public: + SystemBufferManager(); + ~SystemBufferManager(); + + bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id); + + void GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id, + u64* out_system_shared_layer_id) { + *out_system_shared_buffer_id = m_system_shared_buffer_id; + *out_system_shared_layer_id = m_system_shared_layer_id; + } + + void SetWindowVisibility(bool visible); + + Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index); + +private: + Kernel::KProcess* m_process{}; + Nvnflinger::Nvnflinger* m_nvnflinger{}; + bool m_buffer_sharing_enabled{}; + bool m_visible{true}; + u64 m_system_shared_buffer_id{}; + u64 m_system_shared_layer_id{}; +}; + +} // 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..f00957f83 --- /dev/null +++ b/src/core/hle/service/am/window_controller.cpp @@ -0,0 +1,86 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/am/applet.h" +#include "core/hle/service/am/window_controller.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::AM { + +IWindowController::IWindowController(Core::System& system_, std::shared_ptr<Applet> applet_) + : ServiceFramework{system_, "IWindowController"}, applet{std::move(applet_)} { + // 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, &IWindowController::SetAppletWindowVisibility, "SetAppletWindowVisibility"}, + {21, &IWindowController::SetAppletGpuTimeSlice, "SetAppletGpuTimeSlice"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IWindowController::~IWindowController() = default; + +void IWindowController::GetAppletResourceUserId(HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(applet->aruid); +} + +void IWindowController::GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx) { + u64 aruid = 0; + if (auto caller = applet->caller_applet.lock(); caller) { + aruid = caller->aruid; + } + + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(aruid); +} + +void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IWindowController::SetAppletWindowVisibility(HLERequestContext& ctx) { + LOG_INFO(Service_AM, "called"); + + IPC::RequestParser rp{ctx}; + const bool visible = rp.Pop<bool>(); + + applet->system_buffer_manager.SetWindowVisibility(visible); + applet->hid_registration.EnableAppletToGetInput(visible); + + if (visible) { + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); + applet->focus_state = FocusState::InFocus; + } else { + applet->focus_state = FocusState::NotInFocus; + } + applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IWindowController::SetAppletGpuTimeSlice(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto time_slice = rp.Pop<s64>(); + + LOG_WARNING(Service_AM, "(STUBBED) called, time_slice={}", time_slice); + + 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..a28219abe --- /dev/null +++ b/src/core/hle/service/am/window_controller.h @@ -0,0 +1,27 @@ +// 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 { + +struct Applet; + +class IWindowController final : public ServiceFramework<IWindowController> { +public: + explicit IWindowController(Core::System& system_, std::shared_ptr<Applet> applet_); + ~IWindowController() override; + +private: + void GetAppletResourceUserId(HLERequestContext& ctx); + void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx); + void AcquireForegroundRights(HLERequestContext& ctx); + void SetAppletWindowVisibility(HLERequestContext& ctx); + void SetAppletGpuTimeSlice(HLERequestContext& ctx); + + const std::shared_ptr<Applet> applet; +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 7075ab800..486719cc0 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp @@ -202,7 +202,7 @@ void AOC_U::ListAddOnContent(HLERequestContext& ctx) { LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count, process_id); - const auto current = system.GetApplicationProcessProgramID(); + const auto current = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID()); std::vector<u32> out; const auto& disabled = Settings::values.disabled_addons[current]; diff --git a/src/core/hle/service/caps/caps_a.cpp b/src/core/hle/service/caps/caps_a.cpp index 69acb3a8b..47ff072c5 100644 --- a/src/core/hle/service/caps/caps_a.cpp +++ b/src/core/hle/service/caps/caps_a.cpp @@ -5,7 +5,7 @@ #include "core/hle/service/caps/caps_a.h" #include "core/hle/service/caps/caps_manager.h" #include "core/hle/service/caps/caps_result.h" -#include "core/hle/service/caps/caps_types.h" +#include "core/hle/service/cmif_serialization.h" #include "core/hle/service/ipc_helpers.h" namespace Service::Capture { @@ -18,9 +18,9 @@ IAlbumAccessorService::IAlbumAccessorService(Core::System& system_, {0, nullptr, "GetAlbumFileCount"}, {1, nullptr, "GetAlbumFileList"}, {2, nullptr, "LoadAlbumFile"}, - {3, &IAlbumAccessorService::DeleteAlbumFile, "DeleteAlbumFile"}, + {3, C<&IAlbumAccessorService::DeleteAlbumFile>, "DeleteAlbumFile"}, {4, nullptr, "StorageCopyAlbumFile"}, - {5, &IAlbumAccessorService::IsAlbumMounted, "IsAlbumMounted"}, + {5, C<&IAlbumAccessorService::IsAlbumMounted>, "IsAlbumMounted"}, {6, nullptr, "GetAlbumUsage"}, {7, nullptr, "GetAlbumFileSize"}, {8, nullptr, "LoadAlbumFileThumbnail"}, @@ -33,18 +33,18 @@ IAlbumAccessorService::IAlbumAccessorService(Core::System& system_, {15, nullptr, "GetAlbumUsage3"}, {16, nullptr, "GetAlbumMountResult"}, {17, nullptr, "GetAlbumUsage16"}, - {18, &IAlbumAccessorService::Unknown18, "Unknown18"}, + {18, C<&IAlbumAccessorService::Unknown18>, "Unknown18"}, {19, nullptr, "Unknown19"}, {100, nullptr, "GetAlbumFileCountEx0"}, - {101, &IAlbumAccessorService::GetAlbumFileListEx0, "GetAlbumFileListEx0"}, + {101, C<&IAlbumAccessorService::GetAlbumFileListEx0>, "GetAlbumFileListEx0"}, {202, nullptr, "SaveEditedScreenShot"}, {301, nullptr, "GetLastThumbnail"}, {302, nullptr, "GetLastOverlayMovieThumbnail"}, - {401, &IAlbumAccessorService::GetAutoSavingStorage, "GetAutoSavingStorage"}, + {401, C<&IAlbumAccessorService::GetAutoSavingStorage>, "GetAutoSavingStorage"}, {501, nullptr, "GetRequiredStorageSpaceSizeToCopyAll"}, {1001, nullptr, "LoadAlbumScreenShotThumbnailImageEx0"}, - {1002, &IAlbumAccessorService::LoadAlbumScreenShotImageEx1, "LoadAlbumScreenShotImageEx1"}, - {1003, &IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1, "LoadAlbumScreenShotThumbnailImageEx1"}, + {1002, C<&IAlbumAccessorService::LoadAlbumScreenShotImageEx1>, "LoadAlbumScreenShotImageEx1"}, + {1003, C<&IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1>, "LoadAlbumScreenShotThumbnailImageEx1"}, {8001, nullptr, "ForceAlbumUnmounted"}, {8002, nullptr, "ResetAlbumMountStatus"}, {8011, nullptr, "RefreshAlbumCache"}, @@ -62,138 +62,70 @@ IAlbumAccessorService::IAlbumAccessorService(Core::System& system_, IAlbumAccessorService::~IAlbumAccessorService() = default; -void IAlbumAccessorService::DeleteAlbumFile(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto file_id{rp.PopRaw<AlbumFileId>()}; - +Result IAlbumAccessorService::DeleteAlbumFile(AlbumFileId file_id) { LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}", file_id.application_id, file_id.storage, file_id.type); - Result result = manager->DeleteAlbumFile(file_id); - result = TranslateResult(result); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); + const Result result = manager->DeleteAlbumFile(file_id); + R_RETURN(TranslateResult(result)); } -void IAlbumAccessorService::IsAlbumMounted(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto storage{rp.PopEnum<AlbumStorage>()}; - +Result IAlbumAccessorService::IsAlbumMounted(Out<bool> out_is_mounted, AlbumStorage storage) { LOG_INFO(Service_Capture, "called, storage={}", storage); - Result result = manager->IsAlbumMounted(storage); - const bool is_mounted = result.IsSuccess(); - result = TranslateResult(result); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(result); - rb.Push<u8>(is_mounted); + const Result result = manager->IsAlbumMounted(storage); + *out_is_mounted = result.IsSuccess(); + R_RETURN(TranslateResult(result)); } -void IAlbumAccessorService::Unknown18(HLERequestContext& ctx) { - struct UnknownBuffer { - INSERT_PADDING_BYTES(0x10); - }; - static_assert(sizeof(UnknownBuffer) == 0x10, "UnknownBuffer is an invalid size"); - +Result IAlbumAccessorService::Unknown18( + Out<u32> out_buffer_size, + OutArray<u8, BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_buffer) { LOG_WARNING(Service_Capture, "(STUBBED) called"); - - std::vector<UnknownBuffer> buffer{}; - - if (!buffer.empty()) { - ctx.WriteBuffer(buffer); - } - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast<u32>(buffer.size())); + *out_buffer_size = 0; + R_SUCCEED(); } -void IAlbumAccessorService::GetAlbumFileListEx0(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto storage{rp.PopEnum<AlbumStorage>()}; - const auto flags{rp.Pop<u8>()}; - const auto album_entry_size{ctx.GetWriteBufferNumElements<AlbumEntry>()}; - +Result IAlbumAccessorService::GetAlbumFileListEx0( + Out<u64> out_entries_size, AlbumStorage storage, u8 flags, + OutArray<AlbumEntry, BufferAttr_HipcMapAlias> out_entries) { LOG_INFO(Service_Capture, "called, storage={}, flags={}", storage, flags); - std::vector<AlbumEntry> entries; - Result result = manager->GetAlbumFileList(entries, storage, flags); - result = TranslateResult(result); - - entries.resize(std::min(album_entry_size, entries.size())); - - if (!entries.empty()) { - ctx.WriteBuffer(entries); - } - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(result); - rb.Push<u64>(entries.size()); + const Result result = manager->GetAlbumFileList(out_entries, *out_entries_size, storage, flags); + R_RETURN(TranslateResult(result)); } -void IAlbumAccessorService::GetAutoSavingStorage(HLERequestContext& ctx) { +Result IAlbumAccessorService::GetAutoSavingStorage(Out<bool> out_is_autosaving) { LOG_WARNING(Service_Capture, "(STUBBED) called"); - bool is_autosaving{}; - Result result = manager->GetAutoSavingStorage(is_autosaving); - result = TranslateResult(result); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(result); - rb.Push<u8>(is_autosaving); + const Result result = manager->GetAutoSavingStorage(*out_is_autosaving); + R_RETURN(TranslateResult(result)); } -void IAlbumAccessorService::LoadAlbumScreenShotImageEx1(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto file_id{rp.PopRaw<AlbumFileId>()}; - const auto decoder_options{rp.PopRaw<ScreenShotDecodeOption>()}; - const auto image_buffer_size{ctx.GetWriteBufferSize(1)}; - +Result IAlbumAccessorService::LoadAlbumScreenShotImageEx1( + const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options, + OutLargeData<LoadAlbumScreenShotImageOutput, BufferAttr_HipcMapAlias> out_image_output, + OutArray<u8, BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_image, + OutArray<u8, BufferAttr_HipcMapAlias> out_buffer) { LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}, flags={}", file_id.application_id, file_id.storage, file_id.type, decoder_options.flags); - std::vector<u8> image; - LoadAlbumScreenShotImageOutput image_output; - Result result = - manager->LoadAlbumScreenShotImage(image_output, image, file_id, decoder_options); - result = TranslateResult(result); - - if (image.size() > image_buffer_size) { - result = ResultWorkMemoryError; - } - - if (result.IsSuccess()) { - ctx.WriteBuffer(image_output, 0); - ctx.WriteBuffer(image, 1); - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); + const Result result = + manager->LoadAlbumScreenShotImage(*out_image_output, out_image, file_id, decoder_options); + R_RETURN(TranslateResult(result)); } -void IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto file_id{rp.PopRaw<AlbumFileId>()}; - const auto decoder_options{rp.PopRaw<ScreenShotDecodeOption>()}; - +Result IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1( + const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options, + OutLargeData<LoadAlbumScreenShotImageOutput, BufferAttr_HipcMapAlias> out_image_output, + OutArray<u8, BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_image, + OutArray<u8, BufferAttr_HipcMapAlias> out_buffer) { LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}, flags={}", file_id.application_id, file_id.storage, file_id.type, decoder_options.flags); - std::vector<u8> image(ctx.GetWriteBufferSize(1)); - LoadAlbumScreenShotImageOutput image_output; - Result result = - manager->LoadAlbumScreenShotThumbnail(image_output, image, file_id, decoder_options); - result = TranslateResult(result); - - if (result.IsSuccess()) { - ctx.WriteBuffer(image_output, 0); - ctx.WriteBuffer(image, 1); - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); + const Result result = manager->LoadAlbumScreenShotThumbnail(*out_image_output, out_image, + file_id, decoder_options); + R_RETURN(TranslateResult(result)); } Result IAlbumAccessorService::TranslateResult(Result in_result) { diff --git a/src/core/hle/service/caps/caps_a.h b/src/core/hle/service/caps/caps_a.h index c90cff71e..2cb9b4547 100644 --- a/src/core/hle/service/caps/caps_a.h +++ b/src/core/hle/service/caps/caps_a.h @@ -3,6 +3,8 @@ #pragma once +#include "core/hle/service/caps/caps_types.h" +#include "core/hle/service/cmif_types.h" #include "core/hle/service/service.h" namespace Core { @@ -19,13 +21,31 @@ public: ~IAlbumAccessorService() override; private: - void DeleteAlbumFile(HLERequestContext& ctx); - void IsAlbumMounted(HLERequestContext& ctx); - void Unknown18(HLERequestContext& ctx); - void GetAlbumFileListEx0(HLERequestContext& ctx); - void GetAutoSavingStorage(HLERequestContext& ctx); - void LoadAlbumScreenShotImageEx1(HLERequestContext& ctx); - void LoadAlbumScreenShotThumbnailImageEx1(HLERequestContext& ctx); + Result DeleteAlbumFile(AlbumFileId file_id); + + Result IsAlbumMounted(Out<bool> out_is_mounted, AlbumStorage storage); + + Result Unknown18( + Out<u32> out_buffer_size, + OutArray<u8, BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> + out_buffer); + + Result GetAlbumFileListEx0(Out<u64> out_entries_size, AlbumStorage storage, u8 flags, + OutArray<AlbumEntry, BufferAttr_HipcMapAlias> out_entries); + + Result GetAutoSavingStorage(Out<bool> out_is_autosaving); + + Result LoadAlbumScreenShotImageEx1( + const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options, + OutLargeData<LoadAlbumScreenShotImageOutput, BufferAttr_HipcMapAlias> out_image_output, + OutArray<u8, BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_image, + OutArray<u8, BufferAttr_HipcMapAlias> out_buffer); + + Result LoadAlbumScreenShotThumbnailImageEx1( + const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options, + OutLargeData<LoadAlbumScreenShotImageOutput, BufferAttr_HipcMapAlias> out_image_output, + OutArray<u8, BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_image, + OutArray<u8, BufferAttr_HipcMapAlias> out_buffer); Result TranslateResult(Result in_result); diff --git a/src/core/hle/service/caps/caps_c.cpp b/src/core/hle/service/caps/caps_c.cpp index 1e7fe6474..6993c04c2 100644 --- a/src/core/hle/service/caps/caps_c.cpp +++ b/src/core/hle/service/caps/caps_c.cpp @@ -6,6 +6,7 @@ #include "core/hle/service/caps/caps_manager.h" #include "core/hle/service/caps/caps_result.h" #include "core/hle/service/caps/caps_types.h" +#include "core/hle/service/cmif_serialization.h" #include "core/hle/service/ipc_helpers.h" namespace Service::Capture { @@ -17,7 +18,7 @@ IAlbumControlService::IAlbumControlService(Core::System& system_, static const FunctionInfo functions[] = { {1, nullptr, "CaptureRawImage"}, {2, nullptr, "CaptureRawImageWithTimeout"}, - {33, &IAlbumControlService::SetShimLibraryVersion, "SetShimLibraryVersion"}, + {33, C<&IAlbumControlService::SetShimLibraryVersion>, "SetShimLibraryVersion"}, {1001, nullptr, "RequestTakingScreenShot"}, {1002, nullptr, "RequestTakingScreenShotWithTimeout"}, {1011, nullptr, "NotifyTakingScreenShotRefused"}, @@ -42,16 +43,11 @@ IAlbumControlService::IAlbumControlService(Core::System& system_, IAlbumControlService::~IAlbumControlService() = default; -void IAlbumControlService::SetShimLibraryVersion(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto library_version{rp.Pop<u64>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - +Result IAlbumControlService::SetShimLibraryVersion(ShimLibraryVersion library_version, + ClientAppletResourceUserId aruid) { LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}", - library_version, applet_resource_user_id); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + library_version, aruid.pid); + R_SUCCEED(); } } // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_c.h b/src/core/hle/service/caps/caps_c.h index 92ba242db..0ecdfa114 100644 --- a/src/core/hle/service/caps/caps_c.h +++ b/src/core/hle/service/caps/caps_c.h @@ -3,6 +3,7 @@ #pragma once +#include "core/hle/service/cmif_types.h" #include "core/hle/service/service.h" namespace Core { @@ -11,6 +12,7 @@ class System; namespace Service::Capture { class AlbumManager; +enum class ShimLibraryVersion : u64; class IAlbumControlService final : public ServiceFramework<IAlbumControlService> { public: @@ -19,7 +21,8 @@ public: ~IAlbumControlService() override; private: - void SetShimLibraryVersion(HLERequestContext& ctx); + Result SetShimLibraryVersion(ShimLibraryVersion library_version, + ClientAppletResourceUserId aruid); std::shared_ptr<AlbumManager> manager = nullptr; }; diff --git a/src/core/hle/service/caps/caps_manager.cpp b/src/core/hle/service/caps/caps_manager.cpp index 3a22b135f..7f0bc127f 100644 --- a/src/core/hle/service/caps/caps_manager.cpp +++ b/src/core/hle/service/caps/caps_manager.cpp @@ -58,8 +58,8 @@ Result AlbumManager::IsAlbumMounted(AlbumStorage storage) { return is_mounted ? ResultSuccess : ResultIsNotMounted; } -Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage, - u8 flags) const { +Result AlbumManager::GetAlbumFileList(std::span<AlbumEntry> out_entries, u64& out_entries_count, + AlbumStorage storage, u8 flags) const { if (storage > AlbumStorage::Sd) { return ResultInvalidStorage; } @@ -72,51 +72,55 @@ Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, Albu if (file_id.storage != storage) { continue; } - if (out_entries.size() >= SdAlbumFileLimit) { + if (out_entries_count >= SdAlbumFileLimit) { + break; + } + if (out_entries_count >= out_entries.size()) { break; } const auto entry_size = Common::FS::GetSize(path); - out_entries.push_back({ + out_entries[out_entries_count++] = { .entry_size = entry_size, .file_id = file_id, - }); + }; } return ResultSuccess; } -Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, - ContentType content_type, s64 start_posix_time, - s64 end_posix_time, u64 aruid) const { +Result AlbumManager::GetAlbumFileList(std::span<ApplicationAlbumFileEntry> out_entries, + u64& out_entries_count, ContentType content_type, + s64 start_posix_time, s64 end_posix_time, u64 aruid) const { if (!is_mounted) { return ResultIsNotMounted; } - std::vector<ApplicationAlbumEntry> album_entries; + std::vector<ApplicationAlbumEntry> album_entries(out_entries.size()); const auto start_date = ConvertToAlbumDateTime(start_posix_time); const auto end_date = ConvertToAlbumDateTime(end_posix_time); - const auto result = GetAlbumFileList(album_entries, content_type, start_date, end_date, aruid); + const auto result = GetAlbumFileList(album_entries, out_entries_count, content_type, start_date, + end_date, aruid); if (result.IsError()) { return result; } - for (const auto& album_entry : album_entries) { - ApplicationAlbumFileEntry entry{ - .entry = album_entry, - .datetime = album_entry.datetime, + for (std::size_t i = 0; i < out_entries_count; i++) { + out_entries[i] = { + .entry = album_entries[i], + .datetime = album_entries[i].datetime, .unknown = {}, }; - out_entries.push_back(entry); } return ResultSuccess; } -Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries, - ContentType content_type, AlbumFileDateTime start_date, - AlbumFileDateTime end_date, u64 aruid) const { +Result AlbumManager::GetAlbumFileList(std::span<ApplicationAlbumEntry> out_entries, + u64& out_entries_count, ContentType content_type, + AlbumFileDateTime start_date, AlbumFileDateTime end_date, + u64 aruid) const { if (!is_mounted) { return ResultIsNotMounted; } @@ -131,12 +135,15 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_en if (file_id.date < end_date) { continue; } - if (out_entries.size() >= SdAlbumFileLimit) { + if (out_entries_count >= SdAlbumFileLimit) { + break; + } + if (out_entries_count >= out_entries.size()) { break; } const auto entry_size = Common::FS::GetSize(path); - ApplicationAlbumEntry entry{ + out_entries[out_entries_count++] = { .size = entry_size, .hash{}, .datetime = file_id.date, @@ -144,7 +151,6 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_en .content = content_type, .unknown = 1, }; - out_entries.push_back(entry); } return ResultSuccess; @@ -156,8 +162,7 @@ Result AlbumManager::GetAutoSavingStorage(bool& out_is_autosaving) const { } Result AlbumManager::LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output, - std::vector<u8>& out_image, - const AlbumFileId& file_id, + std::span<u8> out_image, const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options) const { if (file_id.storage > AlbumStorage::Sd) { return ResultInvalidStorage; @@ -176,7 +181,9 @@ Result AlbumManager::LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& ou .orientation = AlbumImageOrientation::None, .unknown_1{}, .unknown_2{}, + .pad163{}, }, + .pad179{}, }; std::filesystem::path path; @@ -186,14 +193,12 @@ Result AlbumManager::LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& ou return result; } - out_image.resize(out_image_output.height * out_image_output.width * STBI_rgb_alpha); - return LoadImage(out_image, path, static_cast<int>(out_image_output.width), +static_cast<int>(out_image_output.height), decoder_options.flags); } Result AlbumManager::LoadAlbumScreenShotThumbnail( - LoadAlbumScreenShotImageOutput& out_image_output, std::vector<u8>& out_image, + LoadAlbumScreenShotImageOutput& out_image_output, std::span<u8> out_image, const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options) const { if (file_id.storage > AlbumStorage::Sd) { return ResultInvalidStorage; @@ -212,7 +217,9 @@ Result AlbumManager::LoadAlbumScreenShotThumbnail( .orientation = AlbumImageOrientation::None, .unknown_1{}, .unknown_2{}, + .pad163{}, }, + .pad179{}, }; std::filesystem::path path; @@ -222,8 +229,6 @@ Result AlbumManager::LoadAlbumScreenShotThumbnail( return result; } - out_image.resize(out_image_output.height * out_image_output.width * STBI_rgb_alpha); - return LoadImage(out_image, path, static_cast<int>(out_image_output.width), +static_cast<int>(out_image_output.height), decoder_options.flags); } diff --git a/src/core/hle/service/caps/caps_manager.h b/src/core/hle/service/caps/caps_manager.h index 6fd34f589..893a9075a 100644 --- a/src/core/hle/service/caps/caps_manager.h +++ b/src/core/hle/service/caps/caps_manager.h @@ -42,20 +42,20 @@ public: Result DeleteAlbumFile(const AlbumFileId& file_id); Result IsAlbumMounted(AlbumStorage storage); - Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage, - u8 flags) const; - Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, - ContentType content_type, s64 start_posix_time, s64 end_posix_time, - u64 aruid) const; - Result GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries, + Result GetAlbumFileList(std::span<AlbumEntry> out_entries, u64& out_entries_count, + AlbumStorage storage, u8 flags) const; + Result GetAlbumFileList(std::span<ApplicationAlbumFileEntry> out_entries, + u64& out_entries_count, ContentType content_type, s64 start_posix_time, + s64 end_posix_time, u64 aruid) const; + Result GetAlbumFileList(std::span<ApplicationAlbumEntry> out_entries, u64& out_entries_count, ContentType content_type, AlbumFileDateTime start_date, AlbumFileDateTime end_date, u64 aruid) const; Result GetAutoSavingStorage(bool& out_is_autosaving) const; Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output, - std::vector<u8>& out_image, const AlbumFileId& file_id, + std::span<u8> out_image, const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options) const; Result LoadAlbumScreenShotThumbnail(LoadAlbumScreenShotImageOutput& out_image_output, - std::vector<u8>& out_image, const AlbumFileId& file_id, + std::span<u8> out_image, const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options) const; Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, diff --git a/src/core/hle/service/caps/caps_ss.cpp b/src/core/hle/service/caps/caps_ss.cpp index eab023568..dfa7f1a84 100644 --- a/src/core/hle/service/caps/caps_ss.cpp +++ b/src/core/hle/service/caps/caps_ss.cpp @@ -3,10 +3,9 @@ #include "common/logging/log.h" #include "core/hle/service/caps/caps_manager.h" -#include "core/hle/service/caps/caps_types.h" -#include "core/hle/service/ipc_helpers.h" - #include "core/hle/service/caps/caps_ss.h" +#include "core/hle/service/cmif_serialization.h" +#include "core/hle/service/ipc_helpers.h" namespace Service::Capture { @@ -17,9 +16,9 @@ IScreenShotService::IScreenShotService(Core::System& system_, static const FunctionInfo functions[] = { {201, nullptr, "SaveScreenShot"}, {202, nullptr, "SaveEditedScreenShot"}, - {203, &IScreenShotService::SaveScreenShotEx0, "SaveScreenShotEx0"}, + {203, C<&IScreenShotService::SaveScreenShotEx0>, "SaveScreenShotEx0"}, {204, nullptr, "SaveEditedScreenShotEx0"}, - {206, &IScreenShotService::SaveEditedScreenShotEx1, "SaveEditedScreenShotEx1"}, + {206, C<&IScreenShotService::SaveEditedScreenShotEx1>, "SaveEditedScreenShotEx1"}, {208, nullptr, "SaveScreenShotOfMovieEx1"}, {1000, nullptr, "Unknown1000"}, }; @@ -30,69 +29,38 @@ IScreenShotService::IScreenShotService(Core::System& system_, IScreenShotService::~IScreenShotService() = default; -void IScreenShotService::SaveScreenShotEx0(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - struct Parameters { - ScreenShotAttribute attribute{}; - AlbumReportOption report_option{}; - INSERT_PADDING_BYTES(0x4); - u64 applet_resource_user_id{}; - }; - static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size."); - - const auto parameters{rp.PopRaw<Parameters>()}; - const auto image_data_buffer = ctx.ReadBuffer(); - +Result IScreenShotService::SaveScreenShotEx0( + Out<ApplicationAlbumEntry> out_entry, const ScreenShotAttribute& attribute, + AlbumReportOption report_option, ClientAppletResourceUserId aruid, + InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> + image_data_buffer) { LOG_INFO(Service_Capture, "called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}", - parameters.report_option, image_data_buffer.size(), - parameters.applet_resource_user_id); + report_option, image_data_buffer.size(), aruid.pid); - ApplicationAlbumEntry entry{}; manager->FlipVerticallyOnWrite(false); - const auto result = - manager->SaveScreenShot(entry, parameters.attribute, parameters.report_option, - image_data_buffer, parameters.applet_resource_user_id); - - IPC::ResponseBuilder rb{ctx, 10}; - rb.Push(result); - rb.PushRaw(entry); + R_RETURN(manager->SaveScreenShot(*out_entry, attribute, report_option, image_data_buffer, + aruid.pid)); } -void IScreenShotService::SaveEditedScreenShotEx1(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - struct Parameters { - ScreenShotAttribute attribute; - u64 width; - u64 height; - u64 thumbnail_width; - u64 thumbnail_height; - AlbumFileId file_id; - }; - static_assert(sizeof(Parameters) == 0x78, "Parameters has incorrect size."); - - const auto parameters{rp.PopRaw<Parameters>()}; - const auto application_data_buffer = ctx.ReadBuffer(0); - const auto image_data_buffer = ctx.ReadBuffer(1); - const auto thumbnail_image_data_buffer = ctx.ReadBuffer(2); - +Result IScreenShotService::SaveEditedScreenShotEx1( + Out<ApplicationAlbumEntry> out_entry, const ScreenShotAttribute& attribute, u64 width, + u64 height, u64 thumbnail_width, u64 thumbnail_height, const AlbumFileId& file_id, + const InLargeData<std::array<u8, 0x400>, BufferAttr_HipcMapAlias> application_data_buffer, + const InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> + image_data_buffer, + const InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> + thumbnail_image_data_buffer) { LOG_INFO(Service_Capture, "called, width={}, height={}, thumbnail_width={}, thumbnail_height={}, " - "application_id={:016x}, storage={}, type={}, app_data_buffer_size={}, " + "application_id={:016x}, storage={}, type={}, " "image_data_buffer_size={}, thumbnail_image_buffer_size={}", - parameters.width, parameters.height, parameters.thumbnail_width, - parameters.thumbnail_height, parameters.file_id.application_id, - parameters.file_id.storage, parameters.file_id.type, application_data_buffer.size(), - image_data_buffer.size(), thumbnail_image_data_buffer.size()); + width, height, thumbnail_width, thumbnail_height, file_id.application_id, + file_id.storage, file_id.type, image_data_buffer.size(), + thumbnail_image_data_buffer.size()); - ApplicationAlbumEntry entry{}; manager->FlipVerticallyOnWrite(false); - const auto result = manager->SaveEditedScreenShot(entry, parameters.attribute, - parameters.file_id, image_data_buffer); - - IPC::ResponseBuilder rb{ctx, 10}; - rb.Push(result); - rb.PushRaw(entry); + R_RETURN(manager->SaveEditedScreenShot(*out_entry, attribute, file_id, image_data_buffer)); } } // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_ss.h b/src/core/hle/service/caps/caps_ss.h index a7e9972ab..da4b4cc5f 100644 --- a/src/core/hle/service/caps/caps_ss.h +++ b/src/core/hle/service/caps/caps_ss.h @@ -3,6 +3,8 @@ #pragma once +#include "core/hle/service/caps/caps_types.h" +#include "core/hle/service/cmif_types.h" #include "core/hle/service/service.h" namespace Core { @@ -17,8 +19,20 @@ public: ~IScreenShotService() override; private: - void SaveScreenShotEx0(HLERequestContext& ctx); - void SaveEditedScreenShotEx1(HLERequestContext& ctx); + Result SaveScreenShotEx0( + Out<ApplicationAlbumEntry> out_entry, const ScreenShotAttribute& attribute, + AlbumReportOption report_option, ClientAppletResourceUserId aruid, + InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> + image_data_buffer); + + Result SaveEditedScreenShotEx1( + Out<ApplicationAlbumEntry> out_entry, const ScreenShotAttribute& attribute, u64 width, + u64 height, u64 thumbnail_width, u64 thumbnail_height, const AlbumFileId& file_id, + const InLargeData<std::array<u8, 0x400>, BufferAttr_HipcMapAlias> application_data_buffer, + const InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> + image_data_buffer, + const InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> + thumbnail_image_data_buffer); std::shared_ptr<AlbumManager> manager; }; diff --git a/src/core/hle/service/caps/caps_su.cpp b/src/core/hle/service/caps/caps_su.cpp index 296b07b00..528f364f5 100644 --- a/src/core/hle/service/caps/caps_su.cpp +++ b/src/core/hle/service/caps/caps_su.cpp @@ -6,6 +6,7 @@ #include "core/hle/service/caps/caps_manager.h" #include "core/hle/service/caps/caps_su.h" #include "core/hle/service/caps/caps_types.h" +#include "core/hle/service/cmif_serialization.h" #include "core/hle/service/ipc_helpers.h" #include "video_core/renderer_base.h" @@ -16,10 +17,10 @@ IScreenShotApplicationService::IScreenShotApplicationService( : ServiceFramework{system_, "caps:su"}, manager{album_manager} { // clang-format off static const FunctionInfo functions[] = { - {32, &IScreenShotApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"}, + {32, C<&IScreenShotApplicationService::SetShimLibraryVersion>, "SetShimLibraryVersion"}, {201, nullptr, "SaveScreenShot"}, - {203, &IScreenShotApplicationService::SaveScreenShotEx0, "SaveScreenShotEx0"}, - {205, &IScreenShotApplicationService::SaveScreenShotEx1, "SaveScreenShotEx1"}, + {203, C<&IScreenShotApplicationService::SaveScreenShotEx0>, "SaveScreenShotEx0"}, + {205, C<&IScreenShotApplicationService::SaveScreenShotEx1>, "SaveScreenShotEx1"}, {210, nullptr, "SaveScreenShotEx2"}, }; // clang-format on @@ -29,77 +30,40 @@ IScreenShotApplicationService::IScreenShotApplicationService( IScreenShotApplicationService::~IScreenShotApplicationService() = default; -void IScreenShotApplicationService::SetShimLibraryVersion(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto library_version{rp.Pop<u64>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - +Result IScreenShotApplicationService::SetShimLibraryVersion(ShimLibraryVersion library_version, + ClientAppletResourceUserId aruid) { LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}", - library_version, applet_resource_user_id); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + library_version, aruid.pid); + R_SUCCEED(); } -void IScreenShotApplicationService::SaveScreenShotEx0(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - struct Parameters { - ScreenShotAttribute attribute{}; - AlbumReportOption report_option{}; - INSERT_PADDING_BYTES(0x4); - u64 applet_resource_user_id{}; - }; - static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size."); - - const auto parameters{rp.PopRaw<Parameters>()}; - const auto image_data_buffer = ctx.ReadBuffer(); - +Result IScreenShotApplicationService::SaveScreenShotEx0( + Out<ApplicationAlbumEntry> out_entry, const ScreenShotAttribute& attribute, + AlbumReportOption report_option, ClientAppletResourceUserId aruid, + InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> + image_data_buffer) { LOG_INFO(Service_Capture, "called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}", - parameters.report_option, image_data_buffer.size(), - parameters.applet_resource_user_id); + report_option, image_data_buffer.size(), aruid.pid); - ApplicationAlbumEntry entry{}; manager->FlipVerticallyOnWrite(false); - const auto result = - manager->SaveScreenShot(entry, parameters.attribute, parameters.report_option, - image_data_buffer, parameters.applet_resource_user_id); - - IPC::ResponseBuilder rb{ctx, 10}; - rb.Push(result); - rb.PushRaw(entry); + R_RETURN(manager->SaveScreenShot(*out_entry, attribute, report_option, image_data_buffer, + aruid.pid)); } -void IScreenShotApplicationService::SaveScreenShotEx1(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - struct Parameters { - ScreenShotAttribute attribute{}; - AlbumReportOption report_option{}; - INSERT_PADDING_BYTES(0x4); - u64 applet_resource_user_id{}; - }; - static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size."); - - const auto parameters{rp.PopRaw<Parameters>()}; - const auto app_data_buffer = ctx.ReadBuffer(0); - const auto image_data_buffer = ctx.ReadBuffer(1); - +Result IScreenShotApplicationService::SaveScreenShotEx1( + Out<ApplicationAlbumEntry> out_entry, const ScreenShotAttribute& attribute, + AlbumReportOption report_option, ClientAppletResourceUserId aruid, + const InLargeData<ApplicationData, BufferAttr_HipcMapAlias> app_data_buffer, + const InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> + image_data_buffer) { LOG_INFO(Service_Capture, "called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}", - parameters.report_option, image_data_buffer.size(), - parameters.applet_resource_user_id); + report_option, image_data_buffer.size(), aruid.pid); - ApplicationAlbumEntry entry{}; - ApplicationData app_data{}; - std::memcpy(&app_data, app_data_buffer.data(), sizeof(ApplicationData)); manager->FlipVerticallyOnWrite(false); - const auto result = - manager->SaveScreenShot(entry, parameters.attribute, parameters.report_option, app_data, - image_data_buffer, parameters.applet_resource_user_id); - - IPC::ResponseBuilder rb{ctx, 10}; - rb.Push(result); - rb.PushRaw(entry); + R_RETURN(manager->SaveScreenShot(*out_entry, attribute, report_option, *app_data_buffer, + image_data_buffer, aruid.pid)); } void IScreenShotApplicationService::CaptureAndSaveScreenshot(AlbumReportOption report_option) { @@ -112,6 +76,7 @@ void IScreenShotApplicationService::CaptureAndSaveScreenshot(AlbumReportOption r .orientation = Capture::AlbumImageOrientation::None, .unknown_1{}, .unknown_2{}, + .pad163{}, }; renderer.RequestScreenshot( diff --git a/src/core/hle/service/caps/caps_su.h b/src/core/hle/service/caps/caps_su.h index 21912e95f..4b4cbd09e 100644 --- a/src/core/hle/service/caps/caps_su.h +++ b/src/core/hle/service/caps/caps_su.h @@ -3,6 +3,8 @@ #pragma once +#include "core/hle/service/caps/caps_types.h" +#include "core/hle/service/cmif_types.h" #include "core/hle/service/service.h" namespace Core { @@ -26,9 +28,19 @@ private: static constexpr std::size_t screenshot_height = 720; static constexpr std::size_t bytes_per_pixel = 4; - void SetShimLibraryVersion(HLERequestContext& ctx); - void SaveScreenShotEx0(HLERequestContext& ctx); - void SaveScreenShotEx1(HLERequestContext& ctx); + Result SetShimLibraryVersion(ShimLibraryVersion library_version, + ClientAppletResourceUserId aruid); + Result SaveScreenShotEx0( + Out<ApplicationAlbumEntry> out_entry, const ScreenShotAttribute& attribute, + AlbumReportOption report_option, ClientAppletResourceUserId aruid, + InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> + image_data_buffer); + Result SaveScreenShotEx1( + Out<ApplicationAlbumEntry> out_entry, const ScreenShotAttribute& attribute, + AlbumReportOption report_option, ClientAppletResourceUserId aruid, + const InLargeData<ApplicationData, BufferAttr_HipcMapAlias> app_data_buffer, + const InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> + image_data_buffer); std::array<u8, screenshot_width * screenshot_height * bytes_per_pixel> image_data; diff --git a/src/core/hle/service/caps/caps_types.h b/src/core/hle/service/caps/caps_types.h index 589ac28d3..3deaaad5b 100644 --- a/src/core/hle/service/caps/caps_types.h +++ b/src/core/hle/service/caps/caps_types.h @@ -41,6 +41,10 @@ enum class ScreenShotDecoderFlag : u64 { EnableBlockSmoothing = 1 << 1, }; +enum class ShimLibraryVersion : u64 { + Version1 = 1, +}; + // This is nn::capsrv::AlbumFileDateTime struct AlbumFileDateTime { s16 year{}; @@ -144,19 +148,23 @@ static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30, "ApplicationAlbumFileEntry has incorrect size."); struct ApplicationData { - std::array<u8, 0x400> data{}; - u32 data_size{}; + std::array<u8, 0x400> data; + u32 data_size; }; static_assert(sizeof(ApplicationData) == 0x404, "ApplicationData is an invalid size"); +static_assert(std::is_trivial_v<ApplicationData>, + "ApplicationData type must be trivially copyable."); struct ScreenShotAttribute { - u32 unknown_0{}; - AlbumImageOrientation orientation{}; - u32 unknown_1{}; - u32 unknown_2{}; - INSERT_PADDING_BYTES(0x30); + u32 unknown_0; + AlbumImageOrientation orientation; + u32 unknown_1; + u32 unknown_2; + INSERT_PADDING_BYTES_NOINIT(0x30); }; static_assert(sizeof(ScreenShotAttribute) == 0x40, "ScreenShotAttribute is an invalid size"); +static_assert(std::is_trivial_v<ScreenShotAttribute>, + "ScreenShotAttribute type must be trivially copyable."); struct ScreenShotDecodeOption { ScreenShotDecoderFlag flags{}; @@ -165,13 +173,15 @@ struct ScreenShotDecodeOption { static_assert(sizeof(ScreenShotDecodeOption) == 0x20, "ScreenShotDecodeOption is an invalid size"); struct LoadAlbumScreenShotImageOutput { - s64 width{}; - s64 height{}; - ScreenShotAttribute attribute{}; - INSERT_PADDING_BYTES(0x400); + s64 width; + s64 height; + ScreenShotAttribute attribute; + INSERT_PADDING_BYTES_NOINIT(0x400); }; static_assert(sizeof(LoadAlbumScreenShotImageOutput) == 0x450, "LoadAlbumScreenShotImageOutput is an invalid size"); +static_assert(std::is_trivial_v<LoadAlbumScreenShotImageOutput>, + "LoadAlbumScreenShotImageOutput type must be trivially copyable."); struct LoadAlbumScreenShotImageOutputForApplication { s64 width{}; diff --git a/src/core/hle/service/caps/caps_u.cpp b/src/core/hle/service/caps/caps_u.cpp index b6b33fb2f..40d4d05fe 100644 --- a/src/core/hle/service/caps/caps_u.cpp +++ b/src/core/hle/service/caps/caps_u.cpp @@ -5,6 +5,7 @@ #include "core/hle/service/caps/caps_manager.h" #include "core/hle/service/caps/caps_types.h" #include "core/hle/service/caps/caps_u.h" +#include "core/hle/service/cmif_serialization.h" #include "core/hle/service/ipc_helpers.h" namespace Service::Capture { @@ -14,8 +15,8 @@ IAlbumApplicationService::IAlbumApplicationService(Core::System& system_, : ServiceFramework{system_, "caps:u"}, manager{album_manager} { // clang-format off static const FunctionInfo functions[] = { - {32, &IAlbumApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"}, - {102, &IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated, "GetAlbumFileList0AafeAruidDeprecated"}, + {32, C<&IAlbumApplicationService::SetShimLibraryVersion>, "SetShimLibraryVersion"}, + {102, C<&IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated>, "GetAlbumFileList0AafeAruidDeprecated"}, {103, nullptr, "DeleteAlbumFileByAruid"}, {104, nullptr, "GetAlbumFileSizeByAruid"}, {105, nullptr, "DeleteAlbumFileByAruidForDebug"}, @@ -24,7 +25,7 @@ IAlbumApplicationService::IAlbumApplicationService(Core::System& system_, {130, nullptr, "PrecheckToCreateContentsByAruid"}, {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"}, {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"}, - {142, &IAlbumApplicationService::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"}, + {142, C<&IAlbumApplicationService::GetAlbumFileList3AaeAruid>, "GetAlbumFileList3AaeAruid"}, {143, nullptr, "GetAlbumFileList4AaeUidAruid"}, {144, nullptr, "GetAllAlbumFileList3AaeAruid"}, {60002, nullptr, "OpenAccessorSessionForApplication"}, @@ -36,101 +37,40 @@ IAlbumApplicationService::IAlbumApplicationService(Core::System& system_, IAlbumApplicationService::~IAlbumApplicationService() = default; -void IAlbumApplicationService::SetShimLibraryVersion(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto library_version{rp.Pop<u64>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - +Result IAlbumApplicationService::SetShimLibraryVersion(ShimLibraryVersion library_version, + ClientAppletResourceUserId aruid) { LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}", - library_version, applet_resource_user_id); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + library_version, aruid.pid); + R_SUCCEED(); } -void IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - struct Parameters { - ContentType content_type; - INSERT_PADDING_BYTES(7); - s64 start_posix_time; - s64 end_posix_time; - u64 applet_resource_user_id; - }; - static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size."); - - const auto parameters{rp.PopRaw<Parameters>()}; - +Result IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated( + Out<u64> out_entries_count, ContentType content_type, s64 start_posix_time, s64 end_posix_time, + ClientAppletResourceUserId aruid, + OutArray<ApplicationAlbumFileEntry, BufferAttr_HipcMapAlias> out_entries) { LOG_WARNING(Service_Capture, "(STUBBED) called. content_type={}, start_posix_time={}, end_posix_time={}, " "applet_resource_user_id={}", - parameters.content_type, parameters.start_posix_time, parameters.end_posix_time, - parameters.applet_resource_user_id); - - Result result = ResultSuccess; - - if (result.IsSuccess()) { - result = manager->IsAlbumMounted(AlbumStorage::Sd); - } - - std::vector<ApplicationAlbumFileEntry> entries; - if (result.IsSuccess()) { - result = manager->GetAlbumFileList(entries, parameters.content_type, - parameters.start_posix_time, parameters.end_posix_time, - parameters.applet_resource_user_id); - } + content_type, start_posix_time, end_posix_time, aruid.pid); - if (!entries.empty()) { - ctx.WriteBuffer(entries); - } - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(result); - rb.Push<u64>(entries.size()); + R_TRY(manager->IsAlbumMounted(AlbumStorage::Sd)); + R_RETURN(manager->GetAlbumFileList(out_entries, *out_entries_count, content_type, + start_posix_time, end_posix_time, aruid.pid)); } -void IAlbumApplicationService::GetAlbumFileList3AaeAruid(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - struct Parameters { - ContentType content_type; - INSERT_PADDING_BYTES(1); - AlbumFileDateTime start_date_time; - AlbumFileDateTime end_date_time; - INSERT_PADDING_BYTES(6); - u64 applet_resource_user_id; - }; - static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size."); - - const auto parameters{rp.PopRaw<Parameters>()}; - +Result IAlbumApplicationService::GetAlbumFileList3AaeAruid( + Out<u64> out_entries_count, ContentType content_type, AlbumFileDateTime start_date_time, + AlbumFileDateTime end_date_time, ClientAppletResourceUserId aruid, + OutArray<ApplicationAlbumEntry, BufferAttr_HipcMapAlias> out_entries) { LOG_WARNING(Service_Capture, "(STUBBED) called. content_type={}, start_date={}/{}/{}, " "end_date={}/{}/{}, applet_resource_user_id={}", - parameters.content_type, parameters.start_date_time.year, - parameters.start_date_time.month, parameters.start_date_time.day, - parameters.end_date_time.year, parameters.end_date_time.month, - parameters.end_date_time.day, parameters.applet_resource_user_id); - - Result result = ResultSuccess; - - if (result.IsSuccess()) { - result = manager->IsAlbumMounted(AlbumStorage::Sd); - } - - std::vector<ApplicationAlbumEntry> entries; - if (result.IsSuccess()) { - result = - manager->GetAlbumFileList(entries, parameters.content_type, parameters.start_date_time, - parameters.end_date_time, parameters.applet_resource_user_id); - } - - if (!entries.empty()) { - ctx.WriteBuffer(entries); - } + content_type, start_date_time.year, start_date_time.month, start_date_time.day, + end_date_time.year, end_date_time.month, end_date_time.day, aruid.pid); - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(result); - rb.Push<u64>(entries.size()); + R_TRY(manager->IsAlbumMounted(AlbumStorage::Sd)); + R_RETURN(manager->GetAlbumFileList(out_entries, *out_entries_count, content_type, + start_date_time, end_date_time, aruid.pid)); } } // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_u.h b/src/core/hle/service/caps/caps_u.h index 9458c128e..023ee1fe7 100644 --- a/src/core/hle/service/caps/caps_u.h +++ b/src/core/hle/service/caps/caps_u.h @@ -3,6 +3,7 @@ #pragma once +#include "core/hle/service/cmif_types.h" #include "core/hle/service/service.h" namespace Core { @@ -19,9 +20,18 @@ public: ~IAlbumApplicationService() override; private: - void SetShimLibraryVersion(HLERequestContext& ctx); - void GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx); - void GetAlbumFileList3AaeAruid(HLERequestContext& ctx); + Result SetShimLibraryVersion(ShimLibraryVersion library_version, + ClientAppletResourceUserId aruid); + + Result GetAlbumFileList0AafeAruidDeprecated( + Out<u64> out_entries_count, ContentType content_type, s64 start_posix_time, + s64 end_posix_time, ClientAppletResourceUserId aruid, + OutArray<ApplicationAlbumFileEntry, BufferAttr_HipcMapAlias> out_entries); + + Result GetAlbumFileList3AaeAruid( + Out<u64> out_entries_count, ContentType content_type, AlbumFileDateTime start_date_time, + AlbumFileDateTime end_date_time, ClientAppletResourceUserId aruid, + OutArray<ApplicationAlbumEntry, BufferAttr_HipcMapAlias> out_entries); std::shared_ptr<AlbumManager> manager = nullptr; }; diff --git a/src/core/hle/service/cmif_serialization.h b/src/core/hle/service/cmif_serialization.h index 9ee26400d..315475e71 100644 --- a/src/core/hle/service/cmif_serialization.h +++ b/src/core/hle/service/cmif_serialization.h @@ -122,14 +122,14 @@ struct RequestLayout { u32 domain_interface_count; }; -template <ArgumentType Type1, ArgumentType Type2, typename MethodArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t ArgIndex = 0> -constexpr u32 GetArgumentRawDataSize() { +template <typename MethodArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t ArgIndex = 0> +constexpr u32 GetInRawDataSize() { if constexpr (ArgIndex >= std::tuple_size_v<MethodArguments>) { return static_cast<u32>(DataOffset); } else { using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>; - if constexpr (ArgumentTraits<ArgType>::Type == Type1 || ArgumentTraits<ArgType>::Type == Type2) { + if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InData || ArgumentTraits<ArgType>::Type == ArgumentType::InProcessId) { constexpr size_t ArgAlign = alignof(ArgType); constexpr size_t ArgSize = sizeof(ArgType); @@ -138,9 +138,33 @@ constexpr u32 GetArgumentRawDataSize() { constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); constexpr size_t ArgEnd = ArgOffset + ArgSize; - return GetArgumentRawDataSize<Type1, Type2, MethodArguments, ArgAlign, ArgEnd, ArgIndex + 1>(); + return GetInRawDataSize<MethodArguments, ArgAlign, ArgEnd, ArgIndex + 1>(); + } else { + return GetInRawDataSize<MethodArguments, PrevAlign, DataOffset, ArgIndex + 1>(); + } + } +} + +template <typename MethodArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t ArgIndex = 0> +constexpr u32 GetOutRawDataSize() { + if constexpr (ArgIndex >= std::tuple_size_v<MethodArguments>) { + return static_cast<u32>(DataOffset); + } else { + using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>; + + if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutData) { + using RawArgType = typename ArgType::Type; + constexpr size_t ArgAlign = alignof(RawArgType); + constexpr size_t ArgSize = sizeof(RawArgType); + + static_assert(PrevAlign <= ArgAlign, "Output argument is not ordered by alignment"); + + constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); + constexpr size_t ArgEnd = ArgOffset + ArgSize; + + return GetOutRawDataSize<MethodArguments, ArgAlign, ArgEnd, ArgIndex + 1>(); } else { - return GetArgumentRawDataSize<Type1, Type2, MethodArguments, PrevAlign, DataOffset, ArgIndex + 1>(); + return GetOutRawDataSize<MethodArguments, PrevAlign, DataOffset, ArgIndex + 1>(); } } } @@ -165,7 +189,7 @@ constexpr RequestLayout GetNonDomainReplyInLayout() { return RequestLayout{ .copy_handle_count = GetArgumentTypeCount<ArgumentType::InCopyHandle, MethodArguments>(), .move_handle_count = 0, - .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::InData, ArgumentType::InProcessId, MethodArguments>(), + .cmif_raw_data_size = GetInRawDataSize<MethodArguments>(), .domain_interface_count = 0, }; } @@ -175,7 +199,7 @@ constexpr RequestLayout GetDomainReplyInLayout() { return RequestLayout{ .copy_handle_count = GetArgumentTypeCount<ArgumentType::InCopyHandle, MethodArguments>(), .move_handle_count = 0, - .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::InData, ArgumentType::InProcessId, MethodArguments>(), + .cmif_raw_data_size = GetInRawDataSize<MethodArguments>(), .domain_interface_count = GetArgumentTypeCount<ArgumentType::InInterface, MethodArguments>(), }; } @@ -185,7 +209,7 @@ constexpr RequestLayout GetNonDomainReplyOutLayout() { return RequestLayout{ .copy_handle_count = GetArgumentTypeCount<ArgumentType::OutCopyHandle, MethodArguments>(), .move_handle_count = GetArgumentTypeCount<ArgumentType::OutMoveHandle, MethodArguments>() + GetArgumentTypeCount<ArgumentType::OutInterface, MethodArguments>(), - .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::OutData, ArgumentType::OutData, MethodArguments>(), + .cmif_raw_data_size = GetOutRawDataSize<MethodArguments>(), .domain_interface_count = 0, }; } @@ -195,7 +219,7 @@ constexpr RequestLayout GetDomainReplyOutLayout() { return RequestLayout{ .copy_handle_count = GetArgumentTypeCount<ArgumentType::OutCopyHandle, MethodArguments>(), .move_handle_count = GetArgumentTypeCount<ArgumentType::OutMoveHandle, MethodArguments>(), - .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::OutData, ArgumentType::OutData, MethodArguments>(), + .cmif_raw_data_size = GetOutRawDataSize<MethodArguments>(), .domain_interface_count = GetArgumentTypeCount<ArgumentType::OutInterface, MethodArguments>(), }; } @@ -259,7 +283,7 @@ void ReadInArgument(bool is_domain, CallArguments& args, const u8* raw_data, HLE return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex + 1, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InLargeData) { - constexpr size_t BufferSize = sizeof(ArgType); + constexpr size_t BufferSize = sizeof(typename ArgType::Type); // Clear the existing data. std::memset(&std::get<ArgIndex>(args), 0, BufferSize); @@ -300,7 +324,7 @@ void ReadInArgument(bool is_domain, CallArguments& args, const u8* raw_data, HLE return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) { - constexpr size_t BufferSize = sizeof(ArgType); + constexpr size_t BufferSize = sizeof(typename ArgType::Type); // Clear the existing data. std::memset(&std::get<ArgIndex>(args).raw, 0, BufferSize); @@ -337,13 +361,15 @@ void WriteOutArgument(bool is_domain, CallArguments& args, u8* raw_data, HLERequ using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>; if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutData) { - constexpr size_t ArgAlign = alignof(ArgType); - constexpr size_t ArgSize = sizeof(ArgType); + using RawArgType = decltype(std::get<ArgIndex>(args).raw); + constexpr size_t ArgAlign = alignof(RawArgType); + constexpr size_t ArgSize = sizeof(RawArgType); static_assert(PrevAlign <= ArgAlign, "Output argument is not ordered by alignment"); static_assert(!RawDataFinished, "All output interface arguments must appear after raw data"); static_assert(!std::is_pointer_v<ArgType>, "Output raw data must not be a pointer"); - static_assert(std::is_trivially_copyable_v<decltype(std::get<ArgIndex>(args).raw)>, "Output raw data must be trivially copyable"); + static_assert(!std::is_pointer_v<RawArgType>, "Output raw data must not be a pointer"); + static_assert(std::is_trivially_copyable_v<RawArgType>, "Output raw data must be trivially copyable"); constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); constexpr size_t ArgEnd = ArgOffset + ArgSize; @@ -368,7 +394,7 @@ void WriteOutArgument(bool is_domain, CallArguments& args, u8* raw_data, HLERequ return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) { - constexpr size_t BufferSize = sizeof(ArgType); + constexpr size_t BufferSize = sizeof(typename ArgType::Type); ASSERT(ctx.CanWriteBuffer(OutBufferIndex)); if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) { 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/k_event.h" +#include "core/hle/service/event.h" +#include "core/hle/service/kernel_helpers.h" + +namespace Service { + +Event::Event(KernelHelpers::ServiceContext& ctx) { + m_event = ctx.CreateEvent("Event"); +} + +Event::~Event() { + m_event->GetReadableEvent().Close(); + m_event->Close(); +} + +void Event::Signal() { + m_event->Signal(); +} + +void Event::Clear() { + m_event->Clear(); +} + +Kernel::KReadableEvent* Event::GetHandle() { + return &m_event->GetReadableEvent(); +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +namespace Kernel { +class KEvent; +class KReadableEvent; +} // namespace Kernel + +namespace Service { + +namespace KernelHelpers { +class ServiceContext; +} + +class Event { +public: + explicit Event(KernelHelpers::ServiceContext& ctx); + ~Event(); + + void Signal(); + void Clear(); + + Kernel::KReadableEvent* GetHandle(); + +private: + Kernel::KEvent* m_event; +}; + +} // namespace Service diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp index 2be72b021..5fe534c73 100644 --- a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp @@ -15,11 +15,13 @@ #include "common/settings.h" #include "common/string_util.h" #include "core/core.h" +#include "core/file_sys/content_archive.h" #include "core/file_sys/errors.h" #include "core/file_sys/fs_directory.h" #include "core/file_sys/fs_filesystem.h" #include "core/file_sys/nca_metadata.h" #include "core/file_sys/patch_manager.h" +#include "core/file_sys/romfs.h" #include "core/file_sys/romfs_factory.h" #include "core/file_sys/savedata_factory.h" #include "core/file_sys/system_archive/system_archive.h" @@ -33,18 +35,20 @@ #include "core/hle/service/filesystem/save_data_controller.h" #include "core/hle/service/hle_ipc.h" #include "core/hle/service/ipc_helpers.h" +#include "core/loader/loader.h" #include "core/reporter.h" namespace Service::FileSystem { -enum class FileSystemType : u8 { - Invalid0 = 0, - Invalid1 = 1, +enum class FileSystemProxyType : u8 { + Code = 0, + Rom = 1, Logo = 2, - ContentControl = 3, - ContentManual = 4, - ContentMeta = 5, - ContentData = 6, - ApplicationPackage = 7, + Control = 3, + Manual = 4, + Meta = 5, + Data = 6, + Package = 7, + RegisteredUpdate = 8, }; class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { @@ -357,12 +361,30 @@ void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) { void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto type = rp.PopRaw<FileSystemType>(); - const auto title_id = rp.PopRaw<u64>(); - LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}", type, title_id); + struct InputParameters { + FileSystemProxyType type; + u64 program_id; + }; + static_assert(sizeof(InputParameters) == 0x10, "InputParameters has wrong size"); + + const auto params = rp.PopRaw<InputParameters>(); + LOG_ERROR(Service_FS, "(STUBBED) called with type={}, program_id={:016X}", params.type, + params.program_id); + + // FIXME: many issues with this + ASSERT(params.type == FileSystemProxyType::Manual); + const auto manual_romfs = romfs_controller->OpenPatchedRomFS( + params.program_id, FileSys::ContentRecordType::HtmlDocument); - IPC::ResponseBuilder rb{ctx, 2, 0, 0}; - rb.Push(ResultUnknown); + ASSERT(manual_romfs != nullptr); + + const auto extracted_romfs = FileSys::ExtractRomFS(manual_romfs); + ASSERT(extracted_romfs != nullptr); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IFileSystem>(system, extracted_romfs, + SizeGetter::FromStorageId(fsc, FileSys::StorageId::NandUser)); } void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) { diff --git a/src/core/hle/service/glue/time/time_zone.cpp b/src/core/hle/service/glue/time/time_zone.cpp index 5dc1187cb..98d928697 100644 --- a/src/core/hle/service/glue/time/time_zone.cpp +++ b/src/core/hle/service/glue/time/time_zone.cpp @@ -197,32 +197,27 @@ Result TimeZoneService::ToCalendarTimeWithMyRule( Result TimeZoneService::ToPosixTime(Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times, - Out<u32> out_times_count, - Service::PSC::Time::CalendarTime& calendar_time, InRule rule) { + const Service::PSC::Time::CalendarTime& calendar_time, + InRule rule) { SCOPE_EXIT({ LOG_DEBUG(Service_Time, - "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} " - "out_times_count={}", - calendar_time, *out_count, out_times[0], out_times[1], *out_times_count); + "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}", + calendar_time, *out_count, out_times[0], out_times[1]); }); - R_RETURN( - m_wrapped_service->ToPosixTime(out_count, out_times, out_times_count, calendar_time, rule)); + R_RETURN(m_wrapped_service->ToPosixTime(out_count, out_times, calendar_time, rule)); } -Result TimeZoneService::ToPosixTimeWithMyRule(Out<u32> out_count, - OutArray<s64, BufferAttr_HipcPointer> out_times, - Out<u32> out_times_count, - Service::PSC::Time::CalendarTime& calendar_time) { +Result TimeZoneService::ToPosixTimeWithMyRule( + Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times, + const Service::PSC::Time::CalendarTime& calendar_time) { SCOPE_EXIT({ LOG_DEBUG(Service_Time, - "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} " - "out_times_count={}", - calendar_time, *out_count, out_times[0], out_times[1], *out_times_count); + "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}", + calendar_time, *out_count, out_times[0], out_times[1]); }); - R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, out_times_count, - calendar_time)); + R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, calendar_time)); } } // namespace Service::Glue::Time diff --git a/src/core/hle/service/glue/time/time_zone.h b/src/core/hle/service/glue/time/time_zone.h index bf12adbdc..9c1530966 100644 --- a/src/core/hle/service/glue/time/time_zone.h +++ b/src/core/hle/service/glue/time/time_zone.h @@ -68,12 +68,10 @@ public: Out<Service::PSC::Time::CalendarTime> out_calendar_time, Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time); Result ToPosixTime(Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times, - Out<u32> out_times_count, Service::PSC::Time::CalendarTime& calendar_time, - InRule rule); + const Service::PSC::Time::CalendarTime& calendar_time, InRule rule); Result ToPosixTimeWithMyRule(Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times, - Out<u32> out_times_count, - Service::PSC::Time::CalendarTime& calendar_time); + const Service::PSC::Time::CalendarTime& calendar_time); private: Core::System& m_system; diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 5b28be577..b60fb9139 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -18,9 +18,10 @@ namespace Service::HID { void LoopProcess(Core::System& system) { auto server_manager = std::make_unique<ServerManager>(system); - std::shared_ptr<ResourceManager> resource_manager = std::make_shared<ResourceManager>(system); std::shared_ptr<HidFirmwareSettings> firmware_settings = std::make_shared<HidFirmwareSettings>(system); + std::shared_ptr<ResourceManager> resource_manager = + std::make_shared<ResourceManager>(system, firmware_settings); // TODO: Remove this hack when am is emulated properly. resource_manager->Initialize(); @@ -31,7 +32,7 @@ void LoopProcess(Core::System& system) { server_manager->RegisterNamedService( "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings)); server_manager->RegisterNamedService( - "hid:dbg", std::make_shared<IHidDebugServer>(system, resource_manager)); + "hid:dbg", std::make_shared<IHidDebugServer>(system, resource_manager, firmware_settings)); server_manager->RegisterNamedService( "hid:sys", std::make_shared<IHidSystemServer>(system, resource_manager, firmware_settings)); diff --git a/src/core/hle/service/hid/hid_debug_server.cpp b/src/core/hle/service/hid/hid_debug_server.cpp index f2a767d37..610af34dd 100644 --- a/src/core/hle/service/hid/hid_debug_server.cpp +++ b/src/core/hle/service/hid/hid_debug_server.cpp @@ -1,27 +1,37 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later +#include <algorithm> + #include "core/hle/service/hid/hid_debug_server.h" #include "core/hle/service/ipc_helpers.h" +#include "hid_core/hid_types.h" #include "hid_core/resource_manager.h" +#include "hid_core/resources/hid_firmware_settings.h" + +#include "hid_core/resources/touch_screen/gesture.h" +#include "hid_core/resources/touch_screen/touch_screen.h" +#include "hid_core/resources/touch_screen/touch_types.h" namespace Service::HID { -IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource) - : ServiceFramework{system_, "hid:dbg"}, resource_manager{resource} { +IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource, + std::shared_ptr<HidFirmwareSettings> settings) + : ServiceFramework{system_, "hid:dbg"}, resource_manager{resource}, firmware_settings{ + settings} { // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "DeactivateDebugPad"}, {1, nullptr, "SetDebugPadAutoPilotState"}, {2, nullptr, "UnsetDebugPadAutoPilotState"}, - {10, nullptr, "DeactivateTouchScreen"}, - {11, nullptr, "SetTouchScreenAutoPilotState"}, - {12, nullptr, "UnsetTouchScreenAutoPilotState"}, - {13, nullptr, "GetTouchScreenConfiguration"}, - {14, nullptr, "ProcessTouchScreenAutoTune"}, - {15, nullptr, "ForceStopTouchScreenManagement"}, - {16, nullptr, "ForceRestartTouchScreenManagement"}, - {17, nullptr, "IsTouchScreenManaged"}, + {10, &IHidDebugServer::DeactivateTouchScreen, "DeactivateTouchScreen"}, + {11, &IHidDebugServer::SetTouchScreenAutoPilotState, "SetTouchScreenAutoPilotState"}, + {12, &IHidDebugServer::UnsetTouchScreenAutoPilotState, "UnsetTouchScreenAutoPilotState"}, + {13, &IHidDebugServer::GetTouchScreenConfiguration, "GetTouchScreenConfiguration"}, + {14, &IHidDebugServer::ProcessTouchScreenAutoTune, "ProcessTouchScreenAutoTune"}, + {15, &IHidDebugServer::ForceStopTouchScreenManagement, "ForceStopTouchScreenManagement"}, + {16, &IHidDebugServer::ForceRestartTouchScreenManagement, "ForceRestartTouchScreenManagement"}, + {17, &IHidDebugServer::IsTouchScreenManaged, "IsTouchScreenManaged"}, {20, nullptr, "DeactivateMouse"}, {21, nullptr, "SetMouseAutoPilotState"}, {22, nullptr, "UnsetMouseAutoPilotState"}, @@ -37,7 +47,7 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource {60, nullptr, "ClearNpadSystemCommonPolicy"}, {61, nullptr, "DeactivateNpad"}, {62, nullptr, "ForceDisconnectNpad"}, - {91, nullptr, "DeactivateGesture"}, + {91, &IHidDebugServer::DeactivateGesture, "DeactivateGesture"}, {110, nullptr, "DeactivateHomeButton"}, {111, nullptr, "SetHomeButtonAutoPilotState"}, {112, nullptr, "UnsetHomeButtonAutoPilotState"}, @@ -150,6 +160,170 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource } IHidDebugServer::~IHidDebugServer() = default; +void IHidDebugServer::DeactivateTouchScreen(HLERequestContext& ctx) { + LOG_INFO(Service_HID, "called"); + + Result result = ResultSuccess; + + if (!firmware_settings->IsDeviceManaged()) { + result = GetResourceManager()->GetTouchScreen()->Deactivate(); + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void IHidDebugServer::SetTouchScreenAutoPilotState(HLERequestContext& ctx) { + AutoPilotState auto_pilot{}; + auto_pilot.count = ctx.GetReadBufferNumElements<TouchState>(); + const auto buffer = ctx.ReadBuffer(); + + auto_pilot.count = std::min(auto_pilot.count, static_cast<u64>(auto_pilot.state.size())); + memcpy(auto_pilot.state.data(), buffer.data(), auto_pilot.count * sizeof(TouchState)); + + LOG_INFO(Service_HID, "called, auto_pilot_count={}", auto_pilot.count); + + const Result result = + GetResourceManager()->GetTouchScreen()->SetTouchScreenAutoPilotState(auto_pilot); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void IHidDebugServer::UnsetTouchScreenAutoPilotState(HLERequestContext& ctx) { + LOG_INFO(Service_HID, "called"); + + const Result result = GetResourceManager()->GetTouchScreen()->UnsetTouchScreenAutoPilotState(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void IHidDebugServer::GetTouchScreenConfiguration(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + + Core::HID::TouchScreenConfigurationForNx touchscreen_config{}; + const Result result = GetResourceManager()->GetTouchScreen()->GetTouchScreenConfiguration( + touchscreen_config, applet_resource_user_id); + + if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 && + touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) { + touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting; + } + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(result); + rb.PushRaw(touchscreen_config); +} + +void IHidDebugServer::ProcessTouchScreenAutoTune(HLERequestContext& ctx) { + LOG_INFO(Service_HID, "called"); + + Result result = GetResourceManager()->GetTouchScreen()->ProcessTouchScreenAutoTune(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void IHidDebugServer::ForceStopTouchScreenManagement(HLERequestContext& ctx) { + LOG_INFO(Service_HID, "called"); + + if (!firmware_settings->IsDeviceManaged()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + return; + } + + Result result = ResultSuccess; + bool is_touch_active{}; + bool is_gesture_active{}; + auto touch_screen = GetResourceManager()->GetTouchScreen(); + auto gesture = GetResourceManager()->GetGesture(); + + if (firmware_settings->IsTouchI2cManaged()) { + result = touch_screen->IsActive(is_touch_active); + if (result.IsSuccess()) { + result = gesture->IsActive(is_gesture_active); + } + if (result.IsSuccess() && is_touch_active) { + result = touch_screen->Deactivate(); + } + if (result.IsSuccess() && is_gesture_active) { + result = gesture->Deactivate(); + } + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void IHidDebugServer::ForceRestartTouchScreenManagement(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + struct Parameters { + u32 basic_gesture_id; + INSERT_PADDING_WORDS_NOINIT(1); + u64 applet_resource_user_id; + }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); + + const auto parameters{rp.PopRaw<Parameters>()}; + + LOG_INFO(Service_HID, "called, basic_gesture_id={}, applet_resource_user_id={}", + parameters.basic_gesture_id, parameters.applet_resource_user_id); + + Result result = ResultSuccess; + auto touch_screen = GetResourceManager()->GetTouchScreen(); + auto gesture = GetResourceManager()->GetGesture(); + + if (firmware_settings->IsDeviceManaged() && firmware_settings->IsTouchI2cManaged()) { + result = gesture->Activate(); + if (result.IsSuccess()) { + result = + gesture->Activate(parameters.applet_resource_user_id, parameters.basic_gesture_id); + } + if (result.IsSuccess()) { + result = touch_screen->Activate(); + } + if (result.IsSuccess()) { + result = touch_screen->Activate(parameters.applet_resource_user_id); + } + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void IHidDebugServer::IsTouchScreenManaged(HLERequestContext& ctx) { + LOG_INFO(Service_HID, "called"); + + bool is_touch_active{}; + bool is_gesture_active{}; + + Result result = GetResourceManager()->GetTouchScreen()->IsActive(is_touch_active); + if (result.IsSuccess()) { + result = GetResourceManager()->GetGesture()->IsActive(is_gesture_active); + } + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(result); + rb.Push(is_touch_active | is_gesture_active); +} + +void IHidDebugServer::DeactivateGesture(HLERequestContext& ctx) { + LOG_INFO(Service_HID, "called"); + + Result result = ResultSuccess; + + if (!firmware_settings->IsDeviceManaged()) { + result = GetResourceManager()->GetGesture()->Deactivate(); + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} std::shared_ptr<ResourceManager> IHidDebugServer::GetResourceManager() { resource_manager->Initialize(); diff --git a/src/core/hle/service/hid/hid_debug_server.h b/src/core/hle/service/hid/hid_debug_server.h index 406db2211..7d5b082b3 100644 --- a/src/core/hle/service/hid/hid_debug_server.h +++ b/src/core/hle/service/hid/hid_debug_server.h @@ -11,16 +11,29 @@ class System; namespace Service::HID { class ResourceManager; +class HidFirmwareSettings; class IHidDebugServer final : public ServiceFramework<IHidDebugServer> { public: - explicit IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource); + explicit IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource, + std::shared_ptr<HidFirmwareSettings> settings); ~IHidDebugServer() override; private: + void DeactivateTouchScreen(HLERequestContext& ctx); + void SetTouchScreenAutoPilotState(HLERequestContext& ctx); + void UnsetTouchScreenAutoPilotState(HLERequestContext& ctx); + void GetTouchScreenConfiguration(HLERequestContext& ctx); + void ProcessTouchScreenAutoTune(HLERequestContext& ctx); + void ForceStopTouchScreenManagement(HLERequestContext& ctx); + void ForceRestartTouchScreenManagement(HLERequestContext& ctx); + void IsTouchScreenManaged(HLERequestContext& ctx); + void DeactivateGesture(HLERequestContext& ctx); + std::shared_ptr<ResourceManager> GetResourceManager(); std::shared_ptr<ResourceManager> resource_manager; + std::shared_ptr<HidFirmwareSettings> firmware_settings; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp index 09c47b5e3..3603d8ccf 100644 --- a/src/core/hle/service/hid/hid_server.cpp +++ b/src/core/hle/service/hid/hid_server.cpp @@ -8,6 +8,7 @@ #include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/service/cmif_serialization.h" #include "core/hle/service/hid/hid_server.h" #include "core/hle/service/ipc_helpers.h" #include "core/memory.h" @@ -153,7 +154,7 @@ IHidServer::IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> r {104, &IHidServer::DeactivateNpad, "DeactivateNpad"}, {106, &IHidServer::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"}, {107, &IHidServer::DisconnectNpad, "DisconnectNpad"}, - {108, &IHidServer::GetPlayerLedPattern, "GetPlayerLedPattern"}, + {108, C<&IHidServer::GetPlayerLedPattern>, "GetPlayerLedPattern"}, {109, &IHidServer::ActivateNpadWithRevision, "ActivateNpadWithRevision"}, {120, &IHidServer::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, {121, &IHidServer::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, @@ -989,8 +990,7 @@ void IHidServer::ActivateGesture(HLERequestContext& ctx) { } if (result.IsSuccess()) { - // TODO: Use gesture id here - result = gesture->Activate(parameters.applet_resource_user_id); + result = gesture->Activate(parameters.applet_resource_user_id, parameters.basic_gesture_id); } IPC::ResponseBuilder rb{ctx, 2}; @@ -1136,19 +1136,39 @@ void IHidServer::DisconnectNpad(HLERequestContext& ctx) { rb.Push(ResultSuccess); } -void IHidServer::GetPlayerLedPattern(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()}; - - Core::HID::LedPattern pattern{0, 0, 0, 0}; - auto controller = GetResourceManager()->GetNpad(); - const auto result = controller->GetLedPattern(npad_id, pattern); - +Result IHidServer::GetPlayerLedPattern(Out<Core::HID::LedPattern> out_led_pattern, + Core::HID::NpadIdType npad_id) { LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(result); - rb.Push(pattern.raw); + switch (npad_id) { + case Core::HID::NpadIdType::Player1: + *out_led_pattern = Core::HID::LedPattern{1, 0, 0, 0}; + R_SUCCEED(); + case Core::HID::NpadIdType::Player2: + *out_led_pattern = Core::HID::LedPattern{1, 1, 0, 0}; + R_SUCCEED(); + case Core::HID::NpadIdType::Player3: + *out_led_pattern = Core::HID::LedPattern{1, 1, 1, 0}; + R_SUCCEED(); + case Core::HID::NpadIdType::Player4: + *out_led_pattern = Core::HID::LedPattern{1, 1, 1, 1}; + R_SUCCEED(); + case Core::HID::NpadIdType::Player5: + *out_led_pattern = Core::HID::LedPattern{1, 0, 0, 1}; + R_SUCCEED(); + case Core::HID::NpadIdType::Player6: + *out_led_pattern = Core::HID::LedPattern{1, 0, 1, 0}; + R_SUCCEED(); + case Core::HID::NpadIdType::Player7: + *out_led_pattern = Core::HID::LedPattern{1, 0, 1, 1}; + R_SUCCEED(); + case Core::HID::NpadIdType::Player8: + *out_led_pattern = Core::HID::LedPattern{0, 1, 1, 0}; + R_SUCCEED(); + default: + *out_led_pattern = Core::HID::LedPattern{0, 0, 0, 0}; + R_SUCCEED(); + } } void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) { @@ -2449,14 +2469,22 @@ void IHidServer::GetNpadCommunicationMode(HLERequestContext& ctx) { void IHidServer::SetTouchScreenConfiguration(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto touchscreen_mode{rp.PopRaw<Core::HID::TouchScreenConfigurationForNx>()}; + auto touchscreen_config{rp.PopRaw<Core::HID::TouchScreenConfigurationForNx>()}; const auto applet_resource_user_id{rp.Pop<u64>()}; - LOG_WARNING(Service_HID, "(STUBBED) called, touchscreen_mode={}, applet_resource_user_id={}", - touchscreen_mode.mode, applet_resource_user_id); + LOG_INFO(Service_HID, "called, touchscreen_config={}, applet_resource_user_id={}", + touchscreen_config.mode, applet_resource_user_id); + + if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 && + touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) { + touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting; + } + + const Result result = GetResourceManager()->GetTouchScreen()->SetTouchScreenConfiguration( + touchscreen_config, applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IHidServer::IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx) { @@ -2484,11 +2512,12 @@ void IHidServer::SetTouchScreenResolution(HLERequestContext& ctx) { const auto height{rp.Pop<u32>()}; const auto applet_resource_user_id{rp.Pop<u64>()}; - GetResourceManager()->GetTouchScreen()->SetTouchscreenDimensions(width, height); - LOG_INFO(Service_HID, "called, width={}, height={}, applet_resource_user_id={}", width, height, applet_resource_user_id); + GetResourceManager()->GetTouchScreen()->SetTouchScreenResolution(width, height, + applet_resource_user_id); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } diff --git a/src/core/hle/service/hid/hid_server.h b/src/core/hle/service/hid/hid_server.h index 3a2e0a230..faf775689 100644 --- a/src/core/hle/service/hid/hid_server.h +++ b/src/core/hle/service/hid/hid_server.h @@ -3,7 +3,9 @@ #pragma once +#include "core/hle/service/cmif_types.h" #include "core/hle/service/service.h" +#include "hid_core/hid_types.h" namespace Core { class System; @@ -66,7 +68,8 @@ private: void DeactivateNpad(HLERequestContext& ctx); void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx); void DisconnectNpad(HLERequestContext& ctx); - void GetPlayerLedPattern(HLERequestContext& ctx); + Result GetPlayerLedPattern(Out<Core::HID::LedPattern> out_led_pattern, + Core::HID::NpadIdType npad_id); void ActivateNpadWithRevision(HLERequestContext& ctx); void SetNpadJoyHoldType(HLERequestContext& ctx); void GetNpadJoyHoldType(HLERequestContext& ctx); diff --git a/src/core/hle/service/hid/hid_system_server.cpp b/src/core/hle/service/hid/hid_system_server.cpp index d1ec42edc..22471e9e2 100644 --- a/src/core/hle/service/hid/hid_system_server.cpp +++ b/src/core/hle/service/hid/hid_system_server.cpp @@ -155,9 +155,9 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour {1133, nullptr, "StartUsbFirmwareUpdate"}, {1134, nullptr, "GetUsbFirmwareUpdateState"}, {1135, &IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory, "InitializeUsbFirmwareUpdateWithoutMemory"}, - {1150, nullptr, "SetTouchScreenMagnification"}, - {1151, nullptr, "GetTouchScreenFirmwareVersion"}, - {1152, nullptr, "SetTouchScreenDefaultConfiguration"}, + {1150, &IHidSystemServer::SetTouchScreenMagnification, "SetTouchScreenMagnification"}, + {1151, &IHidSystemServer::GetTouchScreenFirmwareVersion, "GetTouchScreenFirmwareVersion"}, + {1152, &IHidSystemServer::SetTouchScreenDefaultConfiguration, "SetTouchScreenDefaultConfiguration"}, {1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"}, {1154, nullptr, "IsFirmwareAvailableForNotification"}, {1155, &IHidSystemServer::SetForceHandheldStyleVibration, "SetForceHandheldStyleVibration"}, @@ -845,12 +845,60 @@ void IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContex rb.Push(ResultSuccess); } +void IHidSystemServer::SetTouchScreenMagnification(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto point1x{rp.Pop<f32>()}; + const auto point1y{rp.Pop<f32>()}; + const auto point2x{rp.Pop<f32>()}; + const auto point2y{rp.Pop<f32>()}; + + LOG_INFO(Service_HID, "called, point1=-({},{}), point2=({},{})", point1x, point1y, point2x, + point2y); + + const Result result = GetResourceManager()->GetTouchScreen()->SetTouchScreenMagnification( + point1x, point1y, point2x, point2y); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void IHidSystemServer::GetTouchScreenFirmwareVersion(HLERequestContext& ctx) { + LOG_INFO(Service_HID, "called"); + + Core::HID::FirmwareVersion firmware{}; + const auto result = GetResourceManager()->GetTouchScreenFirmwareVersion(firmware); + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(result); + rb.PushRaw(firmware); +} + +void IHidSystemServer::SetTouchScreenDefaultConfiguration(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + auto touchscreen_config{rp.PopRaw<Core::HID::TouchScreenConfigurationForNx>()}; + + LOG_INFO(Service_HID, "called, touchscreen_config={}", touchscreen_config.mode); + + if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 && + touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) { + touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting; + } + + const Result result = + GetResourceManager()->GetTouchScreen()->SetTouchScreenDefaultConfiguration( + touchscreen_config); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); + LOG_INFO(Service_HID, "called"); - Core::HID::TouchScreenConfigurationForNx touchscreen_config{ - .mode = Core::HID::TouchScreenModeForNx::Finger, - }; + Core::HID::TouchScreenConfigurationForNx touchscreen_config{}; + const Result result = + GetResourceManager()->GetTouchScreen()->GetTouchScreenDefaultConfiguration( + touchscreen_config); if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 && touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) { @@ -858,7 +906,7 @@ void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx } IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); + rb.Push(result); rb.PushRaw(touchscreen_config); } diff --git a/src/core/hle/service/hid/hid_system_server.h b/src/core/hle/service/hid/hid_system_server.h index 4ab4d3931..738313e08 100644 --- a/src/core/hle/service/hid/hid_system_server.h +++ b/src/core/hle/service/hid/hid_system_server.h @@ -71,6 +71,9 @@ private: void FinalizeUsbFirmwareUpdate(HLERequestContext& ctx); void CheckUsbFirmwareUpdateRequired(HLERequestContext& ctx); void InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx); + void SetTouchScreenMagnification(HLERequestContext& ctx); + void GetTouchScreenFirmwareVersion(HLERequestContext& ctx); + void SetTouchScreenDefaultConfiguration(HLERequestContext& ctx); void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx); void SetForceHandheldStyleVibration(HLERequestContext& ctx); void IsUsingCustomButtonConfig(HLERequestContext& ctx); diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp index b4d16fed5..efb7f6e32 100644 --- a/src/core/hle/service/mii/mii.cpp +++ b/src/core/hle/service/mii/mii.cpp @@ -111,7 +111,8 @@ private: R_RETURN(result); } - Result UpdateLatest(Out<CharInfo> out_char_info, CharInfo& char_info, SourceFlag source_flag) { + Result UpdateLatest(Out<CharInfo> out_char_info, const CharInfo& char_info, + SourceFlag source_flag) { LOG_INFO(Service_Mii, "called with source_flag={}", source_flag); R_RETURN(manager->UpdateLatest(metadata, *out_char_info, char_info, source_flag)); @@ -159,7 +160,7 @@ private: R_RETURN(result); } - Result UpdateLatest1(Out<StoreData> out_store_data, StoreData& store_data, + Result UpdateLatest1(Out<StoreData> out_store_data, const StoreData& store_data, SourceFlag source_flag) { LOG_INFO(Service_Mii, "called with source_flag={}", source_flag); R_UNLESS(is_system, ResultPermissionDenied); @@ -243,7 +244,7 @@ private: R_SUCCEED(); } - Result GetIndex(Out<s32> out_index, CharInfo& char_info) { + Result GetIndex(Out<s32> out_index, const CharInfo& char_info) { LOG_DEBUG(Service_Mii, "called"); R_RETURN(manager->GetIndex(metadata, char_info, *out_index)); @@ -257,25 +258,25 @@ private: R_SUCCEED(); } - Result Convert(Out<CharInfo> out_char_info, Ver3StoreData& mii_v3) { + Result Convert(Out<CharInfo> out_char_info, const Ver3StoreData& mii_v3) { LOG_INFO(Service_Mii, "called"); R_RETURN(manager->ConvertV3ToCharInfo(*out_char_info, mii_v3)); } - Result ConvertCoreDataToCharInfo(Out<CharInfo> out_char_info, CoreData& core_data) { + Result ConvertCoreDataToCharInfo(Out<CharInfo> out_char_info, const CoreData& core_data) { LOG_INFO(Service_Mii, "called"); R_RETURN(manager->ConvertCoreDataToCharInfo(*out_char_info, core_data)); } - Result ConvertCharInfoToCoreData(Out<CoreData> out_core_data, CharInfo& char_info) { + Result ConvertCharInfoToCoreData(Out<CoreData> out_core_data, const CharInfo& char_info) { LOG_INFO(Service_Mii, "called"); R_RETURN(manager->ConvertCharInfoToCoreData(*out_core_data, char_info)); } - Result Append(CharInfo& char_info) { + Result Append(const CharInfo& char_info) { LOG_INFO(Service_Mii, "called"); R_RETURN(manager->Append(metadata, char_info)); diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 22dc55a6d..8e3224f73 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -185,7 +185,7 @@ public: {3, &IRequest::Cancel, "Cancel"}, {4, &IRequest::Submit, "Submit"}, {5, nullptr, "SetRequirement"}, - {6, nullptr, "SetRequirementPreset"}, + {6, &IRequest::SetRequirementPreset, "SetRequirementPreset"}, {8, nullptr, "SetPriority"}, {9, nullptr, "SetNetworkProfileId"}, {10, nullptr, "SetRejectable"}, @@ -237,6 +237,16 @@ private: rb.PushEnum(state); } + void SetRequirementPreset(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto param_1 = rp.Pop<u32>(); + + LOG_WARNING(Service_NIFM, "(STUBBED) called, param_1={}", param_1); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + void GetResult(HLERequestContext& ctx) { LOG_DEBUG(Service_NIFM, "(STUBBED) called"); diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 2258ee609..19c3ff01b 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp @@ -3,6 +3,7 @@ #include "common/logging/log.h" #include "common/settings.h" +#include "core/arm/debug.h" #include "core/core.h" #include "core/file_sys/control_metadata.h" #include "core/file_sys/patch_manager.h" @@ -544,8 +545,8 @@ IDocumentInterface::IDocumentInterface(Core::System& system_) // clang-format off static const FunctionInfo functions[] = { {21, nullptr, "GetApplicationContentPath"}, - {23, nullptr, "ResolveApplicationContentPath"}, - {93, nullptr, "GetRunningApplicationProgramId"}, + {23, &IDocumentInterface::ResolveApplicationContentPath, "ResolveApplicationContentPath"}, + {92, &IDocumentInterface::GetRunningApplicationProgramId, "GetRunningApplicationProgramId"}, }; // clang-format on @@ -554,6 +555,32 @@ IDocumentInterface::IDocumentInterface(Core::System& system_) IDocumentInterface::~IDocumentInterface() = default; +void IDocumentInterface::ResolveApplicationContentPath(HLERequestContext& ctx) { + struct ContentPath { + u8 file_system_proxy_type; + u64 program_id; + }; + static_assert(sizeof(ContentPath) == 0x10, "ContentPath has wrong size"); + + IPC::RequestParser rp{ctx}; + auto content_path = rp.PopRaw<ContentPath>(); + LOG_WARNING(Service_NS, "(STUBBED) called, file_system_proxy_type={}, program_id={:016X}", + content_path.file_system_proxy_type, content_path.program_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IDocumentInterface::GetRunningApplicationProgramId(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto caller_program_id = rp.PopRaw<u64>(); + LOG_WARNING(Service_NS, "(STUBBED) called, caller_program_id={:016X}", caller_program_id); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(system.GetApplicationProcessProgramID()); +} + IDownloadTaskInterface::IDownloadTaskInterface(Core::System& system_) : ServiceFramework{system_, "IDownloadTaskInterface"} { // clang-format off @@ -613,6 +640,40 @@ IFactoryResetInterface::IFactoryResetInterface(Core::System& system_) IFactoryResetInterface::~IFactoryResetInterface() = default; +IReadOnlyApplicationRecordInterface::IReadOnlyApplicationRecordInterface(Core::System& system_) + : ServiceFramework{system_, "IReadOnlyApplicationRecordInterface"} { + static const FunctionInfo functions[] = { + {0, &IReadOnlyApplicationRecordInterface::HasApplicationRecord, "HasApplicationRecord"}, + {1, nullptr, "NotifyApplicationFailure"}, + {2, &IReadOnlyApplicationRecordInterface::IsDataCorruptedResult, "IsDataCorruptedResult"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IReadOnlyApplicationRecordInterface::~IReadOnlyApplicationRecordInterface() = default; + +void IReadOnlyApplicationRecordInterface::HasApplicationRecord(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 program_id = rp.PopRaw<u64>(); + LOG_WARNING(Service_NS, "(STUBBED) called, program_id={:X}", program_id); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u8>(1); +} + +void IReadOnlyApplicationRecordInterface::IsDataCorruptedResult(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto result = rp.PopRaw<Result>(); + LOG_WARNING(Service_NS, "(STUBBED) called, result={:#x}", result.GetInnerValue()); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u8>(0); +} + IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface( Core::System& system_) : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} { @@ -663,7 +724,7 @@ NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name static const FunctionInfo functions[] = { {7988, nullptr, "GetDynamicRightsInterface"}, {7989, &NS::PushInterface<IReadOnlyApplicationControlDataInterface>, "GetReadOnlyApplicationControlDataInterface"}, - {7991, nullptr, "GetReadOnlyApplicationRecordInterface"}, + {7991, &NS::PushInterface<IReadOnlyApplicationRecordInterface>, "GetReadOnlyApplicationRecordInterface"}, {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"}, {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"}, {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"}, diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h index 34d2a45dc..9ee306ef9 100644 --- a/src/core/hle/service/ns/ns.h +++ b/src/core/hle/service/ns/ns.h @@ -58,6 +58,10 @@ class IDocumentInterface final : public ServiceFramework<IDocumentInterface> { public: explicit IDocumentInterface(Core::System& system_); ~IDocumentInterface() override; + +private: + void ResolveApplicationContentPath(HLERequestContext& ctx); + void GetRunningApplicationProgramId(HLERequestContext& ctx); }; class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> { @@ -78,6 +82,17 @@ public: ~IFactoryResetInterface() override; }; +class IReadOnlyApplicationRecordInterface final + : public ServiceFramework<IReadOnlyApplicationRecordInterface> { +public: + explicit IReadOnlyApplicationRecordInterface(Core::System& system_); + ~IReadOnlyApplicationRecordInterface() override; + +private: + void HasApplicationRecord(HLERequestContext& ctx); + void IsDataCorruptedResult(HLERequestContext& ctx); +}; + class IReadOnlyApplicationControlDataInterface final : public ServiceFramework<IReadOnlyApplicationControlDataInterface> { public: diff --git a/src/core/hle/service/nvdrv/core/container.cpp b/src/core/hle/service/nvdrv/core/container.cpp index dc1b4d5be..e89cca6f2 100644 --- a/src/core/hle/service/nvdrv/core/container.cpp +++ b/src/core/hle/service/nvdrv/core/container.cpp @@ -83,7 +83,9 @@ SessionId Container::OpenSession(Kernel::KProcess* process) { // Check if this memory block is heap. if (svc_mem_info.state == Kernel::Svc::MemoryState::Normal) { - if (svc_mem_info.size > region_size) { + if (region_start + region_size == svc_mem_info.base_address) { + region_size += svc_mem_info.size; + } else if (svc_mem_info.size > region_size) { region_size = svc_mem_info.size; region_start = svc_mem_info.base_address; } diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index c1ebbd62d..abe95303e 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include <boost/container/small_vector.hpp> + #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" @@ -38,19 +40,30 @@ NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in void nvdisp_disp0::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {} void nvdisp_disp0::OnClose(DeviceFD fd) {} -void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, - u32 height, u32 stride, android::BufferTransformFlags transform, - const Common::Rectangle<int>& crop_rect, - std::array<Service::Nvidia::NvFence, 4>& fences, u32 num_fences) { - const DAddr addr = nvmap.GetHandleAddress(buffer_handle); - LOG_TRACE(Service, - "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", - addr, offset, width, height, stride, format); +void nvdisp_disp0::Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers) { + std::vector<Tegra::FramebufferConfig> output_layers; + std::vector<Service::Nvidia::NvFence> output_fences; + output_layers.reserve(sorted_layers.size()); + output_fences.reserve(sorted_layers.size()); + + for (auto& layer : sorted_layers) { + output_layers.emplace_back(Tegra::FramebufferConfig{ + .address = nvmap.GetHandleAddress(layer.buffer_handle), + .offset = layer.offset, + .width = layer.width, + .height = layer.height, + .stride = layer.stride, + .pixel_format = layer.format, + .transform_flags = layer.transform, + .crop_rect = layer.crop_rect, + }); - const Tegra::FramebufferConfig framebuffer{addr, offset, width, height, - stride, format, transform, crop_rect}; + for (size_t i = 0; i < layer.acquire_fence.num_fences; i++) { + output_fences.push_back(layer.acquire_fence.fences[i]); + } + } - system.GPU().RequestSwapBuffers(&framebuffer, fences, num_fences); + system.GPU().RequestComposite(std::move(output_layers), std::move(output_fences)); system.SpeedLimiter().DoSpeedLimiting(system.CoreTiming().GetGlobalTimeUs()); system.GetPerfStats().EndSystemFrame(); system.GetPerfStats().BeginSystemFrame(); diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index 5f13a50a2..1082b85c2 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -8,8 +8,7 @@ #include "common/common_types.h" #include "common/math_util.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" -#include "core/hle/service/nvnflinger/buffer_transform_flags.h" -#include "core/hle/service/nvnflinger/pixel_format.h" +#include "core/hle/service/nvnflinger/hwc_layer.h" namespace Service::Nvidia::NvCore { class Container; @@ -35,11 +34,8 @@ public: void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; - /// Performs a screen flip, drawing the buffer pointed to by the handle. - void flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, u32 height, - u32 stride, android::BufferTransformFlags transform, - const Common::Rectangle<int>& crop_rect, - std::array<Service::Nvidia::NvFence, 4>& fences, u32 num_fences); + /// Performs a screen flip, compositing each buffer. + void Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers); Kernel::KEvent* QueryEvent(u32 event_id) override; 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 // Ensure we maintain a clean state on failure. ON_RESULT_FAILURE { - ASSERT(R_SUCCEEDED(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd))); + R_ASSERT(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd)); }; // Assign the allocated memory to the handle. diff --git a/src/core/hle/service/nvnflinger/hardware_composer.cpp b/src/core/hle/service/nvnflinger/hardware_composer.cpp new file mode 100644 index 000000000..c720dd1f8 --- /dev/null +++ b/src/core/hle/service/nvnflinger/hardware_composer.cpp @@ -0,0 +1,215 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include <boost/container/small_vector.hpp> + +#include "common/microprofile.h" +#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" +#include "core/hle/service/nvnflinger/buffer_item.h" +#include "core/hle/service/nvnflinger/buffer_item_consumer.h" +#include "core/hle/service/nvnflinger/buffer_queue_producer.h" +#include "core/hle/service/nvnflinger/hardware_composer.h" +#include "core/hle/service/nvnflinger/hwc_layer.h" +#include "core/hle/service/nvnflinger/ui/graphic_buffer.h" +#include "core/hle/service/vi/display/vi_display.h" +#include "core/hle/service/vi/layer/vi_layer.h" + +namespace Service::Nvnflinger { + +namespace { + +s32 NormalizeSwapInterval(f32* out_speed_scale, s32 swap_interval) { + if (swap_interval <= 0) { + // As an extension, treat nonpositive swap interval as speed multiplier. + if (out_speed_scale) { + *out_speed_scale = 2.f * static_cast<f32>(1 - swap_interval); + } + + swap_interval = 1; + } + + if (swap_interval >= 5) { + // As an extension, treat high swap interval as precise speed control. + if (out_speed_scale) { + *out_speed_scale = static_cast<f32>(swap_interval) / 100.f; + } + + swap_interval = 1; + } + + return swap_interval; +} + +} // namespace + +HardwareComposer::HardwareComposer() = default; +HardwareComposer::~HardwareComposer() = default; + +u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, + Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance) { + boost::container::small_vector<HwcLayer, 2> composition_stack; + + m_frame_number += frame_advance; + + // Release any necessary framebuffers. + for (auto& [layer_id, framebuffer] : m_framebuffers) { + if (framebuffer.release_frame_number > m_frame_number) { + // Not yet ready to release this framebuffer. + continue; + } + + if (!framebuffer.is_acquired) { + // Already released. + continue; + } + + if (auto* layer = display.FindLayer(layer_id); layer != nullptr) { + // TODO: support release fence + // This is needed to prevent screen tearing + layer->GetConsumer().ReleaseBuffer(framebuffer.item, android::Fence::NoFence()); + framebuffer.is_acquired = false; + } + } + + // Set default speed limit to 100%. + *out_speed_scale = 1.0f; + + // Determine the number of vsync periods to wait before composing again. + std::optional<s32> swap_interval{}; + bool has_acquired_buffer{}; + + // Acquire all necessary framebuffers. + for (size_t i = 0; i < display.GetNumLayers(); i++) { + auto& layer = display.GetLayer(i); + auto layer_id = layer.GetLayerId(); + + // Try to fetch the framebuffer (either new or stale). + const auto result = this->CacheFramebufferLocked(layer, layer_id); + + // If we failed, skip this layer. + if (result == CacheStatus::NoBufferAvailable) { + continue; + } + + // If we acquired a new buffer, we need to present. + if (result == CacheStatus::BufferAcquired) { + has_acquired_buffer = true; + } + + const auto& buffer = m_framebuffers[layer_id]; + const auto& item = buffer.item; + const auto& igbp_buffer = *item.graphic_buffer; + + // TODO: get proper Z-index from layer + composition_stack.emplace_back(HwcLayer{ + .buffer_handle = igbp_buffer.BufferId(), + .offset = igbp_buffer.Offset(), + .format = igbp_buffer.ExternalFormat(), + .width = igbp_buffer.Width(), + .height = igbp_buffer.Height(), + .stride = igbp_buffer.Stride(), + .z_index = 0, + .transform = static_cast<android::BufferTransformFlags>(item.transform), + .crop_rect = item.crop, + .acquire_fence = item.fence, + }); + + // We need to compose again either before this frame is supposed to + // be released, or exactly on the vsync period it should be released. + const s32 item_swap_interval = NormalizeSwapInterval(out_speed_scale, item.swap_interval); + + // TODO: handle cases where swap intervals are relatively prime. So far, + // only swap intervals of 0, 1 and 2 have been observed, but if 3 were + // to be introduced, this would cause an issue. + if (swap_interval) { + swap_interval = std::min(*swap_interval, item_swap_interval); + } else { + swap_interval = item_swap_interval; + } + } + + // If any new buffers were acquired, we can present. + if (has_acquired_buffer) { + // Sort by Z-index. + std::stable_sort(composition_stack.begin(), composition_stack.end(), + [&](auto& l, auto& r) { return l.z_index < r.z_index; }); + + // Composite. + nvdisp.Composite(composition_stack); + } + + // Render MicroProfile. + MicroProfileFlip(); + + // Advance by at least one frame. + return swap_interval.value_or(1); +} + +void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) { + // Check if we are tracking a slot with this layer_id. + const auto it = m_framebuffers.find(layer_id); + if (it == m_framebuffers.end()) { + return; + } + + // Try to release the buffer item. + auto* const layer = display.FindLayer(layer_id); + if (layer && it->second.is_acquired) { + layer->GetConsumer().ReleaseBuffer(it->second.item, android::Fence::NoFence()); + } + + // Erase the slot. + m_framebuffers.erase(it); +} + +bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer) { + // Attempt the update. + const auto status = layer.GetConsumer().AcquireBuffer(&framebuffer.item, {}, false); + if (status != android::Status::NoError) { + return false; + } + + // We succeeded, so set the new release frame info. + framebuffer.release_frame_number = + NormalizeSwapInterval(nullptr, framebuffer.item.swap_interval); + framebuffer.is_acquired = true; + + return true; +} + +HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(VI::Layer& layer, + LayerId layer_id) { + // Check if this framebuffer is already present. + const auto it = m_framebuffers.find(layer_id); + if (it != m_framebuffers.end()) { + // If it's currently still acquired, we are done. + if (it->second.is_acquired) { + return CacheStatus::CachedBufferReused; + } + + // Try to acquire a new item. + if (this->TryAcquireFramebufferLocked(layer, it->second)) { + // We got a new item. + return CacheStatus::BufferAcquired; + } else { + // We didn't acquire a new item, but we can reuse the slot. + return CacheStatus::CachedBufferReused; + } + } + + // Framebuffer is not present, so try to create it. + Framebuffer framebuffer{}; + + if (this->TryAcquireFramebufferLocked(layer, framebuffer)) { + // Move the buffer item into a new slot. + m_framebuffers.emplace(layer_id, std::move(framebuffer)); + + // We succeeded. + return CacheStatus::BufferAcquired; + } + + // We couldn't acquire the buffer item, so don't create a slot. + return CacheStatus::NoBufferAvailable; +} + +} // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/hardware_composer.h b/src/core/hle/service/nvnflinger/hardware_composer.h new file mode 100644 index 000000000..ddab94ac9 --- /dev/null +++ b/src/core/hle/service/nvnflinger/hardware_composer.h @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <memory> +#include <boost/container/flat_map.hpp> + +#include "core/hle/service/nvnflinger/buffer_item.h" + +namespace Service::Nvidia::Devices { +class nvdisp_disp0; +} + +namespace Service::VI { +class Display; +class Layer; +} // namespace Service::VI + +namespace Service::Nvnflinger { + +using LayerId = u64; + +class HardwareComposer { +public: + explicit HardwareComposer(); + ~HardwareComposer(); + + u32 ComposeLocked(f32* out_speed_scale, VI::Display& display, + Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance); + void RemoveLayerLocked(VI::Display& display, LayerId layer_id); + +private: + // TODO: do we want to track frame number in vi instead? + u64 m_frame_number{0}; + +private: + using ReleaseFrameNumber = u64; + + struct Framebuffer { + android::BufferItem item{}; + ReleaseFrameNumber release_frame_number{}; + bool is_acquired{false}; + }; + + enum class CacheStatus : u32 { + NoBufferAvailable, + BufferAcquired, + CachedBufferReused, + }; + + boost::container::flat_map<LayerId, Framebuffer> m_framebuffers{}; + +private: + bool TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer); + CacheStatus CacheFramebufferLocked(VI::Layer& layer, LayerId layer_id); +}; + +} // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/hwc_layer.h b/src/core/hle/service/nvnflinger/hwc_layer.h new file mode 100644 index 000000000..3af668a25 --- /dev/null +++ b/src/core/hle/service/nvnflinger/hwc_layer.h @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/math_util.h" +#include "core/hle/service/nvdrv/nvdata.h" +#include "core/hle/service/nvnflinger/buffer_transform_flags.h" +#include "core/hle/service/nvnflinger/pixel_format.h" +#include "core/hle/service/nvnflinger/ui/fence.h" + +namespace Service::Nvnflinger { + +struct HwcLayer { + u32 buffer_handle; + u32 offset; + android::PixelFormat format; + u32 width; + u32 height; + u32 stride; + s32 z_index; + android::BufferTransformFlags transform; + Common::Rectangle<int> crop_rect; + android::Fence acquire_fence; +}; + +} // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index 71d6fdb0c..a4e848882 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp @@ -18,6 +18,7 @@ #include "core/hle/service/nvnflinger/buffer_item_consumer.h" #include "core/hle/service/nvnflinger/buffer_queue_core.h" #include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" +#include "core/hle/service/nvnflinger/hardware_composer.h" #include "core/hle/service/nvnflinger/hos_binder_driver_server.h" #include "core/hle/service/nvnflinger/nvnflinger.h" #include "core/hle/service/nvnflinger/ui/graphic_buffer.h" @@ -198,6 +199,16 @@ bool Nvnflinger::CloseLayer(u64 layer_id) { return false; } +void Nvnflinger::SetLayerVisibility(u64 layer_id, bool visible) { + const auto lock_guard = Lock(); + + for (auto& display : displays) { + if (auto* layer = display.FindLayer(layer_id); layer) { + layer->SetVisibility(visible); + } + } +} + void Nvnflinger::DestroyLayer(u64 layer_id) { const auto lock_guard = Lock(); @@ -269,45 +280,19 @@ void Nvnflinger::Compose() { SCOPE_EXIT({ display.SignalVSyncEvent(); }); // Don't do anything for displays without layers. - if (!display.HasLayers()) - continue; - - // TODO(Subv): Support more than 1 layer. - VI::Layer& layer = display.GetLayer(0); - - android::BufferItem buffer{}; - const auto status = layer.GetConsumer().AcquireBuffer(&buffer, {}, false); - - if (status != android::Status::NoError) { + if (!display.HasLayers()) { continue; } - const auto& igbp_buffer = *buffer.graphic_buffer; - if (!system.IsPoweredOn()) { return; // We are likely shutting down } - // Now send the buffer to the GPU for drawing. - // TODO(Subv): Support more than just disp0. The display device selection is probably based - // on which display we're drawing (Default, Internal, External, etc) auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd); ASSERT(nvdisp); - Common::Rectangle<int> crop_rect{ - static_cast<int>(buffer.crop.Left()), static_cast<int>(buffer.crop.Top()), - static_cast<int>(buffer.crop.Right()), static_cast<int>(buffer.crop.Bottom())}; - - nvdisp->flip(igbp_buffer.BufferId(), igbp_buffer.Offset(), igbp_buffer.ExternalFormat(), - igbp_buffer.Width(), igbp_buffer.Height(), igbp_buffer.Stride(), - static_cast<android::BufferTransformFlags>(buffer.transform), crop_rect, - buffer.fence.fences, buffer.fence.num_fences); - - MicroProfileFlip(); - - swap_interval = buffer.swap_interval; - - layer.GetConsumer().ReleaseBuffer(buffer, android::Fence::NoFence()); + swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp, + swap_interval); } } @@ -324,15 +309,16 @@ s64 Nvnflinger::GetNextTicks() const { speed_scale = 0.01f; } } + + // Adjust by speed limit determined during composition. + speed_scale /= compose_speed_scale; + if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) { // Run at intended presentation rate during video playback. speed_scale = 1.f; } - // As an extension, treat nonpositive swap interval as framerate multiplier. - const f32 effective_fps = swap_interval <= 0 ? 120.f * static_cast<f32>(1 - swap_interval) - : 60.f / static_cast<f32>(swap_interval); - + const f32 effective_fps = 60.f / static_cast<f32>(swap_interval); return static_cast<s64>(speed_scale * (1000000000.f / effective_fps)); } diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h index a60e0ae6b..c984d55a0 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.h +++ b/src/core/hle/service/nvnflinger/nvnflinger.h @@ -46,6 +46,7 @@ class BufferQueueProducer; namespace Service::Nvnflinger { class FbShareBufferManager; +class HardwareComposer; class HosBinderDriverServer; class Nvnflinger final { @@ -79,6 +80,9 @@ public: /// Closes a layer on all displays for the given layer ID. bool CloseLayer(u64 layer_id); + /// Makes a layer visible on all displays for the given layer ID. + void SetLayerVisibility(u64 layer_id, bool visible); + /// Destroys the given layer ID. void DestroyLayer(u64 layer_id); @@ -140,6 +144,7 @@ private: u32 next_buffer_queue_id = 1; s32 swap_interval = 1; + f32 compose_speed_scale = 1.0f; bool is_abandoned = false; diff --git a/src/core/hle/service/psc/time/common.h b/src/core/hle/service/psc/time/common.h index 596828b8b..3e13144a0 100644 --- a/src/core/hle/service/psc/time/common.h +++ b/src/core/hle/service/psc/time/common.h @@ -189,7 +189,7 @@ struct fmt::formatter<Service::PSC::Time::SteadyClockTimePoint> : fmt::formatter template <typename FormatContext> auto format(const Service::PSC::Time::SteadyClockTimePoint& time_point, FormatContext& ctx) const { - return fmt::format_to(ctx.out(), "time_point={}", time_point.time_point); + return fmt::format_to(ctx.out(), "[time_point={}]", time_point.time_point); } }; @@ -197,7 +197,7 @@ template <> struct fmt::formatter<Service::PSC::Time::SystemClockContext> : fmt::formatter<fmt::string_view> { template <typename FormatContext> auto format(const Service::PSC::Time::SystemClockContext& context, FormatContext& ctx) const { - return fmt::format_to(ctx.out(), "offset={} steady_time_point={}", context.offset, + return fmt::format_to(ctx.out(), "[offset={} steady_time_point={}]", context.offset, context.steady_time_point.time_point); } }; @@ -206,8 +206,9 @@ template <> struct fmt::formatter<Service::PSC::Time::CalendarTime> : fmt::formatter<fmt::string_view> { template <typename FormatContext> auto format(const Service::PSC::Time::CalendarTime& calendar, FormatContext& ctx) const { - return fmt::format_to(ctx.out(), "{}/{}/{} {}:{}:{}", calendar.day, calendar.month, - calendar.year, calendar.hour, calendar.minute, calendar.second); + return fmt::format_to(ctx.out(), "[{:02}/{:02}/{:04} {:02}:{:02}:{:02}]", calendar.day, + calendar.month, calendar.year, calendar.hour, calendar.minute, + calendar.second); } }; @@ -217,7 +218,7 @@ struct fmt::formatter<Service::PSC::Time::CalendarAdditionalInfo> template <typename FormatContext> auto format(const Service::PSC::Time::CalendarAdditionalInfo& additional, FormatContext& ctx) const { - return fmt::format_to(ctx.out(), "weekday={} yearday={} name={} is_dst={} ut_offset={}", + return fmt::format_to(ctx.out(), "[weekday={} yearday={} name={} is_dst={} ut_offset={}]", additional.day_of_week, additional.day_of_year, additional.name.data(), additional.is_dst, additional.ut_offset); } @@ -227,8 +228,7 @@ template <> struct fmt::formatter<Service::PSC::Time::LocationName> : fmt::formatter<fmt::string_view> { template <typename FormatContext> auto format(const Service::PSC::Time::LocationName& name, FormatContext& ctx) const { - std::string_view n{name.data(), name.size()}; - return formatter<string_view>::format(n, ctx); + return formatter<string_view>::format(name.data(), ctx); } }; @@ -236,8 +236,7 @@ template <> struct fmt::formatter<Service::PSC::Time::RuleVersion> : fmt::formatter<fmt::string_view> { template <typename FormatContext> auto format(const Service::PSC::Time::RuleVersion& version, FormatContext& ctx) const { - std::string_view v{version.data(), version.size()}; - return formatter<string_view>::format(v, ctx); + return formatter<string_view>::format(version.data(), ctx); } }; @@ -247,10 +246,11 @@ struct fmt::formatter<Service::PSC::Time::ClockSnapshot> : fmt::formatter<fmt::s auto format(const Service::PSC::Time::ClockSnapshot& snapshot, FormatContext& ctx) const { return fmt::format_to( ctx.out(), - "user_context={} network_context={} user_time={} network_time={} user_calendar_time={} " + "[user_context={} network_context={} user_time={} network_time={} " + "user_calendar_time={} " "network_calendar_time={} user_calendar_additional_time={} " "network_calendar_additional_time={} steady_clock_time_point={} location={} " - "is_automatic_correction_enabled={} type={}", + "is_automatic_correction_enabled={} type={}]", snapshot.user_context, snapshot.network_context, snapshot.user_time, snapshot.network_time, snapshot.user_calendar_time, snapshot.network_calendar_time, snapshot.user_calendar_additional_time, snapshot.network_calendar_additional_time, @@ -266,7 +266,7 @@ struct fmt::formatter<Service::PSC::Time::ContinuousAdjustmentTimePoint> auto format(const Service::PSC::Time::ContinuousAdjustmentTimePoint& time_point, FormatContext& ctx) const { return fmt::format_to(ctx.out(), - "rtc_offset={} diff_scale={} shift_amount={} lower={} upper={}", + "[rtc_offset={} diff_scale={} shift_amount={} lower={} upper={}]", time_point.rtc_offset, time_point.diff_scale, time_point.shift_amount, time_point.lower, time_point.upper); } diff --git a/src/core/hle/service/psc/time/service_manager.cpp b/src/core/hle/service/psc/time/service_manager.cpp index ec906b723..4e1643fcb 100644 --- a/src/core/hle/service/psc/time/service_manager.cpp +++ b/src/core/hle/service/psc/time/service_manager.cpp @@ -120,11 +120,8 @@ Result ServiceManager::SetupStandardNetworkSystemClockCore(SystemClockContext& c context, context.steady_time_point.clock_source_id.RawString(), accuracy); // TODO this is a hack! The network clock should be updated independently, from the ntc service - // and maybe elsewhere. We do not do that, so fix the clock to the local clock on first boot - // to avoid it being stuck at 0. - if (context == Service::PSC::Time::SystemClockContext{}) { - m_local_system_clock.GetContext(context); - } + // and maybe elsewhere. We do not do that, so fix the clock to the local clock. + m_local_system_clock.GetContext(context); m_network_system_clock.SetContextWriter(m_network_system_context_writer); m_network_system_clock.Initialize(context, accuracy); @@ -138,13 +135,6 @@ Result ServiceManager::SetupStandardUserSystemClockCore(bool automatic_correctio LOG_DEBUG(Service_Time, "called. automatic_correction={} time_point={} clock_source_id={}", automatic_correction, time_point, time_point.clock_source_id.RawString()); - // TODO this is a hack! The user clock should be updated independently, from the ntc service - // and maybe elsewhere. We do not do that, so fix the clock to the local clock on first boot - // to avoid it being stuck at 0. - if (time_point == Service::PSC::Time::SteadyClockTimePoint{}) { - m_local_system_clock.GetCurrentTimePoint(time_point); - } - m_user_system_clock.SetAutomaticCorrection(automatic_correction); m_user_system_clock.SetTimePointAndSignal(time_point); m_user_system_clock.SetInitialized(); diff --git a/src/core/hle/service/psc/time/time_zone.cpp b/src/core/hle/service/psc/time/time_zone.cpp index 82ddba42f..cc855c763 100644 --- a/src/core/hle/service/psc/time/time_zone.cpp +++ b/src/core/hle/service/psc/time/time_zone.cpp @@ -140,11 +140,11 @@ Result TimeZone::ParseBinaryInto(Tz::Rule& out_rule, std::span<const u8> binary) R_RETURN(ParseBinaryImpl(out_rule, binary)); } -Result TimeZone::ToPosixTime(u32& out_count, std::span<s64> out_times, u32 out_times_count, - CalendarTime& calendar, const Tz::Rule& rule) { +Result TimeZone::ToPosixTime(u32& out_count, std::span<s64> out_times, size_t out_times_max_count, + const CalendarTime& calendar, const Tz::Rule& rule) { std::scoped_lock l{m_mutex}; - auto res = ToPosixTimeImpl(out_count, out_times, out_times_count, calendar, rule, -1); + auto res = ToPosixTimeImpl(out_count, out_times, out_times_max_count, calendar, rule, -1); if (res != ResultSuccess) { if (res == ResultTimeZoneNotFound) { @@ -158,10 +158,10 @@ Result TimeZone::ToPosixTime(u32& out_count, std::span<s64> out_times, u32 out_t } Result TimeZone::ToPosixTimeWithMyRule(u32& out_count, std::span<s64> out_times, - u32 out_times_count, CalendarTime& calendar) { + size_t out_times_max_count, const CalendarTime& calendar) { std::scoped_lock l{m_mutex}; - auto res = ToPosixTimeImpl(out_count, out_times, out_times_count, calendar, m_my_rule, -1); + auto res = ToPosixTimeImpl(out_count, out_times, out_times_max_count, calendar, m_my_rule, -1); if (res != ResultSuccess) { if (res == ResultTimeZoneNotFound) { @@ -212,20 +212,23 @@ Result TimeZone::ToCalendarTimeImpl(CalendarTime& out_calendar_time, R_SUCCEED(); } -Result TimeZone::ToPosixTimeImpl(u32& out_count, std::span<s64> out_times, u32 out_times_count, - CalendarTime& calendar, const Tz::Rule& rule, s32 is_dst) { +Result TimeZone::ToPosixTimeImpl(u32& out_count, std::span<s64> out_times, + size_t out_times_max_count, const CalendarTime& calendar, + const Tz::Rule& rule, s32 is_dst) { R_TRY(ValidateRule(rule)); - calendar.month -= 1; - calendar.year -= 1900; + CalendarTime local_calendar{calendar}; + + local_calendar.month -= 1; + local_calendar.year -= 1900; Tz::CalendarTimeInternal internal{ - .tm_sec = calendar.second, - .tm_min = calendar.minute, - .tm_hour = calendar.hour, - .tm_mday = calendar.day, - .tm_mon = calendar.month, - .tm_year = calendar.year, + .tm_sec = local_calendar.second, + .tm_min = local_calendar.minute, + .tm_hour = local_calendar.hour, + .tm_mday = local_calendar.day, + .tm_mon = local_calendar.month, + .tm_year = local_calendar.year, .tm_wday = 0, .tm_yday = 0, .tm_isdst = is_dst, @@ -243,9 +246,9 @@ Result TimeZone::ToPosixTimeImpl(u32& out_count, std::span<s64> out_times, u32 o R_RETURN(ResultTimeZoneNotFound); } - if (internal.tm_sec != calendar.second || internal.tm_min != calendar.minute || - internal.tm_hour != calendar.hour || internal.tm_mday != calendar.day || - internal.tm_mon != calendar.month || internal.tm_year != calendar.year) { + if (internal.tm_sec != local_calendar.second || internal.tm_min != local_calendar.minute || + internal.tm_hour != local_calendar.hour || internal.tm_mday != local_calendar.day || + internal.tm_mon != local_calendar.month || internal.tm_year != local_calendar.year) { R_RETURN(ResultTimeZoneNotFound); } @@ -254,7 +257,7 @@ Result TimeZone::ToPosixTimeImpl(u32& out_count, std::span<s64> out_times, u32 o } out_times[0] = time; - if (out_times_count < 2) { + if (out_times_max_count < 2) { out_count = 1; R_SUCCEED(); } diff --git a/src/core/hle/service/psc/time/time_zone.h b/src/core/hle/service/psc/time/time_zone.h index 6bd8f2fda..6248e45f9 100644 --- a/src/core/hle/service/psc/time/time_zone.h +++ b/src/core/hle/service/psc/time/time_zone.h @@ -38,18 +38,18 @@ public: CalendarAdditionalInfo& calendar_additional, s64 time); Result ParseBinary(LocationName& name, std::span<const u8> binary); Result ParseBinaryInto(Tz::Rule& out_rule, std::span<const u8> binary); - Result ToPosixTime(u32& out_count, std::span<s64> out_times, u32 out_times_count, - CalendarTime& calendar, const Tz::Rule& rule); - Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64> out_times, u32 out_times_count, - CalendarTime& calendar); + Result ToPosixTime(u32& out_count, std::span<s64> out_times, size_t out_times_max_count, + const CalendarTime& calendar, const Tz::Rule& rule); + Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64> out_times, + size_t out_times_max_count, const CalendarTime& calendar); private: Result ParseBinaryImpl(Tz::Rule& out_rule, std::span<const u8> binary); Result ToCalendarTimeImpl(CalendarTime& out_calendar_time, CalendarAdditionalInfo& out_additional_info, s64 time, const Tz::Rule& rule); - Result ToPosixTimeImpl(u32& out_count, std::span<s64> out_times, u32 out_times_count, - CalendarTime& calendar, const Tz::Rule& rule, s32 is_dst); + Result ToPosixTimeImpl(u32& out_count, std::span<s64> out_times, size_t out_times_max_count, + const CalendarTime& calendar, const Tz::Rule& rule, s32 is_dst); bool m_initialized{}; std::recursive_mutex m_mutex; diff --git a/src/core/hle/service/psc/time/time_zone_service.cpp b/src/core/hle/service/psc/time/time_zone_service.cpp index 9376a0324..eb81f5b03 100644 --- a/src/core/hle/service/psc/time/time_zone_service.cpp +++ b/src/core/hle/service/psc/time/time_zone_service.cpp @@ -138,32 +138,28 @@ Result TimeZoneService::ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_ Result TimeZoneService::ToPosixTime(Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times, - Out<u32> out_times_count, CalendarTime& calendar_time, - InRule rule) { + const CalendarTime& calendar_time, InRule rule) { SCOPE_EXIT({ LOG_DEBUG(Service_Time, - "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} " - "out_times_count={}", - calendar_time, *out_count, out_times[0], out_times[1], *out_times_count); + "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ", + calendar_time, *out_count, out_times[0], out_times[1]); }); R_RETURN( - m_time_zone.ToPosixTime(*out_count, out_times, *out_times_count, calendar_time, *rule)); + m_time_zone.ToPosixTime(*out_count, out_times, out_times.size(), calendar_time, *rule)); } Result TimeZoneService::ToPosixTimeWithMyRule(Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times, - Out<u32> out_times_count, - CalendarTime& calendar_time) { + const CalendarTime& calendar_time) { SCOPE_EXIT({ LOG_DEBUG(Service_Time, - "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} " - "out_times_count={}", - calendar_time, *out_count, out_times[0], out_times[1], *out_times_count); + "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ", + calendar_time, *out_count, out_times[0], out_times[1]); }); R_RETURN( - m_time_zone.ToPosixTimeWithMyRule(*out_count, out_times, *out_times_count, calendar_time)); + m_time_zone.ToPosixTimeWithMyRule(*out_count, out_times, out_times.size(), calendar_time)); } } // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/time_zone_service.h b/src/core/hle/service/psc/time/time_zone_service.h index 084e3f907..6eb9ddc4b 100644 --- a/src/core/hle/service/psc/time/time_zone_service.h +++ b/src/core/hle/service/psc/time/time_zone_service.h @@ -50,10 +50,10 @@ public: Result ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_time, Out<CalendarAdditionalInfo> out_additional_info, s64 time); Result ToPosixTime(Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times, - Out<u32> out_times_count, CalendarTime& calendar_time, InRule rule); + const CalendarTime& calendar_time, InRule rule); Result ToPosixTimeWithMyRule(Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times, - Out<u32> out_times_count, CalendarTime& calendar_time); + const CalendarTime& calendar_time); private: Core::System& m_system; diff --git a/src/core/hle/service/set/setting_formats/system_settings.h b/src/core/hle/service/set/setting_formats/system_settings.h index ebc373da5..40230182a 100644 --- a/src/core/hle/service/set/setting_formats/system_settings.h +++ b/src/core/hle/service/set/setting_formats/system_settings.h @@ -12,6 +12,7 @@ #include "common/vector_math.h" #include "core/hle/service/set/setting_formats/private_settings.h" #include "core/hle/service/set/settings_types.h" +#include "hid_core/resources/touch_screen/touch_types.h" namespace Service::Set { @@ -257,8 +258,7 @@ struct SystemSettings { std::array<u8, 0x10> analog_stick_user_calibration_left; std::array<u8, 0x10> analog_stick_user_calibration_right; - // nn::settings::system::TouchScreenMode - s32 touch_screen_mode; + TouchScreenMode touch_screen_mode; INSERT_PADDING_BYTES(0x14); // Reserved TvSettings tv_settings; diff --git a/src/core/hle/service/set/system_settings_server.cpp b/src/core/hle/service/set/system_settings_server.cpp index 100cb2db4..7ef4a0ded 100644 --- a/src/core/hle/service/set/system_settings_server.cpp +++ b/src/core/hle/service/set/system_settings_server.cpp @@ -25,7 +25,7 @@ namespace Service::Set { namespace { -constexpr u32 SETTINGS_VERSION{2u}; +constexpr u32 SETTINGS_VERSION{3u}; constexpr auto SETTINGS_MAGIC = Common::MakeMagic('y', 'u', 'z', 'u', '_', 's', 'e', 't'); struct SettingsHeader { u64 magic; @@ -275,8 +275,8 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_) {184, nullptr, "SetPlatformRegion"}, {185, &ISystemSettingsServer::GetHomeMenuSchemeModel, "GetHomeMenuSchemeModel"}, {186, nullptr, "GetMemoryUsageRateFlag"}, - {187, nullptr, "GetTouchScreenMode"}, - {188, nullptr, "SetTouchScreenMode"}, + {187, &ISystemSettingsServer::GetTouchScreenMode, "GetTouchScreenMode"}, + {188, &ISystemSettingsServer::SetTouchScreenMode, "SetTouchScreenMode"}, {189, nullptr, "GetButtonConfigSettingsFull"}, {190, nullptr, "SetButtonConfigSettingsFull"}, {191, nullptr, "GetButtonConfigSettingsEmbedded"}, @@ -1395,6 +1395,28 @@ void ISystemSettingsServer::GetHomeMenuSchemeModel(HLERequestContext& ctx) { rb.Push(0); } +void ISystemSettingsServer::GetTouchScreenMode(HLERequestContext& ctx) { + TouchScreenMode touch_screen_mode{}; + auto res = GetTouchScreenMode(touch_screen_mode); + + LOG_INFO(Service_SET, "called, touch_screen_mode={}", touch_screen_mode); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(res); + rb.PushEnum(touch_screen_mode); +} + +void ISystemSettingsServer::SetTouchScreenMode(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto touch_screen_mode = rp.PopEnum<TouchScreenMode>(); + auto res = SetTouchScreenMode(touch_screen_mode); + + LOG_INFO(Service_SET, "called, touch_screen_mode={}", touch_screen_mode); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + void ISystemSettingsServer::GetFieldTestingFlag(HLERequestContext& ctx) { LOG_INFO(Service_SET, "called, field_testing_flag={}", m_system_settings.field_testing_flag); @@ -1670,4 +1692,15 @@ Result ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime( R_SUCCEED(); } +Result ISystemSettingsServer::GetTouchScreenMode(TouchScreenMode& touch_screen_mode) const { + touch_screen_mode = m_system_settings.touch_screen_mode; + R_SUCCEED(); +} + +Result ISystemSettingsServer::SetTouchScreenMode(TouchScreenMode touch_screen_mode) { + m_system_settings.touch_screen_mode = touch_screen_mode; + SetSaveNeeded(); + R_SUCCEED(); +} + } // namespace Service::Set diff --git a/src/core/hle/service/set/system_settings_server.h b/src/core/hle/service/set/system_settings_server.h index 1982b9723..9a3b36f0c 100644 --- a/src/core/hle/service/set/system_settings_server.h +++ b/src/core/hle/service/set/system_settings_server.h @@ -74,6 +74,8 @@ public: Service::PSC::Time::SteadyClockTimePoint& out_time_point) const; Result SetUserSystemClockAutomaticCorrectionUpdatedTime( const Service::PSC::Time::SteadyClockTimePoint& time_point); + Result GetTouchScreenMode(TouchScreenMode& touch_screen_mode) const; + Result SetTouchScreenMode(TouchScreenMode touch_screen_mode); private: void SetLanguageCode(HLERequestContext& ctx); @@ -154,6 +156,8 @@ private: void GetChineseTraditionalInputMethod(HLERequestContext& ctx); void GetHomeMenuScheme(HLERequestContext& ctx); void GetHomeMenuSchemeModel(HLERequestContext& ctx); + void GetTouchScreenMode(HLERequestContext& ctx); + void SetTouchScreenMode(HLERequestContext& ctx); void GetFieldTestingFlag(HLERequestContext& ctx); void GetPanelCrcMode(HLERequestContext& ctx); void SetPanelCrcMode(HLERequestContext& ctx); diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h index f86af01a4..f3ea31bde 100644 --- a/src/core/hle/service/sockets/sockets.h +++ b/src/core/hle/service/sockets/sockets.h @@ -24,6 +24,7 @@ enum class Errno : u32 { CONNRESET = 104, NOTCONN = 107, TIMEDOUT = 110, + CONNREFUSED = 111, INPROGRESS = 115, }; diff --git a/src/core/hle/service/sockets/sockets_translate.cpp b/src/core/hle/service/sockets/sockets_translate.cpp index aed05250c..21bb3e776 100644 --- a/src/core/hle/service/sockets/sockets_translate.cpp +++ b/src/core/hle/service/sockets/sockets_translate.cpp @@ -25,6 +25,8 @@ Errno Translate(Network::Errno value) { return Errno::MFILE; case Network::Errno::PIPE: return Errno::PIPE; + case Network::Errno::CONNREFUSED: + return Errno::CONNREFUSED; case Network::Errno::NOTCONN: return Errno::NOTCONN; case Network::Errno::TIMEDOUT: diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp index 725311c53..7f2af9acc 100644 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ b/src/core/hle/service/vi/display/vi_display.cpp @@ -16,6 +16,7 @@ #include "core/hle/service/nvnflinger/buffer_queue_consumer.h" #include "core/hle/service/nvnflinger/buffer_queue_core.h" #include "core/hle/service/nvnflinger/buffer_queue_producer.h" +#include "core/hle/service/nvnflinger/hardware_composer.h" #include "core/hle/service/nvnflinger/hos_binder_driver_server.h" #include "core/hle/service/vi/display/vi_display.h" #include "core/hle/service/vi/layer/vi_layer.h" @@ -43,6 +44,7 @@ Display::Display(u64 id, std::string name_, KernelHelpers::ServiceContext& service_context_, Core::System& system_) : display_id{id}, name{std::move(name_)}, hos_binder_driver_server{hos_binder_driver_server_}, service_context{service_context_} { + hardware_composer = std::make_unique<Nvnflinger::HardwareComposer>(); vsync_event = service_context.CreateEvent(fmt::format("Display VSync Event {}", id)); } @@ -53,7 +55,7 @@ Display::~Display() { Layer& Display::GetLayer(std::size_t index) { size_t i = 0; for (auto& layer : layers) { - if (!layer->IsOpen()) { + if (!layer->IsOpen() || !layer->IsVisible()) { continue; } @@ -68,7 +70,7 @@ Layer& Display::GetLayer(std::size_t index) { } size_t Display::GetNumLayers() const { - return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen(); }); + return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen() && l->IsVisible(); }); } Kernel::KReadableEvent* Display::GetVSyncEvent() { @@ -81,8 +83,6 @@ void Display::SignalVSyncEvent() { void Display::CreateLayer(u64 layer_id, u32 binder_id, Service::Nvidia::NvCore::Container& nv_core) { - ASSERT_MSG(layers.empty(), "Only one layer is supported per display at the moment"); - auto [core, producer, consumer] = CreateBufferQueue(service_context, nv_core.GetNvMapFile()); auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(consumer)); diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h index 8eb8a5155..220292cff 100644 --- a/src/core/hle/service/vi/display/vi_display.h +++ b/src/core/hle/service/vi/display/vi_display.h @@ -11,9 +11,14 @@ #include "common/common_types.h" #include "core/hle/result.h" +namespace Core { +class System; +} + namespace Kernel { class KEvent; -} +class KReadableEvent; +} // namespace Kernel namespace Service::android { class BufferQueueProducer; @@ -24,8 +29,9 @@ class ServiceContext; } namespace Service::Nvnflinger { +class HardwareComposer; class HosBinderDriverServer; -} +} // namespace Service::Nvnflinger namespace Service::Nvidia::NvCore { class Container; @@ -118,6 +124,10 @@ public: /// const Layer* FindLayer(u64 layer_id) const; + Nvnflinger::HardwareComposer& GetComposer() const { + return *hardware_composer; + } + private: u64 display_id; std::string name; @@ -125,6 +135,7 @@ private: KernelHelpers::ServiceContext& service_context; std::vector<std::unique_ptr<Layer>> layers; + std::unique_ptr<Nvnflinger::HardwareComposer> hardware_composer; Kernel::KEvent* vsync_event{}; bool is_abandoned{}; }; diff --git a/src/core/hle/service/vi/layer/vi_layer.cpp b/src/core/hle/service/vi/layer/vi_layer.cpp index 04e52a23b..493bd6e9e 100644 --- a/src/core/hle/service/vi/layer/vi_layer.cpp +++ b/src/core/hle/service/vi/layer/vi_layer.cpp @@ -9,7 +9,7 @@ Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_, android::BufferQueueProducer& binder_, std::shared_ptr<android::BufferItemConsumer>&& consumer_) : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, - consumer{std::move(consumer_)}, open{false} {} + consumer{std::move(consumer_)}, open{false}, visible{true} {} Layer::~Layer() = default; diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h index f95e2dc71..b4b031ee7 100644 --- a/src/core/hle/service/vi/layer/vi_layer.h +++ b/src/core/hle/service/vi/layer/vi_layer.h @@ -72,6 +72,14 @@ public: return core; } + bool IsVisible() const { + return visible; + } + + void SetVisibility(bool v) { + visible = v; + } + bool IsOpen() const { return open; } @@ -91,6 +99,7 @@ private: android::BufferQueueProducer& binder; std::shared_ptr<android::BufferItemConsumer> consumer; bool open; + bool visible; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 1f3d82c57..d508ed28c 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -195,8 +195,9 @@ private: void GetSharedBufferMemoryHandleId(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u64 buffer_id = rp.PopRaw<u64>(); + const u64 aruid = ctx.GetPID(); - LOG_INFO(Service_VI, "called. buffer_id={:#x}", buffer_id); + LOG_INFO(Service_VI, "called. buffer_id={:#x}, aruid={:#x}", buffer_id, aruid); struct OutputParameters { s32 nvmap_handle; @@ -206,7 +207,7 @@ private: OutputParameters out{}; Nvnflinger::SharedMemoryPoolLayout layout{}; const auto result = nvnflinger.GetSystemBufferManager().GetSharedBufferMemoryHandleId( - &out.size, &out.nvmap_handle, &layout, buffer_id, 0); + &out.size, &out.nvmap_handle, &layout, buffer_id, aruid); ctx.WriteBuffer(&layout, sizeof(layout)); @@ -535,6 +536,12 @@ public: RegisterHandlers(functions); } + ~IApplicationDisplayService() { + for (const auto layer_id : stray_layer_ids) { + nvnflinger.DestroyLayer(layer_id); + } + } + private: enum class ConvertedScaleMode : u64 { Freeze = 0, @@ -770,6 +777,7 @@ private: return; } + stray_layer_ids.push_back(*layer_id); const auto buffer_queue_id = nvnflinger.FindBufferQueueId(display_id, *layer_id); if (!buffer_queue_id) { LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); @@ -916,6 +924,7 @@ private: Nvnflinger::Nvnflinger& nvnflinger; Nvnflinger::HosBinderDriverServer& hos_binder_driver_server; + std::vector<u64> stray_layer_ids; bool vsync_event_fetched{false}; }; diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp index a983f23ea..7785c1d16 100644 --- a/src/core/internal_network/network.cpp +++ b/src/core/internal_network/network.cpp @@ -693,20 +693,23 @@ std::pair<SocketBase::AcceptResult, Errno> Socket::Accept() { sockaddr_in addr; socklen_t addrlen = sizeof(addr); - std::vector<WSAPOLLFD> host_pollfds{ - WSAPOLLFD{fd, POLLIN, 0}, - WSAPOLLFD{GetInterruptSocket(), POLLIN, 0}, - }; - - while (true) { - const int pollres = - WSAPoll(host_pollfds.data(), static_cast<ULONG>(host_pollfds.size()), -1); - if (host_pollfds[1].revents != 0) { - // Interrupt signaled before a client could be accepted, break - return {AcceptResult{}, Errno::AGAIN}; - } - if (pollres > 0) { - break; + const bool wait_for_accept = !is_non_blocking; + if (wait_for_accept) { + std::vector<WSAPOLLFD> host_pollfds{ + WSAPOLLFD{fd, POLLIN, 0}, + WSAPOLLFD{GetInterruptSocket(), POLLIN, 0}, + }; + + while (true) { + const int pollres = + WSAPoll(host_pollfds.data(), static_cast<ULONG>(host_pollfds.size()), -1); + if (host_pollfds[1].revents != 0) { + // Interrupt signaled before a client could be accepted, break + return {AcceptResult{}, Errno::AGAIN}; + } + if (pollres > 0) { + break; + } } } @@ -913,6 +916,7 @@ Errno Socket::SetRcvTimeo(u32 value) { Errno Socket::SetNonBlock(bool enable) { if (EnableNonBlock(fd, enable)) { + is_non_blocking = enable; return Errno::SUCCESS; } return GetAndLogLastError(); diff --git a/src/core/internal_network/sockets.h b/src/core/internal_network/sockets.h index 4ba51f62c..3a32dff75 100644 --- a/src/core/internal_network/sockets.h +++ b/src/core/internal_network/sockets.h @@ -166,6 +166,9 @@ public: bool IsOpened() const override; void HandleProxyPacket(const ProxyPacket& packet) override; + +private: + bool is_non_blocking = false; }; std::pair<s32, Errno> Poll(std::vector<PollFD>& poll_fds, s32 timeout); |